From 3d48334621b05a60926df2c69db51ba56bdd85a2 Mon Sep 17 00:00:00 2001 From: web-padawan Date: Thu, 28 Dec 2023 15:33:05 +0200 Subject: [PATCH 1/3] feat: add setProperties() method to PolylitMixin --- packages/component-base/src/polylit-mixin.js | 21 +++++++++ .../component-base/test/polylit-mixin.test.js | 46 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/packages/component-base/src/polylit-mixin.js b/packages/component-base/src/polylit-mixin.js index e262c4b42f..80002ed1da 100644 --- a/packages/component-base/src/polylit-mixin.js +++ b/packages/component-base/src/polylit-mixin.js @@ -93,6 +93,9 @@ const PolylitMixinImplementation = (superclass) => { let result = defaultDescriptor; + // Set the key for this property + this.getOrCreateMap('__propKeys').set(name, key); + if (options.sync) { result = { get: defaultDescriptor.get, @@ -232,6 +235,24 @@ const PolylitMixinImplementation = (superclass) => { } } + /** + * Set several properties at once and perform synchronous update. + * @protected + */ + setProperties(props) { + Object.entries(props).forEach(([name, value]) => { + // Use private key and not setter to not trigger + // update for properties marked as `sync: true`. + const key = this.constructor.__propKeys.get(name); + const oldValue = this[name]; + this[key] = value; + this.requestUpdate(name, oldValue); + }); + + // Perform sync update + this.performUpdate(); + } + /** @protected */ _createMethodObserver(observer) { const dynamicObservers = getOrCreateMap(this, '__dynamicObservers'); diff --git a/packages/component-base/test/polylit-mixin.test.js b/packages/component-base/test/polylit-mixin.test.js index 2dcdacc590..9d28b7c122 100644 --- a/packages/component-base/test/polylit-mixin.test.js +++ b/packages/component-base/test/polylit-mixin.test.js @@ -1003,4 +1003,50 @@ describe('PolylitMixin', () => { expect(element.count).to.equal(1); }); }); + + describe('setProperties()', () => { + let element; + + const tag = defineCE( + class extends PolylitMixin(LitElement) { + static get properties() { + return { + disabled: { + type: Boolean, + sync: true, + }, + + value: { + type: String, + }, + }; + } + }, + ); + + beforeEach(async () => { + element = fixtureSync(`<${tag}>`); + await element.updateComplete; + }); + + it('should set property values on the element', () => { + element.setProperties({ value: 'foo', disabled: true }); + expect(element.value).to.equal('foo'); + expect(element.disabled).to.be.true; + }); + + it('should request update for each passed property', () => { + const spy = sinon.spy(element, 'requestUpdate'); + element.setProperties({ value: 'foo', disabled: true }); + expect(spy).to.be.calledTwice; + expect(spy.firstCall.args[0]).to.equal('value'); + expect(spy.secondCall.args[0]).to.equal('disabled'); + }); + + it('should only call performUpdate() method once', () => { + const spy = sinon.spy(element, 'performUpdate'); + element.setProperties({ value: 'foo', disabled: true }); + expect(spy).to.be.calledOnce; + }); + }); }); From 5a934d82a8d202225ebb951f0a116a9d774385dc Mon Sep 17 00:00:00 2001 From: web-padawan Date: Thu, 28 Dec 2023 16:17:09 +0200 Subject: [PATCH 2/3] refactor: use key directly instead of getter --- packages/component-base/src/polylit-mixin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/component-base/src/polylit-mixin.js b/packages/component-base/src/polylit-mixin.js index 80002ed1da..a441672323 100644 --- a/packages/component-base/src/polylit-mixin.js +++ b/packages/component-base/src/polylit-mixin.js @@ -244,7 +244,7 @@ const PolylitMixinImplementation = (superclass) => { // Use private key and not setter to not trigger // update for properties marked as `sync: true`. const key = this.constructor.__propKeys.get(name); - const oldValue = this[name]; + const oldValue = this[key]; this[key] = value; this.requestUpdate(name, oldValue); }); From 6c4a4465198b9fe950d4039abf8b1361e783c8da Mon Sep 17 00:00:00 2001 From: web-padawan Date: Fri, 29 Dec 2023 10:29:17 +0200 Subject: [PATCH 3/3] fix: do not throw when calling setProperties before attach --- packages/component-base/src/polylit-mixin.js | 4 +++- packages/component-base/test/polylit-mixin.test.js | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/component-base/src/polylit-mixin.js b/packages/component-base/src/polylit-mixin.js index a441672323..01f23b4b57 100644 --- a/packages/component-base/src/polylit-mixin.js +++ b/packages/component-base/src/polylit-mixin.js @@ -250,7 +250,9 @@ const PolylitMixinImplementation = (superclass) => { }); // Perform sync update - this.performUpdate(); + if (this.hasUpdated) { + this.performUpdate(); + } } /** @protected */ diff --git a/packages/component-base/test/polylit-mixin.test.js b/packages/component-base/test/polylit-mixin.test.js index 9d28b7c122..760ab8b2db 100644 --- a/packages/component-base/test/polylit-mixin.test.js +++ b/packages/component-base/test/polylit-mixin.test.js @@ -1048,5 +1048,11 @@ describe('PolylitMixin', () => { element.setProperties({ value: 'foo', disabled: true }); expect(spy).to.be.calledOnce; }); + + it('should not throw when calling before first render', () => { + expect(() => { + document.createElement(tag).setProperties({ disabled: true }); + }).to.not.throw(Error); + }); }); });