Skip to content

Commit 314b182

Browse files
authored
refactor: add optional random infix to generated id (#32173)
1 parent d5e7344 commit 314b182

File tree

10 files changed

+19
-16
lines changed

10 files changed

+19
-16
lines changed

goldens/cdk/a11y/index.api.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ export interface Highlightable extends ListKeyManagerOption {
295295

296296
// @public
297297
export class _IdGenerator {
298-
getId(prefix: string): string;
298+
getId(prefix: string, randomize?: boolean): string;
299299
// (undocumented)
300300
static ɵfac: i0.ɵɵFactoryDeclaration<_IdGenerator, never>;
301301
// (undocumented)

src/aria/accordion/accordion.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ export class AccordionPanel {
5454
private readonly _deferredContentAware = inject(DeferredContentAware);
5555

5656
/** A global unique identifier for the panel. */
57-
private readonly _id = inject(_IdGenerator).getId('accordion-trigger-');
57+
private readonly _id = inject(_IdGenerator).getId('accordion-trigger-', true);
5858

5959
/** A local unique identifier for the panel, used to match with its trigger's value. */
6060
value = input.required<string>();
@@ -102,7 +102,7 @@ export class AccordionPanel {
102102
})
103103
export class AccordionTrigger {
104104
/** A global unique identifier for the trigger. */
105-
private readonly _id = inject(_IdGenerator).getId('ng-accordion-trigger-');
105+
private readonly _id = inject(_IdGenerator).getId('ng-accordion-trigger-', true);
106106

107107
/** A reference to the trigger element. */
108108
private readonly _elementRef = inject(ElementRef);

src/aria/grid/grid.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ export class GridCell {
184184
private readonly _row = inject(GridRow);
185185

186186
/** A unique identifier for the cell. */
187-
private readonly _id = inject(_IdGenerator).getId('ng-grid-cell-');
187+
private readonly _id = inject(_IdGenerator).getId('ng-grid-cell-', true);
188188

189189
/** The host native element. */
190190
readonly element = computed(() => this._elementRef.nativeElement);

src/aria/listbox/listbox.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ import {ComboboxPopup} from '../combobox';
6060
})
6161
export class Listbox<V> {
6262
/** A unique identifier for the listbox. */
63-
private readonly _generatedId = inject(_IdGenerator).getId('ng-listbox-');
63+
private readonly _generatedId = inject(_IdGenerator).getId('ng-listbox-', true);
6464

6565
// TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144.
6666
/** A unique identifier for the listbox. */
@@ -211,7 +211,7 @@ export class Option<V> {
211211
private readonly _listbox = inject(Listbox);
212212

213213
/** A unique identifier for the option. */
214-
private readonly _generatedId = inject(_IdGenerator).getId('ng-option-');
214+
private readonly _generatedId = inject(_IdGenerator).getId('ng-option-', true);
215215

216216
// TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144.
217217
/** A unique identifier for the option. */

src/aria/menu/menu.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
MenuPattern,
2828
MenuTriggerPattern,
2929
} from '@angular/aria/private';
30+
import {_IdGenerator} from '@angular/cdk/a11y';
3031
import {toSignal} from '@angular/core/rxjs-interop';
3132
import {Directionality} from '@angular/cdk/bidi';
3233

@@ -132,7 +133,7 @@ export class Menu<V> {
132133
readonly submenu = input<Menu<V> | undefined>(undefined);
133134

134135
/** The unique ID of the menu. */
135-
readonly id = input<string>(Math.random().toString(36).substring(2, 10));
136+
readonly id = input<string>(inject(_IdGenerator).getId('ng-menu-', true));
136137

137138
/** Whether the menu should wrap its items. */
138139
readonly wrap = input<boolean>(true);
@@ -325,7 +326,7 @@ export class MenuItem<V> {
325326
readonly element: HTMLElement = this._elementRef.nativeElement;
326327

327328
/** The unique ID of the menu item. */
328-
readonly id = input<string>(Math.random().toString(36).substring(2, 10));
329+
readonly id = input<string>(inject(_IdGenerator).getId('ng-menu-item-', true));
329330

330331
/** The value of the menu item. */
331332
readonly value = input.required<V>();

src/aria/radio-group/radio-group.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export class RadioButton<V> {
221221
private readonly _radioGroup = inject(RadioGroup);
222222

223223
/** A unique identifier for the radio button. */
224-
private readonly _generatedId = inject(_IdGenerator).getId('ng-radio-button-');
224+
private readonly _generatedId = inject(_IdGenerator).getId('ng-radio-button-', true);
225225

226226
/** A unique identifier for the radio button. */
227227
readonly id = computed(() => this._generatedId);

src/aria/tabs/tabs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ export class TabPanel implements OnInit, OnDestroy {
315315
private readonly _Tabs = inject(Tabs);
316316

317317
/** A global unique identifier for the tab. */
318-
private readonly _id = inject(_IdGenerator).getId('ng-tabpanel-');
318+
private readonly _id = inject(_IdGenerator).getId('ng-tabpanel-', true);
319319

320320
/** The Tab UIPattern associated with the tabpanel */
321321
readonly tab = computed(() => this._Tabs.tabs()?.find(tab => tab.value() === this.value()));

src/aria/toolbar/toolbar.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export class ToolbarWidget<V> implements OnInit, OnDestroy {
185185
private readonly _toolbar = inject(Toolbar);
186186

187187
/** A unique identifier for the widget. */
188-
private readonly _generatedId = inject(_IdGenerator).getId('ng-toolbar-widget-');
188+
private readonly _generatedId = inject(_IdGenerator).getId('ng-toolbar-widget-', true);
189189

190190
/** A unique identifier for the widget. */
191191
readonly id = computed(() => this._generatedId);
@@ -236,7 +236,7 @@ export class ToolbarWidgetGroup<V> implements OnInit, OnDestroy {
236236
private readonly _toolbar = inject(Toolbar, {optional: true});
237237

238238
/** A unique identifier for the widget. */
239-
private readonly _generatedId = inject(_IdGenerator).getId('ng-toolbar-widget-group-');
239+
private readonly _generatedId = inject(_IdGenerator).getId('ng-toolbar-widget-group-', true);
240240

241241
/** A unique identifier for the widget. */
242242
readonly id = computed(() => this._generatedId);

src/aria/tree/tree.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ function sortDirectives(a: HasElement, b: HasElement) {
8282
})
8383
export class Tree<V> {
8484
/** A unique identifier for the tree. */
85-
private readonly _generatedId = inject(_IdGenerator).getId('ng-tree-');
85+
private readonly _generatedId = inject(_IdGenerator).getId('ng-tree-', true);
8686

8787
// TODO(wagnermaciel): https://github.com/angular/components/pull/30495#discussion_r1972601144.
8888
/** A unique identifier for the tree. */
@@ -233,7 +233,7 @@ export class TreeItem<V> extends DeferredContentAware implements OnInit, OnDestr
233233
private readonly _elementRef = inject(ElementRef);
234234

235235
/** A unique identifier for the tree item. */
236-
private readonly _id = inject(_IdGenerator).getId('ng-tree-item-');
236+
private readonly _id = inject(_IdGenerator).getId('ng-tree-item-', true);
237237

238238
/** The owned tree item group. */
239239
private readonly _group = signal<TreeItemGroup<V> | undefined>(undefined);

src/cdk/a11y/id-generator.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ const counters: Record<string, number> = {};
1919
@Injectable({providedIn: 'root'})
2020
export class _IdGenerator {
2121
private _appId = inject(APP_ID);
22+
private static _infix = `a${Math.floor(Math.random() * 100000).toString()}`;
2223

2324
/**
2425
* Generates a unique ID with a specific prefix.
2526
* @param prefix Prefix to add to the ID.
27+
* @param randomize Add a randomized infix string.
2628
*/
27-
getId(prefix: string): string {
29+
getId(prefix: string, randomize: boolean = false): string {
2830
// Omit the app ID if it's the default `ng`. Since the vast majority of pages have one
2931
// Angular app on them, we can reduce the amount of breakages by not adding it.
3032
if (this._appId !== 'ng') {
@@ -35,6 +37,6 @@ export class _IdGenerator {
3537
counters[prefix] = 0;
3638
}
3739

38-
return `${prefix}${counters[prefix]++}`;
40+
return `${prefix}${randomize ? _IdGenerator._infix + '-' : ''}${counters[prefix]++}`;
3941
}
4042
}

0 commit comments

Comments
 (0)