Skip to content

Commit

Permalink
fix(material/chips): aria-selected not reflecting selection state (#2…
Browse files Browse the repository at this point in the history
…5742)

When the chip listbox is in single selection mode, it needs to remove `aria-selected` from the selected option and move it to the newly-selected one. The listbox was doing this already, but change detection wasn't being triggered which meant that the DOM was out of date.
  • Loading branch information
crisbeto committed Oct 3, 2022
1 parent 9769a5a commit 17e217a
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 8 deletions.
84 changes: 76 additions & 8 deletions src/material/chips/chip-listbox.spec.ts
Expand Up @@ -5,7 +5,7 @@ import {
dispatchKeyboardEvent,
MockNgZone,
patchElementFocus,
} from '../../cdk/testing/private';
} from '@angular/cdk/testing/private';
import {
Component,
DebugElement,
Expand Down Expand Up @@ -412,11 +412,8 @@ describe('MDC-based MatChipListbox', () => {
});

describe('selection logic', () => {
beforeEach(() => {
fixture = createComponent(BasicChipListbox);
});

it('should remove selection if chip has been removed', fakeAsync(() => {
fixture = createComponent(BasicChipListbox);
const instanceChips = fixture.componentInstance.chips;
const chipListbox = fixture.componentInstance.chipListbox;
dispatchKeyboardEvent(primaryActions[0], 'keydown', SPACE);
Expand All @@ -439,6 +436,7 @@ describe('MDC-based MatChipListbox', () => {
}));

it('should select an option that was added after initialization', () => {
fixture = createComponent(BasicChipListbox);
fixture.componentInstance.foods.push({viewValue: 'Potatoes', value: 'potatoes-8'});
fixture.detectChanges();

Expand All @@ -458,6 +456,7 @@ describe('MDC-based MatChipListbox', () => {
});

it('should not select disabled chips', () => {
fixture = createComponent(BasicChipListbox);
const array = chips.toArray();
dispatchKeyboardEvent(primaryActions[2], 'keydown', SPACE);
fixture.detectChanges();
Expand All @@ -472,9 +471,6 @@ describe('MDC-based MatChipListbox', () => {
});

it('should not select when is not selectable', fakeAsync(() => {
fixture.destroy();
TestBed.resetTestingModule();

const falsyFixture = createComponent(FalsyBasicChipListbox);
falsyFixture.detectChanges();
tick();
Expand All @@ -498,6 +494,78 @@ describe('MDC-based MatChipListbox', () => {
.withContext('Expected first option not to be selected.')
.toBe(false);
}));

it('should set `aria-selected` based on the selection state in single selection mode', fakeAsync(() => {
const getAriaSelected = () =>
Array.from(primaryActions).map(action => action.getAttribute('aria-selected'));

fixture = createComponent(BasicChipListbox);
// Use a shorter list so we can keep the assertions smaller
fixture.componentInstance.foods = [
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'},
];
fixture.componentInstance.selectable = true;
fixture.detectChanges();

primaryActions = chipListboxNativeElement.querySelectorAll<HTMLElement>(
'.mdc-evolution-chip__action--primary',
);

expect(getAriaSelected()).toEqual([null, null, null]);

primaryActions[1].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual([null, 'true', null]);

primaryActions[2].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual([null, null, 'true']);

primaryActions[0].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual(['true', null, null]);
}));

it('should set `aria-selected` based on the selection state in multi-selection mode', fakeAsync(() => {
const getAriaSelected = () =>
Array.from(primaryActions).map(action => action.getAttribute('aria-selected'));

fixture = createComponent(MultiSelectionChipListbox);
fixture.detectChanges();

// Use a shorter list so we can keep the assertions smaller
fixture.componentInstance.foods = [
{value: 'steak-0', viewValue: 'Steak'},
{value: 'pizza-1', viewValue: 'Pizza'},
{value: 'tacos-2', viewValue: 'Tacos'},
];
fixture.componentInstance.selectable = true;
fixture.detectChanges();

primaryActions = chipListboxNativeElement.querySelectorAll<HTMLElement>(
'.mdc-evolution-chip__action--primary',
);

expect(getAriaSelected()).toEqual([null, null, null]);

primaryActions[1].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual([null, 'true', null]);

primaryActions[2].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual([null, 'true', 'true']);

primaryActions[0].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual(['true', 'true', 'true']);

primaryActions[1].click();
fixture.detectChanges();
expect(getAriaSelected()).toEqual(['true', null, 'true']);
}));
});

describe('chip list with chip input', () => {
Expand Down
3 changes: 3 additions & 0 deletions src/material/chips/chip-option.ts
Expand Up @@ -92,6 +92,7 @@ export class MatChipOption extends MatChip implements OnInit {
}
set selectable(value: BooleanInput) {
this._selectable = coerceBooleanProperty(value);
this._changeDetectorRef.markForCheck();
}
protected _selectable: boolean = true;

Expand Down Expand Up @@ -168,6 +169,8 @@ export class MatChipOption extends MatChip implements OnInit {
selected: this.selected,
});
}

this._changeDetectorRef.markForCheck();
}
}
}

0 comments on commit 17e217a

Please sign in to comment.