Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions docs/_guide/properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</head>

<body>
<my-element></my-element>
<sub-element prop="6.2344235"></sub-element>
</body>

</html>
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import './super-element.js';
import './my-element.js';
import './sub-element.js';
Original file line number Diff line number Diff line change
Expand Up @@ -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"
],
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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);
Original file line number Diff line number Diff line change
@@ -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`
<p>prop1: ${this.prop1}</p>
<button @click="${this.changeProperty}">change property</button>
`;
}

changeProperty() {
let randy = Math.floor(Math.random()*100);
console.log('Setting to:', randy);
this.prop1 = randy;
return html`
<p>prop: ${this.prop}</p>
<button @click="${() => { this.prop = Math.random()*10; }}">
change prop
</button>
`;
}
}

customElements.define('super-element', SuperElement);
48 changes: 13 additions & 35 deletions docs/_includes/projects/properties/customsetter/my-element.js
Original file line number Diff line number Diff line change
@@ -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`
<p>prop1: ${this.prop1}</p>
<p>prop2: ${this.prop2}</p>
<p>prop3: ${this.prop3}</p>

<button @click="${this.getNewVal}">change properties</button>
<p>prop: ${this.prop}</p>
<button @click="${() => { this.prop = Math.random()*10; }}">
change prop
</button>
`;
}

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);