Skip to content

Commit d5e20c6

Browse files
authored
fix: ensure ready() is called after observers (#8254)
1 parent 642a050 commit d5e20c6

File tree

7 files changed

+87
-42
lines changed

7 files changed

+87
-42
lines changed

packages/component-base/src/polylit-mixin.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ const PolylitMixinImplementation = (superclass) => {
213213

214214
/** @protected */
215215
updated(props) {
216+
const wasReadyInvoked = this.__isReadyInvoked;
217+
this.__isReadyInvoked = true;
218+
216219
if (this.constructor.__observers) {
217220
this.__runObservers(props, this.constructor.__observers);
218221
}
@@ -233,8 +236,7 @@ const PolylitMixinImplementation = (superclass) => {
233236
this.__runNotifyProps(props, this.constructor.__notifyProps);
234237
}
235238

236-
if (!this.__isReadyInvoked) {
237-
this.__isReadyInvoked = true;
239+
if (!wasReadyInvoked) {
238240
this.ready();
239241
}
240242
}

packages/component-base/test/polylit-mixin.test.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,79 @@ describe('PolylitMixin', () => {
10691069
});
10701070
});
10711071

1072+
describe('sync observers', () => {
1073+
let element;
1074+
const readySpy = sinon.spy();
1075+
const openedChangedSpy = sinon.spy();
1076+
const headerChangedSpy = sinon.spy();
1077+
const contentChangedSpy = sinon.spy();
1078+
1079+
const tag = defineCE(
1080+
class extends PolylitMixin(LitElement) {
1081+
static get properties() {
1082+
return {
1083+
opened: {
1084+
type: Boolean,
1085+
sync: true,
1086+
},
1087+
1088+
header: {
1089+
type: String,
1090+
sync: true,
1091+
},
1092+
1093+
content: {
1094+
type: String,
1095+
sync: true,
1096+
},
1097+
};
1098+
}
1099+
1100+
static get observers() {
1101+
return ['openedChanged(opened)', 'headerChanged(opened, header)', 'contentChanged(opened, content)'];
1102+
}
1103+
1104+
ready() {
1105+
super.ready();
1106+
readySpy();
1107+
}
1108+
1109+
openedChanged(opened) {
1110+
openedChangedSpy();
1111+
1112+
if (opened) {
1113+
this.header = 'Header';
1114+
this.content = 'Content';
1115+
}
1116+
}
1117+
1118+
headerChanged(_opened, _header) {
1119+
headerChangedSpy();
1120+
}
1121+
1122+
contentChanged(_opened, _content) {
1123+
contentChangedSpy();
1124+
}
1125+
},
1126+
);
1127+
1128+
beforeEach(async () => {
1129+
element = fixtureSync(`<${tag} opened></${tag}>`);
1130+
await element.updateComplete;
1131+
});
1132+
1133+
it('should call ready after observers during initialization', () => {
1134+
expect(openedChangedSpy).to.be.calledOnce;
1135+
expect(headerChangedSpy).to.be.calledTwice;
1136+
expect(contentChangedSpy).to.be.calledTwice;
1137+
1138+
expect(readySpy).to.be.calledOnce;
1139+
expect(readySpy).to.be.calledAfter(openedChangedSpy);
1140+
expect(readySpy).to.be.calledAfter(headerChangedSpy);
1141+
expect(readySpy).to.be.calledAfter(contentChangedSpy);
1142+
});
1143+
});
1144+
10721145
describe('setProperties()', () => {
10731146
let element;
10741147

packages/date-picker/src/vaadin-lit-date-picker.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ class DatePicker extends DatePickerMixin(InputControlMixin(ThemableMixin(Element
109109
}
110110

111111
/** @protected */
112-
firstUpdated() {
113-
super.firstUpdated();
112+
ready() {
113+
super.ready();
114114

115115
this.addController(
116116
new InputController(this, (input) => {

packages/number-field/src/vaadin-lit-number-field.js

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import { html, LitElement } from 'lit';
88
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
99
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
1010
import { PolylitMixin } from '@vaadin/component-base/src/polylit-mixin.js';
11-
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
1211
import { inputFieldShared } from '@vaadin/field-base/src/styles/input-field-shared-styles.js';
1312
import { ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
1413
import { NumberFieldMixin } from './vaadin-number-field-mixin.js';
@@ -84,30 +83,6 @@ class NumberField extends NumberFieldMixin(ThemableMixin(ElementMixin(PolylitMix
8483
<slot name="tooltip"></slot>
8584
`;
8685
}
87-
88-
/** @protected */
89-
ready() {
90-
super.ready();
91-
92-
this._tooltipController = new TooltipController(this);
93-
this.addController(this._tooltipController);
94-
this._tooltipController.setPosition('top');
95-
this._tooltipController.setAriaTarget(this.inputElement);
96-
}
97-
98-
/**
99-
* Override method from `InputConstraintsMixin`
100-
* to create observer after the initial update
101-
* and preserve invalid state set as attribute.
102-
*
103-
* @protected
104-
* @override
105-
*/
106-
async _createConstraintsObserver() {
107-
await this.updateComplete;
108-
109-
super._createConstraintsObserver();
110-
}
11186
}
11287

11388
defineCustomElement(NumberField);

packages/number-field/src/vaadin-number-field-mixin.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
55
*/
66
import { getDeepActiveElement } from '@vaadin/a11y-base/src/focus-utils.js';
7+
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller';
78
import { InputController } from '@vaadin/field-base/src/input-controller.js';
89
import { InputFieldMixin } from '@vaadin/field-base/src/input-field-mixin.js';
910
import { LabelledInputController } from '@vaadin/field-base/src/labelled-input-controller.js';
@@ -127,6 +128,11 @@ export const NumberFieldMixin = (superClass) =>
127128
);
128129

129130
this.addController(new LabelledInputController(this.inputElement, this._labelController));
131+
132+
this._tooltipController = new TooltipController(this);
133+
this.addController(this._tooltipController);
134+
this._tooltipController.setPosition('top');
135+
this._tooltipController.setAriaTarget(this.inputElement);
130136
}
131137

132138
/**

packages/number-field/src/vaadin-number-field.js

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import '@vaadin/input-container/src/vaadin-input-container.js';
77
import { html, PolymerElement } from '@polymer/polymer';
88
import { defineCustomElement } from '@vaadin/component-base/src/define.js';
99
import { ElementMixin } from '@vaadin/component-base/src/element-mixin.js';
10-
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
1110
import { inputFieldShared } from '@vaadin/field-base/src/styles/input-field-shared-styles.js';
1211
import { registerStyles, ThemableMixin } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
1312
import { NumberFieldMixin } from './vaadin-number-field-mixin.js';
@@ -128,16 +127,6 @@ export class NumberField extends NumberFieldMixin(ThemableMixin(ElementMixin(Pol
128127
<slot name="tooltip"></slot>
129128
`;
130129
}
131-
132-
/** @protected */
133-
ready() {
134-
super.ready();
135-
136-
this._tooltipController = new TooltipController(this);
137-
this.addController(this._tooltipController);
138-
this._tooltipController.setPosition('top');
139-
this._tooltipController.setAriaTarget(this.inputElement);
140-
}
141130
}
142131

143132
defineCustomElement(NumberField);

packages/time-picker/src/vaadin-lit-time-picker.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ class TimePicker extends TimePickerMixin(ThemableMixin(ElementMixin(PolylitMixin
115115
}
116116

117117
/** @protected */
118-
firstUpdated() {
119-
super.firstUpdated();
118+
ready() {
119+
super.ready();
120120

121121
this.addController(
122122
new InputController(

0 commit comments

Comments
 (0)