Component Enabled State

A component that allows user interaction (such as an TextField or a Button) can have three different enabled states:

  • enabled: this is the default. An enabled component allows the user to interact with it;

  • explicitly disabled: a component is explicitly disabled when the setEnabled(false) is called directly on it. Any communication from the client to the server is blocked, and the user can’t interact with the component in any way;

  • implicitly disabled: a component is implicitly disabled when it is a child of a explicitly disabled container. The component behaves exactly like a explicitly disabled one, but when it gets detached from the disabled container, it gets enabled again.

Any component that implements the HasEnabled interface can be explicitly enabled/disabled. For example:

Java

  1. TextField name = new TextField("Name");
  2. name.setEnabled(false);

The name field on this example is disabled, so the user can’t interact with it, and any events from the client to server are blocked. The server doesn’t handle any status updates from the component, even if the component is changed manually on the browser (by a client-side script or via developer console, for example).

When you have a container, you can disable all components inside it by using the same API:

Java

  1. FormLayout form = new FormLayout();
  2. TextField name = new TextField("Name");
  3. TextField email = new TextField("E-mail");
  4. Button submit = new Button("Submit");
  5. form.add(name, email, submit);
  6. form.setEnabled(false); // all children are implicitly disabled
  7. System.out.println(name.isEnabled()); // prints false

When an implicitly disabled component is detached from a disabled container, it gets enabled again. Likewise, if an enabled component is attached to a disabled container, the component gets implicitly disabled. For example:

Java

  1. FormLayout form = new FormLayout();
  2. form.setEnabled(false); // the entire form is disabled
  3. TextField name = new TextField("Name");
  4. System.out.println(name.isEnabled()); // prints true, since it is not attached yet
  5. Button submit = new Button("Submit");
  6. submit.setEnabled(false); // the submit button is explicitly disabled
  7. System.out.println(submit.isEnabled()); // prints false
  8. form.add(name, submit); // attaches children
  9. System.out.println(name.isEnabled()); // prints false
  10. System.out.println(submit.isEnabled()); // prints false
  11. form.remove(name); // the name field gets detached
  12. System.out.println(name.isEnabled()); // prints true
  13. form.remove(submit); // the submit button gets detached
  14. System.out.println(submit.isEnabled()); // prints false, since it was explicitly disabled

Override default disabled behavior

By default disabled components don’t allow any user interaction from the client side. Complicated (composite) components sometimes should stay partly functional even in disabled state. In this case it should be possible to enable some RPC client side calls which are blocked for disabled component.

In the following example the Polymer template component controls its enabled state by itself via the checkbox. E.g. it may be a registration form which becomes enabled only when user accepts a license agreement. The checkbox should not ever be disabled and it should enable/disable the component.

Java

  1. @Tag("registration-form")
  2. @HtmlImport("src/registration-form.html")
  3. public class RegistrationForm extends PolymerTemplate<TemplateModel>
  4. implements HasEnabled {
  5. @Id
  6. private TextField name;
  7. @Id
  8. private TextField email;
  9. @Id
  10. private Button submit;
  11. @Id
  12. private Element enable;
  13. public RegistrationForm() {
  14. enable.synchronizeProperty("checked", "checked-changed",
  15. DisabledUpdateMode.ALWAYS);
  16. enable.addPropertyChangeListener("checked", this::handleEnabled);
  17. setEnabled(false);
  18. }
  19. private void handleEnabled(PropertyChangeEvent event) {
  20. setEnabled((Boolean) event.getValue());
  21. }
  22. @EventHandler
  23. private void register() {
  24. String userName = name.getValue();
  25. String userEmail = email.getValue();
  26. System.out.println("Register user with name='" + userName
  27. + "' and email='" + userEmail + "'");
  28. }
  29. }

Here is its template file:

HTML

  1. <dom-module id="registration-form">
  2. <template>
  3. <vaadin-text-field id='name'>{{name}}</vaadin-text-field>
  4. <vaadin-text-field id='email'>{{email}}</vaadin-text-field>
  5. <vaadin-button id='submit' on-click='register'>Register</vaadin-button>
  6. <vaadin-checkbox id='enable'>Accept License Agreement</vaadin-checkbox>
  7. </template>
  8. <script>
  9. class RegistrationForm extends Polymer.Element {
  10. static get is() {return 'registration-form'}
  11. }
  12. customElements.define(RegistrationForm.is, RegistrationForm);
  13. </script>
  14. </dom-module>

In this example the checkbox is implicitly disabled if the template (which is its parent) is disabled. As a result no RPC will be allowed for the checkbox. The method synchronizeProperty with extra argument is used to synchronize checked property. The argument value is DisabledUpdateMode.ALWAYS enum value which instructs to allow updates for this property even if the element is disabled.

Here is the list of RPC communications which are blocked for the disabled element: - Property changes - DOM events - Event handler methods (methods annotated with @EventHandler) - Client delegate methods (methods annotated with @ClientCallable)

E.g. the register() method is an event handler method which is blocked when the component is disabled.

Enable property changes

Similarly to the synchronizeProperty API method which allows to receive property updates for disabled components if it’s called with DisabledUpdateMode.ALWAYS argument value, you may use declarative way to do the same via @Synchronize annotation for the property getter in your component:

Java

  1. @Synchronize(property = "prop", value = "prop-changed", allowUpdates = DisabledUpdateMode.ALWAYS)
  2. public String getProp(){
  3. return getElement().getProperty("prop");
  4. }

Enable DOM events

You may use two ways to receive DOM events: Element API method addEventListener and @DomEvent annotation.

To unblock DOM event for a disabled element using API method you may use addEventListener overload which accepts extra parameter with value DisabledUpdateMode.ALWAYS.

Java

  1. public Notification() {
  2. getElement().addEventListener("opened-changed", event -> {
  3. System.out.println("Notification is opened");})
  4. .setDisabledUpdateMode(DisabledUpdateMode.ALWAYS);
  5. }

To unblock DOM event for a disabled component via @DomEvent annotation you may use the extra parameter value DisabledUpdateMode.ALWAYS : @DomEvent(value="input", allowUpdates = DisabledUpdateMode.ALWAYS ).

Java

  1. @DomEvent(value = "click", allowUpdates = DisabledUpdateMode.ALWAYS)
  2. public class CustomEvent extends ComponentEvent<Component> {
  3. }

Enable server handler methods

If you have server handler methods annotation with @ClientCallable or @EventHandler then you may unblock them for the disabled component specifying DisabledUpdateMode.ALWAYS as a value: @EventHandler(DisabledUpdateMode.ALWAYS).

Java

  1. @EventHandler(DisabledUpdateMode.ALWAYS)
  2. private void eventHandler(){
  3. }
  4. @ClientCallable(DisabledUpdateMode.ALWAYS)
  5. private void clientRequest(){
  6. }