Observers

Sometimes, it is needed to listen to changes in some properties and react on them. For example, we may want to send some notifications to a server when users enter some information.

The example below demonstrates it. Basically, users can choose a type of their company and we save this information somewhere in a database.

Company type selector

Source code

index.html
<html>
<head>
	<link rel="import" href="src/polymer-advanced/observers/company-type-select.html">
	<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
</head>
<body>
    <company-type-select></company-type-select>
</body>
</html>
src/polymer-advanced/observers/company-type-select.html
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/polymer/lib/elements/dom-if.html">
<!-- Material design implementation of a radio button -->
<link rel="import" href="../../../bower_components/paper-radio-button/paper-radio-button.html">
<!-- PaperRadioGroup allows you to group radio buttons, so only one can be selected at any time -->
<link rel="import" href="../../../bower_components/paper-radio-group/paper-radio-group.html">
<!-- Decorative spinner that indicates that something is happening in the background -->
<link rel="import" href="../../../bower_components/paper-spinner/paper-spinner.html">

<dom-module id="company-type-select">
  <template>

    Please select a type of your company:
    <paper-radio-group selected="{{companyType}}">
      <!-- We are disabling radio buttons when we send a notification to a server just to simplify an application -->
      <!--  and prevent a user from rapidly changing settings -->
      <paper-radio-button name="ltd" disabled="[[persistenceInProgress]]">LTD</paper-radio-button>
      <paper-radio-button name="llp" disabled="[[persistenceInProgress]]">LLP</paper-radio-button>
    </paper-radio-group>

    <br/>

    <template is="dom-if" if="[[persistenceInProgress]]">
      <paper-spinner active></paper-spinner>
    </template>

  </template>
  <script>
    class CompanyTypeSelect extends Polymer.Element {
      static get is() {
        return 'company-type-select';
      }

      static get properties() {
        return {
          companyType: {
            type: String,
            observer: 'companyTypeChanged'
          },
          persistenceInProgress: {
            type: Boolean,
            value: false
          }
        }
      }

      // The function accepts 2 parameters. In our case we don't need them
      // so we could just write 'companyTypeChanged: function()'.
      // Based on radio-buttons we can say that newValue would be either 'ltd' or 'llp'.
      companyTypeChanged(newValue, oldValue) {
        this.set('persistenceInProgress', true);
        // It's a stub instead of sending some asynchronous request
        setTimeout(function() {
          this.set('persistenceInProgress', false);
        }.bind(this), 1000);
      }
    }

    customElements.define(CompanyTypeSelect.is, CompanyTypeSelect);
  </script>
</dom-module>

Observers can be much more complex. For example, you may want to monitor changes in several different properties.

Let’s enhance our previous example by adding a contact name input.

src/polymer-advanced/observers/company-type-select-enhanced.html
<link rel="import" href="../../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../../bower_components/polymer/lib/elements/dom-if.html">
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
<link rel="import" href="../../../bower_components/paper-checkbox/paper-checkbox.html">
<link rel="import" href="../../../bower_components/paper-radio-button/paper-radio-button.html">
<link rel="import" href="../../../bower_components/paper-radio-group/paper-radio-group.html">
<link rel="import" href="../../../bower_components/paper-spinner/paper-spinner.html">

<dom-module id="company-type-select-enhanced">
  <template>

    <div>
      Please select a type of your company:
      <paper-radio-group selected="{{companyType}}">
        <paper-radio-button name="ltd" disabled="[[persistenceInProgress]]">LTD</paper-radio-button>
        <paper-radio-button name="llp" disabled="[[persistenceInProgress]]">LLP</paper-radio-button>
      </paper-radio-group>
    </div>
    <div>
      <paper-checkbox disabled="[[persistenceInProgress]]" checked="{{notificationSubscription}}">
        I want to get notifications
      </paper-checkbox>
    </div>
    <br/>
    <div>
      <template is="dom-if" if="[[persistenceInProgress]]">
        <paper-spinner active></paper-spinner>
      </template>
    </div>

  </template>
  <script>
    class CompanyTypeSelectEnhanced extends Polymer.Element {
      static get is() {
        return 'company-type-select-enhanced';
      }

      static get properties() {
        return {
          companyType: String,
          name: String,
          notificationSubscription: Boolean,
          persistenceInProgress: {
            type: Boolean,
            value: false
          }
        }
      }

      // This static getter is used to specify an array of observers
      static get observers() {
        return [
          'userInfoChanged(companyType, notificationSubscription)'
        ];
      }

      userInfoChanged(companyType, notificationSubscription) {
        this.set('persistenceInProgress', true);
        setTimeout(function() {
          this.set('persistenceInProgress', false);
        }.bind(this), 1000);
      }
    }

    customElements.define(CompanyTypeSelectEnhanced.is, CompanyTypeSelectEnhanced);
  </script>
</dom-module>

Enhanced company type selector

What we have learned so far
  • We can monitor changes in a single property by using an observer attribute. An observer function accepts 2 arguments: an old value and a new one.

  • We can monitor several properties at the same time by using observers array. But we lose information about old values in this case.