The data system provides methods for making observable changes to an element's model data (properties and subproperties). Use these methods to make observable changes to arrays and object subproperties.

Related concepts:

A data path is a series of path segments. In most cases, each path segment is a property name. The data APIs accept two kinds of paths:

  • A string, with path segments separated by dots.

  • An array of strings, where each array element is either a path segment or a dotted path.

The following all represent the same path:

"one.two.three"
["one", "two", "three"]
["one.two", "three"]

There are a few special types of path segments.

  • Wildcard paths (like foo.*) represent all changes to a given path and its subproperties, including array mutations.
  • Array mutation paths (like foo.splices) represent all array mutations to a given array.
  • Array item paths (like foo.11) represent an item in an array.

Use the get method to retrieve a value based on its path.

// retrieve a subproperty by path
var value = this.get('myProp.subProp');
// Retrieve the 11th item in myArray
var item = this.get(['myArray', 11])

Use the set method to make an observable change to a subproperty.

// clear an array
this.set('group.members', []);
// set a subproperty
this.set('profile.name', 'Alex');

Calling set has no effect if the value of the property or subproperty doesn't change. In particular, calling set on an object property won't cause Polymer to pick up changes to the object's subproperties, unless the object itself changes. Likewise, calling set on an array property won't cause Polymer to pick up array mutations that have already been made:

// DOES NOT WORK
this.profile.name = Alex;
this.set('profile', this.profile);

// DOES NOT WORK
this.users.push({name: 'Grace'});
this.set('users', this.users);

In both cases an object to itself doesn't have any effect—the object hasn't changed. Instead, you can use notifyPath to inform Polymer of a subproperty change that's already happened. For an array, you can either use Polymer's array mutation methods as described in Mutate an array, or notify Polymer after the fact as described in Notify Polymer of array mutations.

MutableData For elements that include the Polymer.MutableData mixin, calling set on an object or array causes Polymer to re-evaluates the entire object graph starting at that object or array, even if the object or array itself hasn't changed. For details, see Using the MutableData mixin.

Related tasks:

After making changes to an object subproperty, call notifyPath to make the change observable to the data system.

this.profile.name = Alex;
this.notifyPath('profile.name');

When calling notifyPath, you need to use the exact path that changed. For example, calling this.notifyPath('profile') doesn't pick up a change to profile.name because the profile object itself hasn't changed.

MutableData For elements that include the Polymer.MutableData mixin, calling notifyPath on an object or array causes Polymer to re-evaluates the entire object graph starting at that object or array, even if the object or array itself hasn't changed. For details, see Using the MutableData mixin.

Use Polymer's array mutation methods to make observable changes to arrays.

If you manipulate an array using the native methods (like Array.prototype.push), you can notify Polymer after the fact, as described in Batch changes to an object or array.

When modifying arrays, Polymer provides a set of array mutation methods that mimic Array.prototype methods, with the exception that they take a path string as the first argument. The path argument identifies an array on the element to mutate, with the following arguments matching those of the native Array methods.

These methods perform the mutation action on the array, and then notify other elements that may be bound to the same array of the changes. You can use these methods when mutating an array to ensure that any elements watching the array (via observers, computed properties, or data bindings) are kept in sync.

Every Polymer element has the following array mutation methods available:

  • push(path, item1, [..., itemN])
  • pop(path)
  • unshift(path, item1, [..., itemN])
  • shift(path)
  • splice(path, index, removeCount, [item1, ..., itemN])

Example

<link rel="import" href="components/polymer/polymer-element.html">
<link rel="import" href="components/polymer/src/elements/dom-repeat.html">

<dom-module id="x-custom">
  <template>
    <template is="dom-repeat" items="[[users]]">{{item}}</template>
  </template>

  <script>
    class XCustom extends Polymer.Element {

      static get is() {return 'custom-element'}

      addUser(user) {
        this.push('users', user);
      }

      removeUser(user) {
        var index = this.users.indexOf(user);
        this.splice('users', index, 1);
      }

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

The set method can also be used to manipulate arrays by using an array path. For example, to to replace the array item at index 3:

this.set('users.3', {name: 'Churchill'});

Sometimes it's not convenient to use the Polymer array mutation methods. In this event, you have a few choices:

  • Use the notifySplices method to notify Polymer after the fact.

  • Use the MutableData mixin. For elements that include the Polymer.MutableData mixin, calling set or notifyPath on an object or array causes Polymer to re-evaluate the entire object graph starting at that object or array, even if the object or array itself hasn't changed. For details, see Using the MutableData mixin.

Whenever possible you should always use Polymer's array mutation methods. However, this isn't always possible. For example, you may be using a third-party library that does not use Polymer's array mutation methods. In these scenarios you can call notifySplices after the mutations to ensure that any Polymer elements observing the array are properly notified of the changes.

The notifySplices method requires the array mutations to be normalized into a series of splice operations. For example, calling shift on an array removes the first element of the array, so is equivalent to calling splice(0, 1).

Splices should be applied in index order, so that the element can update its internal representation of the array.

If you can't know the exact changes that occurred, you can use the MutableData mixin. For elements that include the Polymer.MutableData mixin, calling set or notifyPath on an object or array causes Polymer to re-evaluate the entire object graph starting at that object or array, even if the object or array itself hasn't changed. For details, see Using the MutableData mixin.

Use setProperties method to make a batch change to a set of properties. This ensures the property changes run as a coherent set.

this.setProperties({
  date: 'Jan 17, 2017',
  verified: true
});

setProperties supports an optional setReadOnly flag as the second parameter. If you need to set read-only properties as part of a batch change, pass true for the second parameter:

this.setProperties({
  date: 'Jan 17, 2017',
  verified: true
}, true);

Use the linkPaths method to associate two paths. Use linkPaths when an element has two paths that refer to the same object, as described in Two paths referencing the same object.

When two paths are linked, an observable change to one path is observable on the other path, as well.

linkPaths('selectedUser', 'users.1');

Both paths must be relative to the same element. To propagate changes between elements, you must use a data binding.

To remove a path linkage, call unlinkPaths, passing in the first path you passed to linkPaths:

unlinkPaths('selectedUser');