Lifecycle Callbacks

Polymer components allow you to define code that would be called in response to certain lifecycle events.

To use this feature, implement methods with the following names:

  • constructor - called when an element is created but before property values are set.

  • connectedCallback - called when an element is created and properties are set.

  • disconnectedCallback - called when an element is removed from a document.

For example, a user opens some profile page and we would like to load all required details from the server before showing them to the user.

index.html
<html>
<head>
	<link rel="import" href="src/polymer-advanced/lifecycle/profile-page.html">
	<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>
</head>
<body>
    <profile-page></profile-page>
</body>
</html>
src/polymer-advanced/lifecycle/profile-page.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/paper-button/paper-button.html">
<link rel="import" href="personal-details-page.html">
<link rel="import" href="preferences-page.html">

<dom-module id="profile-page">
  <template>

    <!-- Navigation section -->
    <paper-button on-click="openPersonalDetailsPage">Personal Details</paper-button>
    <paper-button on-click="openPreferencesPage">Preferences</paper-button>

    <hr/>

    <!-- dom-if by default doesn't remove it's content when condition evaluates to false, it just hides it. -->
    <!-- 'restamp' attribute allows you to override this behavior causing HTML element actually being added -->
    <!--  and removed each time a condition changes. -->
    <template is="dom-if" if="[[personalDetailsPageOpened]]" restamp>
      <personal-details-page></personal-details-page>
    </template>
    <template is="dom-if" if="[[preferencesPageOpened]]" restamp>
      <preferences-page id="test"></preferences-page>
    </template>

  </template>
  <script>
    class ProfilePage extends Polymer.Element {
      static get is() {
        return 'profile-page';
      }

      static get properties() {
        return {
          personalDetailsPageOpened: {
            type: Boolean,
            value: true
          },
          preferencesPageOpened: {
            type: Boolean,
            value: false
          }
        }
      }

      openPersonalDetailsPage() {
        this.set('personalDetailsPageOpened', true);
        this.set('preferencesPageOpened', false);
      }

      openPreferencesPage() {
        this.set('personalDetailsPageOpened', false);
        this.set('preferencesPageOpened', true);
      }
    }

    customElements.define(ProfilePage.is, ProfilePage);
  </script>
</dom-module>
src/polymer-advanced/lifecycle/personal-details-page.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/paper-spinner/paper-spinner.html">

<dom-module id="personal-details-page">
  <template>

    <h3>Personal Details</h3>

    <template is="dom-if" if="[[dataLoaded]]">
      <p>First name: [[details.name]]</p>
      <p>Family name: [[details.familyName]]</p>
      <p>Age: [[details.age]]</p>
    </template>
    <template is="dom-if" if="[[!dataLoaded]]">
      <div>
        <paper-spinner active></paper-spinner>
      </div>
    </template>

  </template>
  <script>
    class PersonalDetailsPage extends Polymer.Element {
      static get is() {
        return 'personal-details-page';
      }

      static get properties() {
        return {
          dataLoaded: Boolean,
          details: Object
        }
      }

      connectedCallback() {
        // When using callbacks we have to call a parent method first
        //  to ensure that all standard logic and logic from mixins (if they are used)
        //  is applied
        super.connectedCallback();

        this.set('dataLoaded', false);
        this.set('details', {});
        setTimeout(function() {
          this.set('details', {
            name: 'John',
            familyName: 'Black',
            age: 31
          });
          this.set('dataLoaded', true);
        }.bind(this), 1500);
      }
    }

    customElements.define(PersonalDetailsPage.is, PersonalDetailsPage);
  </script>
</dom-module>
src/polymer-advanced/lifecycle/preferences-page.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/paper-spinner/paper-spinner.html">

<dom-module id="preferences-page">
  <template>

    <h3>Preferences</h3>

    <template is="dom-if" if="[[dataLoaded]]">
      <p>Favourite color: [[preferences.color]]</p>
      <p>Favourite song: [[preferences.song]]</p>
    </template>
    <template is="dom-if" if="[[!dataLoaded]]">
      <div>
        <paper-spinner active></paper-spinner>
      </div>
    </template>

  </template>
  <script>
    class PreferencesPage extends Polymer.Element {
      static get is() {
        return 'preferences-page';
      }

      static get properties() {
        return {
          dataLoaded: Boolean,
          preferences: Object
        }
      }

      connectedCallback() {
        super.connectedCallback();
        this.set('dataLoaded', false);
        this.set('preferences', {});
        setTimeout(function() {
          this.set('preferences', {
            color: 'Aquamarine',
            song: 'My Sharona'
          });
          this.set('dataLoaded', true);
        }.bind(this), 500);
      }
    }

    customElements.define(PreferencesPage.is, PreferencesPage);
  </script>
</dom-module>
What we have learned so far
  • During their lifecycle, Polymer elements call a number of callback methods. We can use these methods to invoke our initialization logic.