Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] Update docs to reflect #454 change to remove accessor wrapping #460

Merged
8 commits merged into from
Feb 5, 2019
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
71 changes: 26 additions & 45 deletions docs/_guide/properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,78 +385,59 @@ 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:
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
set myProp(value) { ... /* Custom setter */ }
get myProp() { ... /* Custom getter */ }
set myProp(value) {
const oldValue = this.myProp;
// Implement setter logic here...
this.requestUpdate('myProp', oldValue);
}
get myProp() { ... }

...

// Later, set the property
this.myProp = 'hi'; // Invokes generated accessor, which calls custom accessor
this.myProp = 'hi'; // Invokes your accessor
```

When you create custom property accessors for a property, LitElement still generates its own accessors unless you specify otherwise ([see below](#accessors-noaccessor)). The generated setter:
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.

* Saves the previous property value.
* Calls your custom setter.
* Requests an update, supplying the property name and its old value to the update lifecycle.

### Prevent LitElement from generating a property accessor {#accessors-noaccessor}
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.

To prevent LitElement from generating property accessors, set `noAccessor` to `true` in the property declaration:
**Example**

```js
static get properties() { return {
// Don't generate accessors for myProp
myProp: { type: Number, noAccessor: true }

// Do generate accessors for aProp
aProp: { type: String }
}; }

// Create custom accessors for myProp
set myProp(value) { this._myProp = Math.floor(value); }
get myProp() { return this._myProp; }

updated(changedProperties) { ... /* no changedProperties entry for myProp */ }

...
// later...
this.myProp = Math.random()*10; // Invokes custom setter; no generated setter
this.aProp = 'hi'; // Invokes generated setter
{% include projects/properties/customsetter/my-element.js %}
```

In the example above:
### Prevent LitElement from generating a property accessor {#accessors-noaccessor}

* No update request will be made when `this.myProp = ...` is executed.
* The update requested as a result of `this.aProp = ...` will still capture `myProp`'s new value.
* The change to `myProp` won't register in the element update lifecycle.
In rare cases, a subclass may need to change or add property options for a property that exists on its superclass.

To handle update requests and property options in a custom setter, call `this.requestUpdate('propertyName', oldValue)`:
To prevent LitElement from generating a property accessor that overwrites the superclass's defined accessor, set `noAccessor` to `true` in the property declaration:

```js
set myProp(value) {
let oldValue = this._myProp;
this._myProp = Math.floor(value);
this.requestUpdate('myProp', oldValue);
}
static get properties() {
return { myProp: { type: Number, noAccessor: true } };
}
```

**Example: Custom property accessors**
You don't need to set `noAccessor` when defining your own accessors.

**Example**

**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 {#haschanged}

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, noAccessor: true },
prop2: { type: Number },
prop3: { type: Number, noAccessor: 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);