Skip to content

Commit

Permalink
fix: avoid triggering connected callback from disconnected callback (#…
Browse files Browse the repository at this point in the history
…4718)

When moving an element that extends from `DirMixin` in the DOM, the `DirMixin.disconnectedCallback` can trigger the element's `connectedCallback` before the `disconnectedCallback` has finished (currently reproducable in Chrome, FF). That can cause elements to re-run their initialization logic before their cleanup logic is finished. For example in case of the `AppLayout`, this results in the `connectedCallback` adding several event listeners again, after which the remaining logic in
`disconnectedCallback` removes them again, leaving the element in a state where the listeners are not registered. See #4682 (comment).

This change removes the `removeAttribute` call from `DirMixin.disconnectedCallback` that causes the premature reconnect, and instead introduces a flag that ensures that the element will subscribe to global dir changes again on reconnect. This also fixes a minor bug where the custom dir of an element was removed on disconnect (see test case).

Fixes: #4682
  • Loading branch information
sissbruecker authored Oct 11, 2022
1 parent 09af697 commit ca9ee25
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 10 deletions.
24 changes: 14 additions & 10 deletions packages/component-base/src/dir-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { DirHelper } from './dir-helper.js';
* Array of Vaadin custom element classes that have been subscribed to the dir changes.
*/
const directionSubscribers = [];

function directionUpdater() {
const documentDir = getDocumentDir();
directionSubscribers.forEach((element) => {
Expand Down Expand Up @@ -74,7 +75,7 @@ export const DirMixin = (superClass) =>
connectedCallback() {
super.connectedCallback();

if (!this.hasAttribute('dir')) {
if (!this.hasAttribute('dir') || this.__restoreSubscription) {
this.__subscribe();
alignDirs(this, getDocumentDir(), null);
}
Expand All @@ -100,15 +101,15 @@ export const DirMixin = (superClass) =>
this.__subscribe();
alignDirs(this, documentDir, newValue);
} else if (newDiffValue) {
this.__subscribe(false);
this.__unsubscribe();
}
}

/** @protected */
disconnectedCallback() {
super.disconnectedCallback();
this.__subscribe(false);
this.removeAttribute('dir');
this.__restoreSubscription = directionSubscribers.includes(this);
this.__unsubscribe();
}

/** @protected */
Expand All @@ -133,12 +134,15 @@ export const DirMixin = (superClass) =>
}

/** @private */
__subscribe(push = true) {
if (push) {
if (!directionSubscribers.includes(this)) {
directionSubscribers.push(this);
}
} else if (directionSubscribers.includes(this)) {
__subscribe() {
if (!directionSubscribers.includes(this)) {
directionSubscribers.push(this);
}
}

/** @private */
__unsubscribe() {
if (directionSubscribers.includes(this)) {
directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
}
}
Expand Down
9 changes: 9 additions & 0 deletions packages/component-base/test/dir-mixin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,15 @@ const runTests = (baseClass) => {
await Promise.resolve();
expect(element.getAttribute('dir')).to.eql('ltr');
});

it('should keep custom direction when disconnecting and reconnecting', async () => {
element.setAttribute('dir', 'ltr');
setDir('rtl');
await Promise.resolve();
// Disconnect + reconnect
document.body.appendChild(element);
expect(element.getAttribute('dir')).to.eql('ltr');
});
});
};

Expand Down

0 comments on commit ca9ee25

Please sign in to comment.