Skip to content

Commit b041f3f

Browse files
crisbetojosephperrott
authored andcommitted
fix(aria-describer): clear duplicate container coming in from the server (#11900)
1 parent e9e44f6 commit b041f3f

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

src/cdk/a11y/aria-describer/aria-describer.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,17 @@ describe('AriaDescriber', () => {
121121
const node: any = document.createComment('Not an element node');
122122
expect(() => ariaDescriber.describe(node, 'This looks like an element')).not.toThrow();
123123
});
124+
125+
it('should clear any pre-existing containers', () => {
126+
const extraContainer = document.createElement('div');
127+
extraContainer.id = MESSAGES_CONTAINER_ID;
128+
document.body.appendChild(extraContainer);
129+
130+
ariaDescriber.describe(component.element1, 'Hello');
131+
132+
// Use `querySelectorAll` with an attribute since `getElementById` will stop at the first match.
133+
expect(document.querySelectorAll(`[id='${MESSAGES_CONTAINER_ID}']`).length).toBe(1);
134+
});
124135
});
125136

126137
function getMessagesContainer() {

src/cdk/a11y/aria-describer/aria-describer.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export class AriaDescriber implements OnDestroy {
127127
messageElement.setAttribute('id', `${CDK_DESCRIBEDBY_ID_PREFIX}-${nextId++}`);
128128
messageElement.appendChild(this._document.createTextNode(message)!);
129129

130-
if (!messagesContainer) { this._createMessagesContainer(); }
130+
this._createMessagesContainer();
131131
messagesContainer!.appendChild(messageElement);
132132

133133
messageRegistry.set(message, {messageElement, referenceCount: 0});
@@ -145,11 +145,23 @@ export class AriaDescriber implements OnDestroy {
145145

146146
/** Creates the global container for all aria-describedby messages. */
147147
private _createMessagesContainer() {
148-
messagesContainer = this._document.createElement('div');
149-
messagesContainer.setAttribute('id', MESSAGES_CONTAINER_ID);
150-
messagesContainer.setAttribute('aria-hidden', 'true');
151-
messagesContainer.style.display = 'none';
152-
this._document.body.appendChild(messagesContainer);
148+
if (!messagesContainer) {
149+
const preExistingContainer = this._document.getElementById(MESSAGES_CONTAINER_ID);
150+
151+
// When going from the server to the client, we may end up in a situation where there's
152+
// already a container on the page, but we don't have a reference to it. Clear the
153+
// old container so we don't get duplicates. Doing this, instead of emptying the previous
154+
// container, should be slightly faster.
155+
if (preExistingContainer) {
156+
preExistingContainer.parentNode!.removeChild(preExistingContainer);
157+
}
158+
159+
messagesContainer = this._document.createElement('div');
160+
messagesContainer.id = MESSAGES_CONTAINER_ID;
161+
messagesContainer.setAttribute('aria-hidden', 'true');
162+
messagesContainer.style.display = 'none';
163+
this._document.body.appendChild(messagesContainer);
164+
}
153165
}
154166

155167
/** Deletes the global messages container. */

0 commit comments

Comments
 (0)