Declarative property configuration with automatic attribute synchronization, change notification, computed properties, and property observation.
Configure element properties with automatic attribute synchronization and change observation.
/**
* Property configuration object that defines element properties
*/
interface PropertyDeclarations {
[property: string]: PropertyType | PropertyDeclaration;
}
/**
* Detailed property configuration
*/
interface PropertyDeclaration {
/** Type constructor for attribute deserialization */
type?: PropertyType;
/** Default value or function that returns default value */
value?: any | (() => any);
/** Whether property changes should be reflected to attributes */
reflectToAttribute?: boolean;
/** Whether property is read-only (creates _setProperty method) */
readOnly?: boolean;
/** Whether property changes fire property-changed events */
notify?: boolean;
/** Method and dependencies for computed property */
computed?: string;
/** Observer method called when property changes */
observer?: string;
}
/**
* Supported property types for attribute deserialization
*/
type PropertyType = StringConstructor | NumberConstructor | BooleanConstructor | ArrayConstructor | ObjectConstructor;Usage Examples:
import { PolymerElement, html } from '@polymer/polymer/polymer-element.js';
class PropertyExample extends PolymerElement {
static get is() { return 'property-example'; }
static get properties() {
return {
// Simple string property
name: String,
// Property with default value
count: {
type: Number,
value: 0
},
// Property with function default
items: {
type: Array,
value: () => []
},
// Reflected property (syncs to attribute)
active: {
type: Boolean,
value: false,
reflectToAttribute: true
},
// Notify property (fires events on change)
selectedIndex: {
type: Number,
value: -1,
notify: true
},
// Read-only property
isReady: {
type: Boolean,
value: false,
readOnly: true
},
// Computed property
displayName: {
type: String,
computed: 'computeDisplayName(name, count)'
},
// Property with observer
status: {
type: String,
value: 'idle',
observer: 'statusChanged'
}
};
}
computeDisplayName(name, count) {
return `${name} (${count})`;
}
statusChanged(newStatus, oldStatus) {
console.log(`Status: ${oldStatus} → ${newStatus}`);
}
// Read-only properties get _setPropertyName methods
markReady() {
this._setIsReady(true);
}
}Methods that are called when properties change, supporting both single and multi-property observation.
/**
* Observer methods array for watching property changes
*/
static get observers(): string[];Usage Examples:
class ObserverExample extends PolymerElement {
static get is() { return 'observer-example'; }
static get properties() {
return {
firstName: String,
lastName: String,
age: Number,
address: Object,
tags: Array
};
}
static get observers() {
return [
// Multi-property observer
'nameChanged(firstName, lastName)',
// Observer with wildcard for object changes
'addressChanged(address.*)',
// Observer with array mutation watching
'tagsChanged(tags.splices)',
// Complex path observation
'userLocationChanged(address.city, address.country)'
];
}
nameChanged(first, last) {
console.log('Name changed:', first, last);
}
addressChanged(changeRecord) {
console.log('Address property changed:', changeRecord);
}
tagsChanged(changeRecord) {
if (changeRecord) {
console.log('Array mutations:', changeRecord.indexSplices);
}
}
userLocationChanged(city, country) {
if (city && country) {
console.log('Location:', city, country);
}
}
}Automatic synchronization between element properties and HTML attributes.
/**
* Properties with reflectToAttribute: true automatically sync to attributes
* Attributes are automatically deserialized to properties based on type
*/Usage Examples:
class AttributeSync extends PolymerElement {
static get is() { return 'attribute-sync'; }
static get properties() {
return {
// String attribute: <element title="Hello">
title: {
type: String,
reflectToAttribute: true
},
// Boolean attribute: <element disabled> or <element disabled="">
disabled: {
type: Boolean,
reflectToAttribute: true
},
// Number attribute: <element count="5">
count: {
type: Number,
reflectToAttribute: true
},
// Object/Array attributes: <element data='{"key":"value"}'>
data: {
type: Object,
reflectToAttribute: true
}
};
}
}
// Usage in HTML:
// <attribute-sync title="Hello" disabled count="10" data='{"items":[1,2,3]}'></attribute-sync>Properties with notify: true fire events when they change, enabling two-way data binding.
/**
* Property change events follow the pattern: property-name-changed
* Event detail contains the new value
*/Usage Examples:
class NotifyExample extends PolymerElement {
static get is() { return 'notify-example'; }
static get properties() {
return {
value: {
type: String,
notify: true
}
};
}
connectedCallback() {
super.connectedCallback();
// Listen for property change events
this.addEventListener('value-changed', (e) => {
console.log('Value changed to:', e.detail.value);
});
}
updateValue() {
this.value = 'new value'; // Fires 'value-changed' event
}
}
// Two-way binding in templates:
// <notify-example value="{{boundProperty}}"></notify-example>Properties that are automatically calculated based on other properties.
/**
* Computed properties are read-only and automatically updated when dependencies change
* Format: 'methodName(dependency1, dependency2, ...)'
*/Usage Examples:
class ComputedExample extends PolymerElement {
static get is() { return 'computed-example'; }
static get properties() {
return {
first: String,
last: String,
// Simple computed property
fullName: {
type: String,
computed: 'computeFullName(first, last)'
},
// Computed property with complex dependencies
summary: {
type: String,
computed: 'computeSummary(user.*, settings.displayMode)'
}
};
}
computeFullName(first, last) {
return first && last ? `${first} ${last}` : '';
}
computeSummary(userChangeRecord, displayMode) {
const user = userChangeRecord.base;
if (displayMode === 'full') {
return `${user.name} - ${user.email}`;
}
return user.name;
}
}type PropertyType = StringConstructor | NumberConstructor | BooleanConstructor | ArrayConstructor | ObjectConstructor;
interface PropertyDeclaration {
type?: PropertyType;
value?: any | (() => any);
reflectToAttribute?: boolean;
readOnly?: boolean;
notify?: boolean;
computed?: string;
observer?: string;
}
interface PropertyDeclarations {
[property: string]: PropertyType | PropertyDeclaration;
}