Thursday, November 15, 2018

Polymer Computed Properties

Polymer supports the concept of computed properties which allows you to create virtual properties whose values are calculated from other properties. If those properties that it depends on change the computed property will get recomputed.

However, there are a few gotchas when creating computed properties that you  need to know in order to successfully write your own. So let's do a simple example to explain.

Let's say we have a component with a name property and we want to change the layout depending on if the name is defined. So what we need is a computed property called hasName that returns true if the name is defined.

class MyElement extends PolymerElement {
  static get properties() {
    return {
      name: String,
      computedName: {
        type: String,
        computed: "_computeName(name)"
      }
    }
  }
  static get template() {
    return html`
      <span>[[computedName]]<span>`;
  }

To make a computed property you need to tell the property how to compute the value by specifyingit a function call, _computeName. Any parameters to the function will become dependencies of the computed property. In this case "name". So whenever name changes the _computeName() function will be called to recompute the value of computedName.

Here's the _computeName() function. It takes the name as a parameter and simply returns the name or "unknown" if it's not defined.

  _computeName(name) {
    return name || "Unknown";
  }

You might think we're done at this point, but if you were to run it now all you would ever get is "Unknown" for computedName, even if the name property changed. You would be pulling your hair out trying to determine why it doesn't work (not that I'm speaking from experience or anything ;-)).

The problem is that if the name property is undefined the first time the component gets created it will cause computedName to never get recomputed. Therefore we must give name a default value in the constructor. We'll just set it to empty string.


  constructor() {
    super();
    this.name = "";
  }

There! Now it should work properly.

Code hard!

No comments:

Post a Comment