This guide describes the changes required to migrate a Polymer element from 0.5 to 1.0.
Polyup Tool
We have been working on a tool called polyup
to automatically
perform many of the changes detailed in this guide. Check out the list of current
that it performs on its
README at github.
Migration
When migrating, the following items can be translated easily from 0.5 to 1.0:
- Web components polyfill library
- Element registration
- Local DOM template
- Declarative event handlers
- Property definitions
- Default attributes
- Layout attributes
- Use WebComponentsReady instead of the polymer-ready event
- domReady event
- Gestures
- Vulcanize
- Element & helper method changes
Other areas may require more changes to work correctly, either because there are significant API changes from 0.5, feature gaps, or both. These areas include:
The following sections discuss the changes required to migrate your code to this release, starting with the simpler topics.
Web components polyfill library
Polymer no longer requires the shadow DOM polyfill, which
is included in webcomponents.js
. Use the smaller webcomponents-lite.js
library
instead:
<script src="bower_components/webcomponentsjs/webcomponents.min.js"></script>
<script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
Element registration
The <polymer-element>
tag is no longer used to define an element. In this release,
these are replaced by a <dom-module>
element (to define local DOM and styles)
and the Polymer
call (to register the element).
<polymer-element name="register-me">
<template>
<div>Hello from my local DOM</div>
</template>
<script>
Polymer();
</script>
</polymer-element>
<dom-module id="register-me">
<template>
<div>Hello from my local DOM</div>
</template>
<script>
Polymer({is: "register-me"});
</script>
</dom-module>
In this release:
-
The element name is specified using the
is
property on the prototype (required). -
If you supply a local DOM template, it's wrapped in a
<dom-module>
element with an ID that matches the element name. -
Polymer supports the
extends
keyword as in 0.5, but at this point you can only extend built-in DOM elements, such as<button>
. For more information, see Inheritance.
In 0.5, you can define published properties and default attributes by setting
attributes on the <polymer-element>
tag. These features are now only available
on the prototype.
If you have default attributes on your <polymer-element>
declaration, make a
note of them for later:
<polymer-element name="register-me" tabindex="0">
These are now declared using the hostAttributes
object on the prototype. For example:
hostAttributes: {
tabindex: 0
}
See Default attributes for details.
If you've published any properties using the attributes
attribute, make a note of them:
<polymer-element name="register-me" attributes="foo">
In general, any property published in 0.5 should be declared on
the properties
object now. For example:
properties: {
foo: { type: String }
}
See Declared properties for details.
Now the Polymer
function returns a working constructor:
var RegisterMe = Polymer({is: "register-me"});
var el = new RegisterMe();
// equivalent to:
var el = document.createElement("register-me");
Local DOM template
Polymer now uses an abstract local DOM mechanism. Local DOM can be implemented using native shadow DOM or using a lightweight alternative, "shady DOM". Polymer uses shady DOM by default on all browsers. You can opt into using native shadow DOM where available.
In 0.5, the local DOM template is specified as a child of the <polymer-element>
:
<polymer-element name="template-me" noscript>
<template>
<!-- local DOM styles -->
<style>
div { color: red }
</style>
<div>This is local DOM</div>
</template>
</polymer-element>
To specify a local DOM template now, use a dom-module
tag, with your custom element name as its id
:
<!-- ID attribute must match element name passed to Polymer() -->
<dom-module id="template-me">
<template>
<!-- local DOM styles -->
<style>
div { color: red }
</style>
<div>This is local DOM</div>
</template>
<script>
Polymer({is: "template-me"});
</script>
</dom-module>
Note: Prior to Polymer 1.1, we recommended placing
element styles outside of the <template>
tag. As of 1.1, styles
outside the template are supported, but this is slower than placing styles
inside the template and is no longer recommended.
The <script>
tag can be inside or outside of the <dom-module>
element, but the element's
template must be parsed before the call to Polymer
.
Dependency Ordering
Any custom element that the element depends on must be registered first. That
is, if <parent-element>
includes <child-element>
in its local DOM,
<child-element>
must be registered before <parent-element>
.
Declarative event handlers
Curly brackets ({{}}) are not used for declarative event handlers in the template.
<input on-input="{{checkValue}}">
<input on-input="checkValue">
The event handler is no longer passed the third argument, inSender
, but is still passed the first two:
inEvent
is the standard event object.inDetail
is a convenience form ofinEvent.detail
.
Declared properties
Polymer 0.5 has two mechanisms to publish properties—the attributes
attribute and the publish
object. Either of these mechanisms can be used to
publish a property:
<polymer-element name="publish-me" attributes="myproperty">
or:
Polymer({
publish: {
myproperty: 0
}
});
In addition, 0.5 has separate objects for defining computed properties and
property observers (the computed
and observe
objects).
Polymer now provides a single
property configuration object, the properties
object:
Polymer({
is: "publish-me",
properties: {
prop: Number,
observedProp: {
type: Number,
value: 42,
observer: 'observedPropChanged'
},
computedProp: {
type: String,
computed: 'computeValue(prop)'
}
}
});
Simple properties (like prop
above) can be declared as
propertyName: type
.
For more complicated properties, use propertyName:
config
, where the config
object can
contain the following keys:
Key | Details |
---|---|
type |
Type: constructor (one of Boolean , Date , Number , String , Array or Object )Attribute type, used for deserializing from an attribute. Unlike 0.5, the property's type is explicit, specified using the type's constructor. See attribute deserialization for more information. |
value |
Type: boolean , number , string or function .Default value for the property. If |
reflectToAttribute |
Type: boolean Set to |
readOnly |
Type: boolean If |
notify |
Type: boolean If |
computed |
Type: string The value is interpreted as a method name and argument list. The method is invoked to calculate the value whenever any of the argument values changes. Computed properties are always read-only. See Computed properties for more information. |
observer |
Type: string The value is interpreted as a method name to be invoked when the property value
changes. Note that unlike in 0.5, property change handlers must be registered
explicitly. The |
Any property in your element's public API should be declared in the properties
object.
ES5 accessors not supported
You cannot define a declared property that uses ES5 accessors. Polymer creates its own accessors to monitor property changes for observers, data binding, and computed properties.
For some use cases, you may be able to accomplish the same thing with either computed properties, observers, or read-only properties.
If you don't need any of the features of declared properties, you can simply add a property with ES5 accessors to your prototype.
Property name to attribute name mapping
For data binding, deserializing properties from attributes, and reflecting properties back to attributes, Polymer maps attribute names to property names and the reverse.
When mapping attribute names to property names:
-
Attribute names are converted to lowercase property names. For example, the attribute
firstName
maps tofirstname
. -
Attribute names with dashes are converted to camelCase property names by capitalizing the character following each dash, then removing the dashes. For example, the attribute
first-name
maps tofirstName
.
The same mappings happen in reverse when converting property names to attribute
names (for example, if a property is defined using reflectToAttribute: true
.)
In 0.5, Polymer attempted to map attribute names to corresponding
properties. For example, the attribute foobar
would map to the property
fooBar
if it was defined on the element. Polymer does not do
this anymore—attribute to property mappings are set up on the element at
registration time based on the rules described above.
<polymer-element name="map-me" attributes="fooBar">
<script>
Polymer({
fooBar: ""
});
</script>
</polymer-element>
<map-me foobar="test1"></map-me> <!-- sets map-me.fooBar -->
<map-me FOOBAR="test2"></map-me> <!-- sets map-me.fooBar -->
<map-me foo-bar="test3"></map-me> <!-- no matching property to set -->
<script>
Polymer({
is: "map-me"
properties: {
fooBar: {
type: String,
value: ""
}
}
});
</script>
<map-me foo-bar="test2"></map-me> <!-- sets map-me.fooBar -->
<map-me FOO-BAR="test3"></map-me> <!-- sets map-me.fooBar -->
<map-me foobar="test1"></map-me> <!-- sets map-me.foobar -->
Attribute deserialization
For any property listed in the properties
object, the user can set a value
on the corresponding attribute to initialize the property. Deserialization works much
like it did in 0.5 (where any property in the publish
object
was deserialized).
There are two differences from 0.5:
-
The
type
field is used to determine how to deserialize the attribute value. If no type is specified, the property takes the string value of the attribute. In 0.5, the type was determined implicitly, from the type of the default value. -
Polymer does not modify the string before JSON parsing
Object
andArray
values. In 0.5, Polymer replaced single quotes with double quotes. This allowed some invalid JSON to work correctly but broke some valid JSON.
<my-element foo="{ 'title': 'Persuasion', 'author': 'Austen' }"></my-element>
<my-element foo='{ "title": "Persuasion", "author": "Austen" }'></my-element>
Binding to properties
In 0.5, only properties that are explicitly published can be data bound from outside the element. Now, any property is available for data binding, whether or not it is listed in the properties
object. For more details on data binding in the this release, see Data binding.
Default values
In Polymer 0.5, default values can be specified multiple ways: directly on the
prototype, in the publish
object, or in the created
method (for objects and
arrays). Now, default values are specified on the properties
object, using the value
key.
For value
, you can provide either a default value or a function that returns
the default value. If value
is a function, the function is invoked during the
configuration phase (after the created
callback and before ready
) and the
return value is used as the value of the property.
If the default value should be an array or object unique to the instance, create the array or object inside a function.
value: function() { return {}; },
Computed properties
Computed properties must be moved from the computed
object to the properties
object.
All computed properties are defined using a function name and one or more dependent properties,
in parentheses.
Arbitrary expressions are not supported in computed properties—they need to be moved to functions.
computed: {
product: 'multiply(x,y)',
sum: 'x + y'
},
multiply: function(a, b) {
return a * b;
}
properties: {
product: {
computed: 'multiply(x,y)'
},
sum: {
computed: 'add(x,y)'
}
},
multiply: function(a, b) {
return a * b;
},
add: function(a, b) {
return a + b;
}
Computed properties are always read-only (in the sense that they can't be set directly or via data binding). All properties can be data bound now, so unlike 0.5, there is no need to explicitly publish a computed property.
For more information, see [Computed properties](devguide/properties.html #computed-properties) in the Developer guide.
Property observers & Changed watchers
0.5 supported implicit change handlers. If a property foo
changed, the
corresponding fooChanged
handler was called automatically. If your element
uses any propertyNameChanged
handlers, you must
explicitly register them in the properties
object.
<polymer-element name="observe-prop" attributes="foo">
<script>
Polymer({
foo: '',
fooChanged: function(oldValue, newValue) {
...
}
});
</script>
</polymer-element>
Polymer({
is: "observe-prop",
properties: {
foo: {
type: String,
value: '',
observer: 'fooChanged'
}
},
fooChanged: function(newValue, oldValue) {
...
}
});
Note that the arguments to the observer are currently in the opposite order compared to 0.5.
The observers
array should be used for change observers with
multiple dependencies:
properties: {
x: Number,
y: Number,
z: Number
},
observers: [
"coordinatesChanged(x, y, z)"
]
Note: As in 0.5, the observers
array is a top-level object on the
prototype: it isn't part of the properties
object.
Unlike Polymer 0.5, observers do not support the
this.$.elementId
syntax for observing changes to the
properties of local DOM children. However, in some cases you can use data
binding to bind a property to the child element's property, and observe the
local property instead.
<polymer-element name="observe-me">
<template>
<my-input id="input">
</template>
<script>
Polymer({
observers: {
'this.$.input.value': 'valueChanged'
},
valueChanged: function() { … }
});
</script>
</polymer-element>
<dom-module id="observe-me">
<template>
<my-input value="{{inputval}}">
</template>
<script>
Polymer({
is: "observe-me",
properties: {
inputval: {
observer: 'valueChanged'
}
},
valueChanged: function() { … }
});
</script>
</dom-module>
For more information, see Observers and computed properties in the Developer guide.
Default attributes
In 0.5, default attributes are defined on the <polymer-element>
declaration:
<polymer-element name="register-me" checked tabindex="0" role="checkbox" noscript>
</polymer-element>
Now you define default attributes by adding a hostAttributes
object to the prototype:
hostAttributes: {
checked: true,
tabindex: 0,
role: "checkbox"
}
Default attributes are added to the instance at creation time. The default
attribute values are serialized based on the value type. Boolean attributes use
the standard HTML mechanism—the attribute is present if true, absent if false.
(So adding a default attribute with a value of false
has no effect.)
Note that hostAttributes
only specifies static, default attributes. To
set an attribute dynamically based on a property value, see
Reflecting properties to attributes
in the Developer guide, or use setAttribute
directly.
Also, note that the class
attribute is ignored if it is specified in the hostAttributes
object.
Listeners
In 0.5 you could declare event listeners for a custom element as an attribute on the
polymer-element
declaration:
<polymer-element name="magic-button" on-scroll="{{onScrollHandler}}" on-tap="{{wasTapped}}">
</polymer-element>
Now you define these listeners on the listeners
object on the prototype:
listeners: {
scroll: 'onScrollHandler',
tap: 'wasTapped'
}
For more info, see Event listener setup in the Developer guide.
Layout attributes replaced by layout classes and custom CSS mixins
The layout attributes stylesheet that's included in Polymer 0.5 has been replaced with an optional stylesheet that uses custom CSS mixins. If your element uses layout attributes, you'll need to make some changes.
There are two ways to use the new iron-flex-layout
package. You can use the layout mixins
directly in your stylesheets, or use a predefined set of layout classes.
For a complete guide, see the
iron-flex-layout
guide
in the Element catalog.
For examples of the layout properties in use, see the
iron-flex-layout
demo.
Use layout mixins
-
Install the
iron-flex-layout
component:bower install --save PolymerElements/iron-flex-layout
-
Add an import for
iron-flex-layout.html
on any element that used the layout attributes.<link rel="import" href="bower_components/iron-flex-layout/iron-flex-layout.html">
-
Replace the layout attributes with custom CSS mixins, using
@apply
inside your element's CSS.@apply --layout-horizontal; @apply --layout-wrap;
See the
iron-flex-layout
guide in the Element catalog for a list of the available mixins.
<link rel="import" href="/bower_components/polymer/polymer.html">
<!-- layout attributes for the host defined on <polymer-element> -->
<polymer-element name="x-profile" layout vertical>
<template>
<!-- layout attributes for a local DOM element -->
<div layout horizontal center>
<img src="{{avatarUrl}}">
<span class="name">{{name}}</span>
</div>
<p>{{details}}</p>
</template>
<script>
Polymer({ ... });
</script>
</polymer-element>
<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/iron-flex-layout/iron-flex-layout.html">
<dom-module id="x-profile">
<template>
<style>
:host {
/* layout properties for the host element */
@apply --layout-vertical;
}
.header {
/* layout properties for a local DOM element */
@apply --layout-horizontal;
@apply --layout-center;
}
</style>
<div class="header">
<img src="{{avatarUrl}}">
<span class="name">{{name}}</span>
</div>
<p>{{details}}</p>
</template>
<script>
Polymer({
is: "x-profile"
});
</script>
</dom-module>
To see the available custom layout mixins, ee the
iron-flex-layout
guide in the
Element catalog.
Using the layout classes
If you want to keep using layout classes, iron-flex-layout
includes a separate import,
iron-flex-layout-classes.html
, that defines a set of style modules you can import into
an element, or into the main document.
To use the layout classes:
-
Install the
iron-flex-layout
component:bower install --save PolymerElements/iron-flex-layout
-
Add an import for
iron-flex-layout-classes.html
on any element that used the layout attributes. (Or in the main document, if you're using layout attributes in the main document.)<link rel="import" href="bower_components/iron-flex-layout/iron-flex-layout-classes.html">
-
Include the style modules you require:
<style include="iron-flex iron-flex-alignment"></style>
See the
iron-flex-layout
guide in the Element catalog for a list of the available style modules, and the classes they define.Use
<style is="custom-style">
to include style modules in the main document. -
Replace the layout attributes with classes.
Example of using the layout classes in the main page:
<head>
...
<!-- import module -->
<link rel="import" href="/bower_components/iron-flex-layout/iron-flex-layout-classes.html">
<!-- include the necessary style modules -->
<style is="custom-style" include="iron-flex iron-positioning"></style>
</head>
<body class="fullbleed layout horizontal center-center">
...
</body>
For more information, see the
iron-flex-layout
guide
in the Element catalog.
Use WebComponentsReady instead of polymer-ready
The polymer-ready
event was supported in release 0.5 because Polymer
elements performed some asynchronous initialization which meant that they weren't ready
to use when the polyfill WebComponentsReady
event fired. This initialization is now synchronous, so the WebComponentsReady
event
can be used instead.
If you are not using the web components polyfills (for example, in a Chrome extension),
the WebComponentsReady
event will not fire. With native HTML imports and custom elements,
elements upgrade synchronously, so the event is not required. Simply place any scripts that
manipulate Polymer elements at the end of the page, and all elements should
be ready.
domReady event
This release doesn't support the domReady
callback. This callback was a partial
solution to the problem of determining when sibling elements and light DOM children were ready.
A more complete solution is in progress. In the meantime, if you are using domReady
in
1.0 you can replace it by using the async
method inside your attached
callback:
attached: function() {
this.async(function() {
// code that formerly resided in `domReady`
});
}
For more on element initialization, see: Initialization order in the Developer guide.
Gestures
This release includes support for a limited number of gestures, including, tap
, up
, down
, and
track
. If you are using these events using either declarative event handlers or the listeners
object, you shouldn't need to update anything.
Note that trackstart
and trackend
are not fired as separate events, but as track
events with
detail.state
set to start
or end
, respectively.
For more details, see Gesture events.
Vulcanize
The latest versions of the vulcanize
tool are updated for the new Polymer
element format. Newer versions of vulcanize are not backward compatible:
vulcanize
versions 1.0 and higher are compatible with Polymer 0.8+ only. The current version is 1.4.2.vulcanize
versions below 1.0 are compatible with Polymer 0.5 only. The current version is 0.7.10.
The --csp
option to vulcanize
is now a separate utility, crisper
. Typical usage
is:
vulcanize --inline-scripts --inline-css target.html | \
crisper --html build.html --js build.js
For more details on the vulcanize
arguments, see the README.
Element & helper method changes
Some element methods and helper methods have been renamed, moved, or changed signatures. For a complete list of element methods, see the API reference.
Element methods: job renamed to debounce
The job
method in 0.5 is replaced by debounce
. The arguments are identical.
This release includes several related methods, including methods for canceling a pending task, and immediately executing a pending task. For details, see Instance methods.
Element methods—async
The async
method works slightly differently than in 0.5 when called without a specified delay, like:
this.async(doSomething);
In this release, this adds a callback to the browser's microtask queue, which is
handled asynchronously, but before the next event from the event queue is
handled. If you call async
from within the async
callback, the second
async
callback is called during the same task as the first callback.
In 0.5, the async
method without a delay scheduled work using
requestAnimationFrame
. If you call async
from within an async
callback,
the second async
callback is fired during a subsequent task (in the next frame
interval). If you want this behavior, use requestAnimationFrame
instead.
Element methods: fire API changes
The fire
method now takes three arguments:
fire(type, [detail], [options]);
The options
object can contain the following properties:
node
. Node to fire the event on. Defaults tothis
.bubbles
. Whether the event should bubble. Defaults totrue
.cancelable
. Whether the event can be canceled withpreventDefault
. Defaults tofalse
.
Element methods—resolvePath renamed to resolveUrl
The resolvePath
method in 0.5 is replaced by resolveUrl
. The arguments are identical.
Element methods—Polymer.import replaced by importHref
The global Polymer.import
function is replaced by importHref
. The
new method can be invoked from an element as this.importHref
. Outside
an element, it can be called as as Polymer.Base.importHref
.
Manipulating DOM
If your element manipulates its light DOM or local DOM imperatively, or your
application manipulates the children of Polymer elements using the standard DOM
manipulation APIs, you need to use the Polymer.dom
APIs for manipulating DOM.
In addition, if you use APIs like querySelector
or querySelectorAll
, you
should use the Polymer.dom
versions, which are aware of local DOM trees. If
you do not do any imperative DOM manipulation, you can skip this section.
The Polymer.dom
method takes a DOM node as an argument and returns a wrapper
that implements the following methods and properties.
Adding and removing children:
Polymer.dom(parent).appendChild(node)
Polymer.dom(parent).insertBefore(node, beforeNode)
Polymer.dom(parent).removeChild(node)
Polymer.dom.flush()
Parent and child accessors:
Polymer.dom(parent).childNodes
Polymer.dom(node).parentNode
Polymer.dom(node).firstChild
Polymer.dom(node).lastChild
Polymer.dom(node).firstElementChild
Polymer.dom(node).lastElementChild
Polymer.dom(node).previousSibling
Polymer.dom(node).nextSibling
Polymer.dom(node).textContent
Polymer.dom(node).innerHTML
Query selector:
Polymer.dom(parent).querySelector(selector)
Polymer.dom(parent).querySelectorAll(selector)
Content APIs:
Polymer.dom(contentElement).getDistributedNodes()
Polymer.dom(node).getDestinationInsertionPoints()
Node mutation APIs:
Polymer.dom(node).setAttribute(attribute, value)
Polymer.dom(node).removeAttribute(attribute)
Polymer.dom(node).classList
In each case, the Polymer.dom
methods and properties behave like the standard
DOM would on a browser with native Shadow DOM support, with the following
differences:
-
The insert, append, and remove operations are transacted lazily in certain cases for performance. In order to interrogate the DOM (for example, offsetHeight, getComputedStyle, etc.) immediately after one of these operations, call
Polymer.dom.flush()
first. -
Calling
append
/insertBefore
where parent is a custom Polymer element adds the node to the light DOM of the element. In order to add children to the local DOM of a custom element, useelement.root
as the parent, whereelement
is the custom element you're adding to. Theroot
property identifies the custom element's shadow root or shady root (depending on which system is in use in the browser). -
Method and properties that return a list of nodes return an
Array
, not aNodeList
as in standard DOM.
this.appendChild(node);
Polymer.dom(this).appendChild(node);
this.shadowRoot.appendChild(node);
Polymer.dom(this.root).appendChild(node);
Before (append to a container in local DOM):
this.$.container.appendChild(node);
Polymer.dom(this.$.container).appendChild(node);
Note that Polymer.dom
provides only a subset of the standard DOM API, so for
example firstChild
must be replaced with childNodes[0]
:
Polymer.dom(this).insertBefore(node, Polymer.dom(this).childNodes[0]);
You can safely use Polymer.dom
when manipulating any elements in
your DOM tree. When used on elements that don't have a local DOM tree,
Polymer.dom
simply manipulates the light DOM children, just like the built-in
DOM methods.
Local DOM aware query selector:
Polymer.dom(document).querySelectorAll(selector);
Returns all elements matching selector in the main document.
Event retargeting
Shadow DOM has a feature called "event retargeting" which changes an event's target as it bubbles up, such that target is always in the receiving element's light DOM.
Use Polymer.dom(event)
to get a normalized event object that provides
equivalent target data on both shady DOM and shadow DOM. Specifically, the
normalized event has the following properties:
-
rootTarget
: The original or root target before shadow retargeting (equivalent toevent.path[0]
under shadow DOM orevent.target
under shady DOM). -
localTarget
: Retargeted event target (equivalent toevent.target
under shadow DOM). -
path
: Array of nodes through which event will pass (equivalent toevent.path
under shadow DOM).
Data binding
Data binding in this release is based on generated property accessors, generated at element registration time, which provides high performance with minimal cost at instantiation time. The main differences in binding are:
-
No expression or filter support. Binding is to properties or paths only. (The negation operator,
!
, is supported for convenience.) In many cases, computed properties can be used in place of complex binding expressions. -
Polymer doesn't use
Object.observe
to watch object changes, so in some cases your code needs to use explicit APIs for manipulating objects in order for bindings to update. For more information, see Observable changes, and Work with object and array data in the Developer Guide.
As of release 1.2.0, Polymer includes support for compound bindings, which combine binding annotations and literal strings:
<span>Name: {{lastname}}, {{firstname}}</span>
Support for repeating templates, conditional templates and autobinding templates is provided by helper elements.
There are many subtle differences between the old and new binding systems as well. See Data binding in the Developer guide for more details on the new system.
Property bindings
Note: Unlike 0.5, properties don't need to be explicitly published to enable data binding. An element can bind to a property on any element in its local DOM using the corresponding attribute name. By convention, properties not intended for external use should be prefixed with an underscore.
Data binding is now one-way by default: the property can be set from the
outside, but does not propagate changes to the outside. For a property that can
be two-way data bound, add the notify
property:
Polymer({
is: "publish-me",
properties: {
value: {
type: Number,
notify: true
}
}
});
If another element includes publish-me
in its local DOM and binds to the
value
property, value changes are propagated upward:
<dom-module id="binding-owner">
<template>
<publish-me value="{{twoway}}"></publish-me>
</template>
<script>
Polymer({ is: "binding-owner" });
</script>
</dom-module>
In this example, when publish-me.value
changes, the change is pushed up to binding-owner.twoway
.
The element requesting the binding can explicitly specify one-way binding using square brackets: [[]]
.
<publish-me value="[[oneway]]"></publish-me>
To make your code more easier to read, you may want to use the
[[property]]
form by default, and only use
{{property}}
for two-way bindings.
For more details, see Data binding in the Developer guide.
Attribute bindings
In 0.5, you can bind a binary attribute value like this:
<div hidden?="{{isHidden}}">Boo!</div>
Where the hidden
attribute is added if, and only if, isHidden
is truthy.
Change this expression to
attributeName$="{{propertyName}}"
.
For example:
<div hidden$="{{isHidden}}">Boo!</div>
The new version is more general-purpose: it can handle both boolean and valued attributes. The property value is serialized, just like it is for reflected properties (see Attribute serialization in the Developer guide for details).
For example:
<input type="checkbox" checked$="{{isComplete}}"
aria-label$="{{completedLabel}}">
If isComplete
is true
and completedLabel
is "Completed", this appears as:
<input type="checkbox" checked aria-label="Completed">
Note: If you are using the attributeName$=
syntax with
a non-boolean property, you'll need to change your code to get the same
results. For example, use a computed binding to cast the original property to
a Boolean.
Computed bindings
Computed properties only needed in the template can be bound directly in the template without an intermediate property on the instance:
<dom-module id="inline-compute">
<template>
...
<button hidden$="[[_computeButtonHidden(dirty)]]">
Save
</button>
</template>
<script>
Polymer({
is: "inline-compute",
_computeButtonHidden: function(dirty) {
return !dirty;
},
...
});
</script>
</dom-module>
The arguments to a computed binding are evaluated relative to the current binding scope. For more details, see Computed bindings.
Data binding helper elements
Support for repeating templates, conditional templates and autobinding templates is provided by helper elements.
Template Repeat
The template repeat
mechanism is replaced by the new dom-repeat
helper element.
Note: dom-repeat
and the other helper elements described here are included as part
of the Polymer library, and do not need to be installed or imported separately.
Pass data to the <dom-repeat>
by specifying an items
array, and bind to individual item properties using item.
propertyName:
<template is="dom-repeat" items="{{myData}}">
<p>{{item.name}}</p>
</template>
Note that browsers that do not support templates natively don't allow
<template>
tags inside of <table>
or <select>
elements.
Polymer 0.5 provided a workaround for this using the [template
attribute](/0.5/docs/polymer/databinding-compat.html#elements-that-cant-
contain-a-template). There is no equivalent workaround for the new release at
this point.
If you are using event.target.templateInstance.model
to get model information for events,
in most cases you can replace this with event.model
. For more information, see
Handling events in dom-repeat
templates.
For more information, see Template repeater.
Autobinding templates
Autobinding templates are replaced by the new dom-bind
helper element.
If you are relying on the template-bound
event fired by auto-binding templates
in 0.5, note that all of the template helpers in 1.0 fire an equivalent dom-change
event.
Note: dom-bind
is included as part of the Polymer library, and does not need to be installed or imported separately.
For more information, see Autobinding templates.
Conditional templates
Conditional templates (<template if=condition>
) are replaced by the new dom-if
helper element.
Note: dom-if
is included as part of the Polymer library, and does not need to be installed or imported separately.
For more information, see Conditional templates.
Binding to native input elements
Two-way binding to the values of native input elements does not work
automatically as it did in 0.5, since two-way data binding relies on
special property-changed
events generated by
Polymer elements.
You can work with native input elements by specifying a custom event name in the binding, like this:
<!-- Listens for "change" event and sets hostValue to <input>.value -->
<input value="{{hostValue::change}}">
For more information, see Two-way binding to native elements.
Binding to sibling elements
0.5 provided a mechanism to bind directly to properties on sibling elements, using $. For example:
<template>
<x-publisher id="publisher"></x-publisher>
<x-subscriber input="{{$.publisher.output}}"></x-subscriber>
</template>
In most cases, this can be replaced by binding both values to a shared property:
<template>
<x-publisher id="publisher" output="{{data}}"></x-publisher>
<x-subscriber input="{{data}}"></x-subscriber>
</template>
Styling
Element-level styling should be placed inside the local DOM <template>
tag, as
in 0.5.
<dom-module>
<template>
<style>
:host { display: block }
</style>
...
</template>
</dom-module>
External stylesheets are supported using HTML Imports. See Shared styles and external stylesheets in the Developer guide for details.
Document-level styling can be added using the custom-style
element:
<style is="custom-style">
html /deep/ iron-icon {
color: red;
}
</style>
The custom-style
element modifies the style sheets to work with either shady DOM or
shadow DOM. As such, it's the equivalent of the shim-shadowdom
attribute
supported in 0.5.
In addition to shimming shadow DOM selectors (/deep/
and ::shadow
),
custom-style
prevents styles from leaking downward into the shady DOM trees.
**Note: <custom-style>
is included as part of the Polymer library, and does not
need to be installed or imported separately.
For more information on the custom-style
element, see Custom element for document styling
in the Developer guide.
Styling distributed children with ::content
See Styling local DOM.
Styling elements distributed to content (via ::content) requires using a wrapper element for compatibility with shady DOM.
<template>
<style>
.wrapper > ::content .foo {
color: lemonchiffon;
}
</style>
<div class="wrapper">
<content></content>
</div>
</template>
Inheritance
This release doesn't support inheriting from other custom elements—only from standard DOM elements. This will be supported in a future release.
In the meantime, you can achieve many of the same results using either composition or mixins to share functionality between elements.