diff --git a/src/material/chips/chip-list.spec.ts b/src/material/chips/chip-list.spec.ts index 5d553eb865b9..3dc926178c84 100644 --- a/src/material/chips/chip-list.spec.ts +++ b/src/material/chips/chip-list.spec.ts @@ -29,6 +29,7 @@ import { Type, ViewChild, ViewChildren, + ChangeDetectionStrategy, } from '@angular/core'; import {ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing'; import {FormControl, FormsModule, NgForm, ReactiveFormsModule, Validators} from '@angular/forms'; @@ -1270,6 +1271,16 @@ describe('MatChipList', () => { }); }); + it('should preselected chip as selected inside an OnPush component', fakeAsync(() => { + fixture = createComponent(PreselectedChipInsideOnPush); + fixture.detectChanges(); + tick(); + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.mat-chip').classList) + .toContain('mat-chip-selected', 'Expected first chip to be selected.'); + })); + function createComponent(component: Type, providers: Provider[] = [], animationsModule: Type | Type = NoopAnimationsModule): ComponentFixture { @@ -1607,3 +1618,19 @@ class ChipListWithRemove { this.chips.splice(event.chip.value, 1); } } + + +@Component({ + template: ` + + + Pizza + Pasta + + + `, + changeDetection: ChangeDetectionStrategy.OnPush +}) +class PreselectedChipInsideOnPush { + control = new FormControl('Pizza'); +} diff --git a/src/material/chips/chip.ts b/src/material/chips/chip.ts index 3b857e573697..527156456f2a 100644 --- a/src/material/chips/chip.ts +++ b/src/material/chips/chip.ts @@ -22,6 +22,7 @@ import { OnDestroy, Optional, Output, + ChangeDetectorRef, } from '@angular/core'; import { CanColor, @@ -235,7 +236,9 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes @Optional() @Inject(MAT_RIPPLE_GLOBAL_OPTIONS) globalRippleOptions: RippleGlobalOptions | null, // @breaking-change 8.0.0 `animationMode` parameter to become required. - @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string) { + @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode?: string, + // @breaking-change 9.0.0 `_changeDetectorRef` parameter to become required. + private _changeDetectorRef?: ChangeDetectorRef) { super(_elementRef); this._addHostClassName(); @@ -269,6 +272,7 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes if (!this._selected) { this._selected = true; this._dispatchSelectionChange(); + this._markForCheck(); } } @@ -277,6 +281,7 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes if (this._selected) { this._selected = false; this._dispatchSelectionChange(); + this._markForCheck(); } } @@ -285,6 +290,7 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes if (!this._selected) { this._selected = true; this._dispatchSelectionChange(true); + this._markForCheck(); } } @@ -292,6 +298,7 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes toggleSelected(isUserInput: boolean = false): boolean { this._selected = !this.selected; this._dispatchSelectionChange(isUserInput); + this._markForCheck(); return this.selected; } @@ -374,6 +381,13 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes selected: this._selected }); } + + private _markForCheck() { + // @breaking-change 9.0.0 Remove this method once the _changeDetectorRef is a required param. + if (this._changeDetectorRef) { + this._changeDetectorRef.markForCheck(); + } + } } diff --git a/tools/public_api_guard/material/chips.d.ts b/tools/public_api_guard/material/chips.d.ts index 5b103368cc5e..6aa2f7715c90 100644 --- a/tools/public_api_guard/material/chips.d.ts +++ b/tools/public_api_guard/material/chips.d.ts @@ -25,7 +25,7 @@ export declare class MatChip extends _MatChipMixinBase implements FocusableOptio readonly selectionChange: EventEmitter; trailingIcon: MatChipTrailingIcon; value: any; - constructor(_elementRef: ElementRef, _ngZone: NgZone, platform: Platform, globalRippleOptions: RippleGlobalOptions | null, animationMode?: string); + constructor(_elementRef: ElementRef, _ngZone: NgZone, platform: Platform, globalRippleOptions: RippleGlobalOptions | null, animationMode?: string, _changeDetectorRef?: ChangeDetectorRef | undefined); _addHostClassName(): void; _blur(): void; _handleClick(event: Event): void;