For Developers‎ > ‎

Polymer 1.0

Polymer 1.0 has some key differences from previous versions. This document concisely outlines the major changes of interest to Chromium, informed by our work migrating the Settings UI from 0.5 to 1.0. We assume some basic knowledge of Polymer; you've worked through a tutorial or have been using Polymer 0.5.

This article was written for migrating only to Polymer 1.0. To stay informed on important changes in new versions, follow the Polymer blog. For specific information on developing WebUI with Polymer, see Updating WebUI for Material Design.

Polymer 1.0 in broad strokes

  • Structure of the Polymer call has changed somewhat (example)
  • Structure of the HTML has also changed (example)
  • Properties can be configured with keys: type, value, notify, observer, readOnly, reflectToAttribute, computed
  • Can extend native HTML elements, but not custom elements
  • Binding expressions are limited to the ! operator and computed properties
  • Mixins are now behaviors
  • Use custom CSS properties and mixins instead of /deep/ and ::shadow

Getting started

By default, 1.0 uses shady DOM. In Chromium we want shadow DOM, so make sure this line runs before the Polymer library is imported:

Polymer = { dom: 'shadow' };

Achieving data binding nirvana

Data binding doesn't work the same as 0.5; it seems a bit complicated at first but is based on simple rules.

A host element can bind its published properties to the published properties, attributes or text content of elements in its local DOM. How this plays out depends on the binding annotation used and the configuration of the child element’s properties.

To bind a host element’s property to a property of a child element, provide the binding annotation to the corresponding attribute: <foo-child their-property="{{myProperty}}"></foo-child>

Polymer maps the attribute name to the corresponding property by converting dash-case to camelCase. Data binding does not set the attribute of the element, only the property, unless $= is used rather than =, in which case the attribute is set instead of the property. (Separately, an element’s published property may be configured with reflectToAttribute, which would cause the element’s attribute to be set to the serialized value of its corresponding property.)

How configuration and binding annotation affect direction of data binding:

Child property config notify: false
readOnly: false
notify: true*
readOnly: false
notify: true*
readOnly: true
notify: false
readOnly: true
Binding        
{{curly}} host --> child host <--> child host <-- child no binding
[[square]]  host --> child host --> child silly no binding

So using curly braces only takes effect when the child’s property is notify: true, and setting the child to notify: true only takes effect when the host uses curly braces.

In other words:
  • Host-to-child binding requires: readOnly: false
  • Child-to-host binding requires: {{curly}}, notify: true*
  • Two-way binding requires all of the above: {{curly}}, notify: true*, readyOnly: false
* notify: true, or, send a <property>-changed event from your element manually.

Using curly braces only when two-way binding is desired will make the intention of your code clearer.

Binding to sub-properties

Sub-properties can be bound just like properties, but changes may not always propagate as expected.

If a path is changed automatically by a binding, the change propagates normally to other bindings to that path (and its sub-paths).

If a path is changed imperatively, you must use notifyPath(pathValue, newValue) for the bindings to update. A convenience function lets you set the new value and notify all in one: this.set(pathValue, newValue). See also: array mutation.

Two-way binding to native elements

<foo-child some-property="{{parentValue}}"> is basically sugar for:
<foo-child some-property="{{parentValue::some-property-changed}}">
which updates parentValue when some-property-changed is called. That event is called automatically if notify: true is set.

So we can achieve two-way binding with native elements by taking advantage of native events:

<input type="checkbox" checked="{{hostChecked::change}}">

If we leave out the ::event syntax, we only get one-way, host-to-child binding for the native element.

Annotated computed properties

These are function calls which specify at least one property to observe, so the value is recalculated whenever the parameters change. Used for downward data propagation (host-to-child) when the property need not be part of the API.

<x-foo bar="{{getBar(abc, xyz)}}">

Note: getBar is only called after abc and xyz.baz have been defined on the host (e.g. using the value key in properties).

Migration pain points

Templates

New template helpers:
  • <template repeat> is replaced by <template is="dom-repeat" items="{{...}}">.
  • <template if> is replaced by <template is="x-if" if="{{...}}"> with different behavior; use with care.
  • <template bind> is gone.
  • <template is=”autobind”> is replaced by <template is="dom-bind">.
  • <array-selector> is added.
Attributes in your HTML should use hyphen-casing to set the corresponding camelCased published property.

Shared stylesheets should be created inline inside their own <dom-module>s and included with the new <style include> syntax.

Deprecated as of 1.1: In 1.0, your stylesheets can be imported within <dom-module> but outside of the <template> element using a special <link rel="import" type="css"> import. This is deprecated and support may be removed in the future.

Properties and observers

The properties block replaces the publish block. All properties that use data binding should be defined here. Properties can be assigned a type (Boolean, Number, String, Array, Object), or an object which represents their configuration, similar to 0.5. Some changes to the config object:
  • The type must be specified.
  • Observers must be explicitly specified with the observer key.
  • Setting notify: true will make the property available for data binding.
  • reflect is now reflectToAttribute.
Property change observers are no longer set up automatically, and their arguments are in reverse order: (newValue, oldValue).

An observer that should be triggered by multiple properties can be specified separately, in your observers array, e.g.: 'oddPropsChanged(prop1, prop3, prop5)'

The observers array can also specify sub-properties to observe. These aren’t real observers; these sub-properties must be changed by Polymer data binding or using set(path, value) or notifyPath(path, value) for the observer to be called. (See "Binding to sub-properties" above). [It seems the observer is also called if the path’s root property is set, but this is not documented.]

The observers block can also specify wildcard paths ('user.*' observes user and all its sub-properties recursively); the same rules apply; in this case the change handler is a record consisting of { path, value, base } (where base is the value of the path’s root property).

More on binding

To bind to attributes (instead of properties), use $=. Prefer $= for native element attributes:

<a href$="{{link}}">

Event handler attributes don't use {{}} anymore:

<paper-button on-click="handleClick">

Obsolete: Newer versions have implemented string interpolation. In the original 1.0, text bindings had to span the entire tag. If you see this in code, feel free to remove unnecessary tags surrounding bindings when it makes sense:

<div>Hello {{world}}</div>  // 1.0 used to require <div>Hello <span>{{world}}</span></div>

Comments