diff --git a/docs/_guide/properties.md b/docs/_guide/properties.md index 4394646e..2a6d465c 100644 --- a/docs/_guide/properties.md +++ b/docs/_guide/properties.md @@ -385,56 +385,65 @@ this.myProp = 'hi'; // invokes myProp's generated property accessor Generated accessors automatically call `requestUpdate`, initiating an update if one has not already begun. -### Create custom property accessors {#accessors-custom} +### Create your own property accessors {#accessors-custom} -To specify how getting and setting works for a property, create custom accessors instead of using automatically generated accessors: +To specify how getting and setting works for a property, you can define your own property accessors. For example: ```js // Declare a property static get properties() { return { myProp: { type: String } }; } -// Custom accessors +// Define accessors set myProp(value) { // Capture old value const oldValue = this.myProp; - // Implement custom setter logic + // Implement setter logic ... // Pass the old value to request an update this.requestUpdate('myProp', oldValue); } -get myProp() { ... /* Custom getter */ } +get myProp() { ... } ... // Later, set the property -this.myProp = 'hi'; // Invokes custom accessor +this.myProp = 'hi'; // Invokes your accessor ``` -If your class defines custom property accessors for a declared property directly on its prototype (i.e., not inherited from a superclass), LitElement will not overwrite them with generated accessors. Such custom setters must manually request an update, supplying the property name and its old value to the update lifecycle by calling `requestUpdate`. +If your class defines its own accessors for a property, LitElement will not overwrite them with generated accessors. If your class does not define accessors for a property, LitElement will generate them, even if a superclass has defined the property or accessors. + +The setters that LitElement generates automatically call `requestUpdate`. If you write your own setter you must call `requestUpdate` manually, supplying the property name and its old value. + +**Example: Define your own property accessors** + +```js +{% include projects/properties/customsetter/my-element.js %} +``` + +{% include project.html folder="properties/customsetter" openFile="my-element.js" %} ### Prevent LitElement from generating a property accessor {#accessors-noaccessor} -To prevent LitElement from generating property accessors, set `noAccessor` to `true` in the property declaration: +In rare cases, a subclass may need to change or add property options for a property that exists on its superclass. + +To prevent LitElement from generating a property accessor that overwrites the superclass's defined accessor, set `noAccessor` to `true` in the property declaration: ```js static get properties() { return { - // Don't generate accessors for myProp + // Don't generate accessor for myProp myProp: { type: Number, noAccessor: true } - - // Do generate accessors for aProp - aProp: { type: String } }; } ``` -In rare cases, a subclass may need to change or add property options for a custom property accessor that exists on its superclass. In these cases, setting `noAccessor` to `true` will prevent LitElement from creating a generated accessor on the subclass that overwrites the superclass's custom accessor. +**Example: Property accessors with subclassing** -**Example: Custom property accessors** +**Subclass element** ```js -{% include projects/properties/customsetter/my-element.js %} +{% include projects/properties/accessorssubclassing/sub-element.js %} ``` -{% include project.html folder="properties/customsetter" openFile="my-element.js" %} +{% include project.html folder="properties/accessorssubclassing" openFile="sub-element.js" %} ## Configure property changes diff --git a/docs/_includes/projects/properties/accessorssubclassing/index.html b/docs/_includes/projects/properties/accessorssubclassing/index.html index 205b902b..3a5498d2 100644 --- a/docs/_includes/projects/properties/accessorssubclassing/index.html +++ b/docs/_includes/projects/properties/accessorssubclassing/index.html @@ -11,7 +11,7 @@ - + diff --git a/docs/_includes/projects/properties/accessorssubclassing/index.ts b/docs/_includes/projects/properties/accessorssubclassing/index.ts index 63f0dd76..4c350674 100644 --- a/docs/_includes/projects/properties/accessorssubclassing/index.ts +++ b/docs/_includes/projects/properties/accessorssubclassing/index.ts @@ -1,2 +1,2 @@ import './super-element.js'; -import './my-element.js'; +import './sub-element.js'; diff --git a/docs/_includes/projects/properties/accessorssubclassing/manifest.json b/docs/_includes/projects/properties/accessorssubclassing/manifest.json index 6c2bc4b9..f99f3674 100644 --- a/docs/_includes/projects/properties/accessorssubclassing/manifest.json +++ b/docs/_includes/projects/properties/accessorssubclassing/manifest.json @@ -2,8 +2,8 @@ "title": "lit-element code sample", "description": "lit-element code sample", "files": [ - "my-element.js", "super-element.js", + "sub-element.js", "index.html", "index.ts" ], diff --git a/docs/_includes/projects/properties/accessorssubclassing/my-element.js b/docs/_includes/projects/properties/accessorssubclassing/my-element.js deleted file mode 100644 index c90bdda2..00000000 --- a/docs/_includes/projects/properties/accessorssubclassing/my-element.js +++ /dev/null @@ -1,16 +0,0 @@ -import SuperElement from './super-element.js'; - -class MyElement extends SuperElement { - static get properties() { return {}; }; - - get prop1() { - return this._prop1; - } - - set prop1(value) { - console.log('MyElement custom setter'); - this._prop1 = Math.floor(value/10)*2; - } -} - -customElements.define('my-element', MyElement); diff --git a/docs/_includes/projects/properties/accessorssubclassing/sub-element.js b/docs/_includes/projects/properties/accessorssubclassing/sub-element.js new file mode 100644 index 00000000..873aec61 --- /dev/null +++ b/docs/_includes/projects/properties/accessorssubclassing/sub-element.js @@ -0,0 +1,9 @@ +import { SuperElement } from './super-element.js'; + +class SubElement extends SuperElement { + static get properties() { + return { prop: { reflectToAttribute: true, noAccessor: true } }; + } +} + +customElements.define('sub-element', SubElement); diff --git a/docs/_includes/projects/properties/accessorssubclassing/super-element.js b/docs/_includes/projects/properties/accessorssubclassing/super-element.js index b2f346f2..58b30a58 100644 --- a/docs/_includes/projects/properties/accessorssubclassing/super-element.js +++ b/docs/_includes/projects/properties/accessorssubclassing/super-element.js @@ -1,37 +1,30 @@ import { LitElement, html } from 'lit-element'; export class SuperElement extends LitElement { - static get properties() { return { - prop1: { type: Number } - };} - - get prop1() { - console.log('custom getter'); - return this._prop1; + static get properties() { + return { prop: { type: Number } }; } - set prop1(value) { - console.log('custom setter'); - this._prop1 = Math.floor(value/10); + set prop(val) { + let oldVal = this._prop; + this._prop = Math.floor(val); + this.requestUpdate('prop', oldVal); } + get prop() { return this._prop; } + constructor() { super(); - this.prop1 = 0; + this._prop = 0; } render() { - return html` -

prop1: ${this.prop1}

- - `; - } - - changeProperty() { - let randy = Math.floor(Math.random()*100); - console.log('Setting to:', randy); - this.prop1 = randy; + return html` +

prop: ${this.prop}

+ + `; } } - customElements.define('super-element', SuperElement); diff --git a/docs/_includes/projects/properties/customsetter/my-element.js b/docs/_includes/projects/properties/customsetter/my-element.js index 8b042a85..74fc4077 100644 --- a/docs/_includes/projects/properties/customsetter/my-element.js +++ b/docs/_includes/projects/properties/customsetter/my-element.js @@ -1,52 +1,30 @@ import { LitElement, html } from 'lit-element'; class MyElement extends LitElement { - static get properties() { return { - prop1: { type: Number, noAccessors: true }, - prop2: { type: Number }, - prop3: { type: Number, noAccessors: true }, - };} + static get properties() { + return { prop: { type: Number } }; + } - set prop1(newVal) { this._prop1 = Math.floor(newVal); } - set prop2(newVal) { this._prop2 = Math.floor(newVal); } - set prop3(newVal) { - let oldVal = this._prop3; - this._prop3 = Math.floor(newVal); - this.requestUpdate('prop3', oldVal); + set prop(val) { + let oldVal = this._prop; + this._prop = Math.floor(val); + this.requestUpdate('prop', oldVal); } - get prop1() { return this._prop1; } - get prop2() { return this._prop2; } - get prop3() { return this._prop3; } + get prop() { return this._prop; } constructor() { super(); - this._prop1 = 0; - this._prop2 = 0; - this._prop3 = 0; + this._prop = 0; } render() { return html` -

prop1: ${this.prop1}

-

prop2: ${this.prop2}

-

prop3: ${this.prop3}

- - +

prop: ${this.prop}

+ `; } - - updated(changedProperties) { - changedProperties.forEach((oldValue, propName) => { - console.log(`${propName} changed. oldValue: ${oldValue}`); - }); - } - - getNewVal() { - let newVal = Math.random()*10; - this.prop1 = newVal; - this.prop2 = newVal; - this.prop3 = newVal; - } } customElements.define('my-element', MyElement);