From 9337ae181f4a8af2dc11170dd44fa6be20ec3e9b Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 9 Mar 2018 10:28:08 -0500 Subject: [PATCH] fix(chips): form field label pointing to non-existing elements (#9908) Currently when a `mat-chip-list` is inside of a form field, the label of the form field has a `for` and `aria-owns` attributes that point to a non-existing element, because the `id` from the chip list isn't being used anywhere. These changes switch it to point to the chip list input, if it has any, otherwise it'll fall back to pointing to the chip list itself. --- src/lib/chips/chip-input.spec.ts | 4 ++++ src/lib/chips/chip-input.ts | 7 +++++++ src/lib/chips/chip-list.spec.ts | 14 +++++++++++++- src/lib/chips/chip-list.ts | 13 +++++-------- 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/lib/chips/chip-input.spec.ts b/src/lib/chips/chip-input.spec.ts index 5f43c5b4e8f..ff5da838cd1 100644 --- a/src/lib/chips/chip-input.spec.ts +++ b/src/lib/chips/chip-input.spec.ts @@ -51,6 +51,10 @@ describe('MatChipInput', () => { chipInputDirective._keydown(ENTER_EVENT); expect(testChipInput.add).toHaveBeenCalled(); }); + + it('should have a default id', () => { + expect(inputNativeElement.getAttribute('id')).toBeTruthy(); + }); }); describe('[addOnBlur]', () => { diff --git a/src/lib/chips/chip-input.ts b/src/lib/chips/chip-input.ts index 7c69709a2bd..742da25102f 100644 --- a/src/lib/chips/chip-input.ts +++ b/src/lib/chips/chip-input.ts @@ -21,6 +21,9 @@ export interface MatChipInputEvent { value: string; } +// Increasing integer for generating unique ids. +let nextUniqueId = 0; + /** * Directive that adds chip-specific behaviors to an input element inside ``. * May be placed inside or outside of an ``. @@ -34,6 +37,7 @@ export interface MatChipInputEvent { '(blur)': '_blur()', '(focus)': '_focus()', '(input)': '_onInput()', + '[id]': 'id', } }) export class MatChipInput { @@ -73,6 +77,9 @@ export class MatChipInput { /** The input's placeholder text. */ @Input() placeholder: string = ''; + /** Unique id for the input. */ + @Input() id: string = `mat-chip-list-input-${nextUniqueId++}`; + /** Whether the input is empty. */ get empty(): boolean { return !this._inputElement.value; } diff --git a/src/lib/chips/chip-list.spec.ts b/src/lib/chips/chip-list.spec.ts index 1e3d1e9339e..f2a6129d166 100644 --- a/src/lib/chips/chip-list.spec.ts +++ b/src/lib/chips/chip-list.spec.ts @@ -377,6 +377,17 @@ describe('MatChipList', () => { subscription.unsubscribe(); }); + it('should point the label id to the chip input', () => { + const label = fixture.nativeElement.querySelector('label'); + const input = fixture.nativeElement.querySelector('input'); + + fixture.detectChanges(); + + expect(label.getAttribute('for')).toBeTruthy(); + expect(label.getAttribute('for')).toBe(input.getAttribute('id')); + expect(label.getAttribute('aria-owns')).toBe(input.getAttribute('id')); + }); + }); describe('selection logic', () => { @@ -1054,12 +1065,13 @@ class StandardChipList { @Component({ template: ` + Add a chip Chip 1 Chip 1 Chip 1 - + ` }) diff --git a/src/lib/chips/chip-list.ts b/src/lib/chips/chip-list.ts index 13cd2f7a0e6..3a38efc1410 100644 --- a/src/lib/chips/chip-list.ts +++ b/src/lib/chips/chip-list.ts @@ -87,7 +87,8 @@ export class MatChipListChange { 'class': 'mat-chip-list', '(focus)': 'focus()', '(blur)': '_blur()', - '(keydown)': '_keydown($event)' + '(keydown)': '_keydown($event)', + '[id]': '_uid', }, providers: [{provide: MatFormFieldControl, useExisting: MatChipList}], styleUrls: ['chips.css'], @@ -130,7 +131,7 @@ export class MatChipList extends _MatChipListMixinBase implements MatFormFieldCo protected _chipInput: MatChipInput; /** Uid of the chip list */ - protected _uid: string = `mat-chip-list-${nextUniqueId++}`; + _uid: string = `mat-chip-list-${nextUniqueId++}`; /** The aria-describedby attribute on the chip list for improved a11y. */ _ariaDescribedby: string; @@ -206,13 +207,9 @@ export class MatChipList extends _MatChipListMixinBase implements MatFormFieldCo * Implemented as part of MatFormFieldControl. * @docs-private */ - @Input() - get id(): string { return this._id || this._uid; } - set id(value: string) { - this._id = value; - this.stateChanges.next(); + get id(): string { + return this._chipInput ? this._chipInput.id : this._uid; } - protected _id: string; /** * Implemented as part of MatFormFieldControl.