You can declare properties on an element to add a default value and enable various features in the data system.
Declared properties can specify:
- Property type.
- Default value.
- Property change observer. Calls a method whenever the property value changes.
- Read-only status. Prevents accidental changes to the property value.
- Two-way data binding support. Fires an event whenever the property value changes.
- Computed property. Dynamically calculates a value based on other properties.
- Property reflection to attribute. Updates the corresponding attribute value when the property value changes.
Many of these features are tightly integrated into the data system, and are documented in the data system section.
In addition, a declared property can be configured from markup using an attribute (see attribute deserialization for details).
In most cases, a property that's part of your element's public API should be declared in the
properties
object.
To declare properties, add a static properties
getter to the element's class. The getter should
return an object containing property declarations.
class XCustom extends PolymerElement {
static get properties() {
return {
user: String,
isHappy: Boolean,
count: {
type: Number,
readOnly: true,
notify: true
}
}
}
}
customElements.define('x-custom', XCustom);
The properties
object supports the following keys for each property:
Key | Details |
---|---|
type |
Type: constructor Attribute type, used for deserializing from an attribute. Polymer supports deserializing the
following types: Unlike 0.5, the property's type is explicit, specified using the type's constructor. See attribute deserialization for more information. Default: |
value |
Type: boolean , number , string or function .Default value for the property. If Default: |
reflectToAttribute |
Type: boolean Set to Default: false |
readOnly |
Type: boolean If Default: false |
notify |
Type: boolean If Default: false |
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. Default: none |
observer |
Type: string The value is interpreted as a method name to be invoked when the property value changes. See Property change callbacks (observers) for more information. Default: none |
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
.)
Compatibility note: 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. This does not happen in 1.0—attribute to property
mappings are set up on the element at registration time based on the rules
described above.
Attribute deserialization
If a property is configured in the properties
object, an attribute on the
instance matching the property name will be deserialized according to the type
specified and assigned to a property of the same name on the element instance.
If no other properties
options are specified for a property, the type
(specified using the type constructor, e.g. Object
, String
, etc.) can be set
directly as the value of the property in the properties
object; otherwise it
should be provided as the value to the type
key in the properties
configuration object.
Boolean properties are set based on the presence of the attribute:
if the attribute exists at all, the property is set to true
, regardless
of the attribute value. If the attribute is absent, the property
gets its default value.
<script type="module">
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
class XCustom extends PolymerElement {
static get properties() {
return {
user: String,
manager: {
type: Boolean,
notify: true
}
}
}
connectedCallback() {
super.connectedCallback();
// render
this.textContent = 'Hello World, my user is ' + (this.user || 'nobody') + '.\n' +
'This user is ' + (this.manager ? '' : 'not') + ' a manager.';
}
}
customElements.define('x-custom', XCustom);
</script>
<x-custom user="Scott" manager></x-custom>
<!--
<x-custom>'s text content becomes:
Hello World, my user is Scott.
This user is a manager.
-->
To configure camel-case properties of elements using attributes, dash- case should be used in the attribute name.
<script type="module">
import {PolymerElement} from '@polymer/polymer/polymer-element.js';
class XCustom extends Polymer.Element {
static get properties() {
return {
userName: String
}
}
}
customElements.define('x-custom', XCustom);
</script>
<x-custom user-name="Scott"></x-custom>
<!-- Sets <x-custom>.userName = 'Scott'; -->
Note: Deserialization occurs both at create time, and at runtime (for
example, when the attribute is changed using setAttribute
). However, it is
encouraged that attributes only be used for configuring properties in static
markup, and instead that properties are set directly for changes at runtime.
Configuring boolean properties
For a Boolean property to be configurable from markup, it must default to false
. If it defaults
to true
, you cannot set it to false
from markup, since the presence of the attribute, with or
without a value, equates to true
. This is the standard behavior for attributes in the web platform.
If this behavior doesn't fit your use case, you can use a string-valued or number-valued attribute instead.
Configuring object and array properties
For object and array properties you can pass an object or array in JSON format:
<my-element book='{ "title": "Persuasion", "author": "Austen" }'></my-element>
Note that JSON requires double quotes, as shown above.
Custom deserializers
The type system includes built-in support for Boolean and Number values, Object and Array values
expressed as JSON, or Date objects expressed as any Date-parsable string
representation. To support other types, you can override the element's _deserializeValue
method.
_deserializeValue(value, type) {
if (type == MyCustomType) {
return stringToMyCustomType(value);
} else {
return super._deserializeValue(value, type);
}
}
Configuring default property values
Default values for properties may be specified in the properties
object using
the value
field, or set imperatively in the element's constructor
.
The value in the properties
object may either be a primitive value, or a function
that returns a value.
If you provide a function, Polymer calls the function once per element instance.
When initializing a property to an object or array value, either initialize the property in the constructor, or use a function to ensure that each element gets its own copy of the value, rather than having an object or array shared across all instances of the element.
class XCustom extends PolymerElement {
static get properties() {
return {
mode: {
type: String,
value: 'auto'
},
data: {
type: Object,
notify: true,
value: function() { return {}; }
}
}
}
}
constructor() {
super();
this.mode = 'auto';
this.data = {};
}
static get properties() {
return {
mode: String,
data: {
type: Object,
notify: true
}
}
}
Property change notification events (notify)
When a property is set to notify: true
, an event is fired whenever the
property value changes. The event name is:
property-name-changed
Where property-name
is the dash-case version of
the property name. For example, a change to this.firstName
fires
first-name-changed
.
These events are used by the two-way data binding system. External
scripts can also listen for events (such as first-name-changed
)
directly using addEventListener
. Property change events don't bubble, so
the event listener must be added directly to the element generating the event.
For more on property change notifications and the data system, see Data flow.
Read-only properties
When a property only "produces" data and never consumes data, this can be made
explicit to avoid accidental changes from the host by setting the readOnly
flag to true
in the properties
property definition. In order for the
element to actually change the value of the property, it must use a private
generated setter of the convention _setProperty(value)
where Property
is the property name, with the first character converted to uppercase (if alphabetic). For example, the setter for oneProperty
is _setOneProperty
, and the setter
for _privateProperty is _set_privateProperty
.
class XCustom extends PolymerElement {
static get properties() {
return {
response: {
type: Object,
readOnly: true,
notify: true
}
}
}
responseHandler(response) {
// set read-only property
this._setResponse(response);
}
}
For more on read-only properties and data binding, see How data flow is controlled.
Reflecting properties to attributes
In specific cases, it may be useful to keep an HTML attribute value in sync with
a property value. This may be achieved by setting reflectToAttribute: true
on
a property in the properties
configuration object. This causes any observable
change to the property to trigger an update to the corresponding attribute
(as described in Property name to attribute name mapping).
Since attributes only take string values, the property value is serialized
to a string, as described in Attribute serialization.
class XCustom extends PolymerElement {
static get properties() {
return {
loaded: {
type: Boolean,
reflectToAttribute: true
}
}
}
_onLoad() {
this.loaded = true;
// results in this.setAttribute('loaded', true);
}
}
Attribute serialization
When reflecting a property to an attribute or binding a property to an attribute, the property value is serialized to the attribute.
By default, values are serialized according to value's current type,
regardless of the property's type
value:
String
. No serialization required.Date
orNumber
. Serialized usingtoString
.Boolean
. Results in a non-valued attribute to be either set (true
) or removed (false
).Array
orObject
. Serialized usingJSON.stringify
.
To add custom serialization for other data types, override your element's _serializeValue
method.
_serializeValue(value) {
if (value instanceof MyCustomType) {
return value.toString();
}
return super._serializeValue(value);
}
Implicitly declared properties
A property is declared implicitly if you add it to a data binding or add it as a dependency of an observer, computed property, or computed binding.
Polymer automatically creates setters for these implicitly declared properties. However, implicitly declared properties can't be configured from markup.
Private and protected properties
JavaScript doesn't have any true protection for properties. By convention, Polymer elements usually
use a single underscore (_protectedProp
) to indicate a protected property or method (intended to
be used or overridden by subclasses, but not for public use), and a double underscore
(__privateProp
) for members that are private to the class.