Skip to content

Commit

Permalink
Initializers are copied but separate from superclass initializers (#3374
Browse files Browse the repository at this point in the history
)

Initializers are copied but separate from superclass initializers, fixes #/3373.
  • Loading branch information
Steve Orvell committed Oct 23, 2022
1 parent 7d7fc85 commit bb09895
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-olives-fetch.md
@@ -0,0 +1,5 @@
---
'@lit/reactive-element': patch
---

Initializers added to subclasses are no longer improperly added to superclass.
10 changes: 8 additions & 2 deletions packages/reactive-element/src/reactive-element.ts
Expand Up @@ -490,8 +490,8 @@ export abstract class ReactiveElement
* @nocollapse
*/
static addInitializer(initializer: Initializer) {
this._initializers ??= [];
this._initializers.push(initializer);
this.finalize();
(this._initializers ??= []).push(initializer);
}

static _initializers?: Initializer[];
Expand Down Expand Up @@ -762,6 +762,12 @@ export abstract class ReactiveElement
// finalize any superclasses
const superCtor = Object.getPrototypeOf(this) as typeof ReactiveElement;
superCtor.finalize();
// Create own set of initializers for this class if any exist on the
// superclass and copy them down. Note, for a small perf boost, avoid
// creating initializers unless needed.
if (superCtor._initializers !== undefined) {
this._initializers = [...superCtor._initializers];
}
this.elementProperties = new Map(superCtor.elementProperties);
// initialize Map populated in observedAttributes
this.__attributeToPropertyMap = new Map();
Expand Down
57 changes: 42 additions & 15 deletions packages/reactive-element/src/test/reactive-element_test.ts
Expand Up @@ -2550,28 +2550,55 @@ suite('ReactiveElement', () => {
assert.equal(a.getAttribute('bar'), 'yo');
});

test('addInitializer', () => {
class A extends ReactiveElement {
suite('initializers', () => {
class Base extends ReactiveElement {
prop1?: string;
prop2?: string;
event?: string;
}
A.addInitializer((a) => {
(a as A).prop1 = 'prop1';
Base.addInitializer((a) => {
(a as Base).prop1 = 'prop1';
});
A.addInitializer((a) => {
(a as A).prop2 = 'prop2';
Base.addInitializer((a) => {
(a as Base).prop2 = 'prop2';
});
A.addInitializer((a) => {
a.addEventListener('click', (e) => ((a as A).event = e.type));
Base.addInitializer((a) => {
a.addEventListener('click', (e) => ((a as Base).event = e.type));
});
customElements.define(generateElementName(), Base);

test('addInitializer', () => {
const a = new Base();
container.appendChild(a);
assert.equal(a.prop1, 'prop1');
assert.equal(a.prop2, 'prop2');
a.dispatchEvent(new Event('click'));
assert.equal(a.event, 'click');
});

class Sub extends Base {
prop3?: string;
}
Sub.addInitializer((a) => {
(a as Sub).prop3 = 'prop3';
});
customElements.define(generateElementName(), Sub);

test('addInitializer on subclass', () => {
const s = new Sub();
container.appendChild(s);
assert.equal(s.prop1, 'prop1');
assert.equal(s.prop2, 'prop2');
assert.equal(s.prop3, 'prop3');
s.dispatchEvent(new Event('click'));
assert.equal(s.event, 'click');
});

test('addInitializer on subclass independent from superclass', () => {
const b = new Base();
container.appendChild(b);
assert.notOk((b as any).prop3);
});
customElements.define(generateElementName(), A);
const a = new A();
container.appendChild(a);
assert.equal(a.prop1, 'prop1');
assert.equal(a.prop2, 'prop2');
a.dispatchEvent(new Event('click'));
assert.equal(a.event, 'click');
});

suite('exceptions', () => {
Expand Down

0 comments on commit bb09895

Please sign in to comment.