Description
Problem
Many of our bugs are related to people believing that the initialization value is a default value.
@component('filter')
export class Filter extends LitElement {
@property({ type: Number })
min: number = -Infinity;
@property({ type: Number })
max: number = Infinity;
@property({ type: Number })
decimals: number = 0;
...
onSelectorChanged (e: CustomEvent) {
const value = e.detail.value;
// Everyone expects min and max to be defined numbers, never to be undefined
// But when it is undefined, all hell breaks loose
if (value < this.min || value > this.max) {
...
}
this.value = value;
}
}
So they write code, that works. But it is very ugly and repetitive.
get _max () {
return this.max !== undefined ? this.max : Infinity;
}
get _min () {
return this.min !== undefined ? this.min : -Infinity;
}
onSelectorChanged (e: CustomEvent) {
const value = e.detail.value;
if (value < this._min || value > this._max) {
...
}
this.value = value;
}
Why are so many variables set as undefined
despite having an initialization value? Because of abstractions. Let's say we have a filters
property with many dynamic filters to be rendered.
get filtersTemplate () {
return this.filters.map(filter => {
return html`<filter
.min="${filter.min}"
.max="${filter.max}"
.decimals="${filter.decimals}" >
</filter>`
});
}
Any filter property that is undefined will override the initialization value of our filter
component. The following syntax would be great, but it's not legal.
// This wil throw
html`<filter ${ filter.min !== undefined ? 'min="${filter.min}"' : ''}"></filter>`
Proposal
We use a patched version of lit-element that allows the following syntax.
@component('filter')
export class Filter extends LitElement {
@property({ type: Number, default: () => -Infinity })
min: number;
@property({ type: Number, default: () => Infinity })
max: number;
@property({ type: Number, default: () => ({ foo: 'bar' }) })
extraData: number;
...
onSelectorChanged (e: CustomEvent) {
const value = e.detail.value;
// Works as expected
if (value < this.min || value > this.max) {
...
}
this.value = value;
}
}
Whenever a property would become undefined
, the value is overridden with the default value.
Take a look at branch default_values in my repo.
I've also opened this pull request to discuss implementation details #906