Skip to content

Commit 5e4ece4

Browse files
author
Steven Orvell
committed
Fixes #965
It is now possible to set a computed reflecting property in another property's setter as long as `requestUpdate` is called before setting the computed property. Note, this does require a slightly user code modification to address #965 but it addresses the use case without degrading performance by adding per-property tracking (which is the other alternative).
1 parent bcd500a commit 5e4ece4

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

src/lib/updating-element.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,8 @@ export abstract class UpdatingElement extends HTMLElement {
657657
let shouldRequestUpdate = true;
658658
// If we have a property key, perform property update steps.
659659
if (name !== undefined) {
660+
const isReflectingToProperty = this._updateState & STATE_IS_REFLECTING_TO_PROPERTY;
661+
this._updateState = this._updateState & ~STATE_IS_REFLECTING_TO_PROPERTY;
660662
const ctor = this.constructor as typeof UpdatingElement;
661663
const options = ctor.getPropertyOptions(name);
662664
if (ctor._valueHasChanged(
@@ -668,8 +670,7 @@ export abstract class UpdatingElement extends HTMLElement {
668670
// Note, it's important that every change has a chance to add the
669671
// property to `_reflectingProperties`. This ensures setting
670672
// attribute + property reflects correctly.
671-
if (options.reflect === true &&
672-
!(this._updateState & STATE_IS_REFLECTING_TO_PROPERTY)) {
673+
if (options.reflect === true && !isReflectingToProperty) {
673674
if (this._reflectingProperties === undefined) {
674675
this._reflectingProperties = new Map();
675676
}

src/test/lib/updating-element_test.ts

+49
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,55 @@ suite('UpdatingElement', () => {
460460
assert.equal(el.getAttribute('obj'), '{"obj":3}');
461461
});
462462

463+
464+
test('set an attribute that reflects to a property which has a setter that computes another reflecting property', async () => {
465+
class E extends UpdatingElement {
466+
static get properties() {
467+
return {
468+
a: {type: Boolean},
469+
b: {type: Number, reflect: true}
470+
};
471+
}
472+
473+
_a: boolean;
474+
b: number;
475+
476+
constructor() {
477+
super();
478+
this._a = false;
479+
this.b = 0;
480+
}
481+
482+
get a() {
483+
return this._a;
484+
}
485+
486+
set a(value: boolean) {
487+
const oldValue = this.a;
488+
this._a = value;
489+
this.requestUpdate('a', oldValue);
490+
this.b += 1;
491+
}
492+
}
493+
const name = generateElementName();
494+
customElements.define(name, E);
495+
const el = new E();
496+
container.appendChild(el);
497+
await el.updateComplete;
498+
assert.equal(el.getAttribute('b'), '0');
499+
el.a = true;
500+
await el.updateComplete;
501+
assert.equal(el.getAttribute('b'), '1');
502+
el.a = false;
503+
el.a = true;
504+
el.a = false;
505+
await el.updateComplete;
506+
assert.equal(el.getAttribute('b'), '4');
507+
el.setAttribute('a', '');
508+
await el.updateComplete;
509+
assert.equal(el.getAttribute('b'), '5');
510+
});
511+
463512
test('property options via decorator', async () => {
464513
const hasChanged = (value: any, old: any) =>
465514
old === undefined || value > old;

0 commit comments

Comments
 (0)