Skip to content

Commit

Permalink
refactor(material/chips): remove TypeScript mixin usages
Browse files Browse the repository at this point in the history
Replaces the final TypeScript mixin used by `MatChipGrid` with an internal class.
  • Loading branch information
crisbeto committed Nov 18, 2023
1 parent 528e636 commit 00e076e
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 57 deletions.
93 changes: 41 additions & 52 deletions src/material/chips/chip-grid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
NgForm,
Validators,
} from '@angular/forms';
import {CanUpdateErrorState, ErrorStateMatcher, mixinErrorState} from '@angular/material/core';
import {ErrorStateMatcher, _ErrorStateTracker} from '@angular/material/core';
import {MatFormFieldControl} from '@angular/material/form-field';
import {MatChipTextControl} from './chip-text-control';
import {Observable, Subject, merge} from 'rxjs';
Expand All @@ -53,44 +53,6 @@ export class MatChipGridChange {
) {}
}

/**
* Boilerplate for applying mixins to MatChipGrid.
* Important! this class needs to be marked as a component or a directive, because
* leaving it without metadata cuases the framework to execute the host bindings multiple
* times which breaks the keyboard navigation. We can't use `@Directive()` here, because
* `MatChipSet` is a component. We should able to remove this class altogether once
* the error state is moved away from using mixins.
* @docs-private
*/
// tslint:disable-next-line:validate-decorators
@Component({template: ''})
class MatChipGridBase extends MatChipSet {
/**
* Emits whenever the component state changes and should cause the parent
* form-field to update. Implemented as part of `MatFormFieldControl`.
* @docs-private
*/
readonly stateChanges = new Subject<void>();

constructor(
elementRef: ElementRef,
changeDetectorRef: ChangeDetectorRef,
dir: Directionality,
public _defaultErrorStateMatcher: ErrorStateMatcher,
public _parentForm: NgForm,
public _parentFormGroup: FormGroupDirective,
/**
* Form control bound to the component.
* Implemented as part of `MatFormFieldControl`.
* @docs-private
*/
public ngControl: NgControl,
) {
super(elementRef, changeDetectorRef, dir);
}
}
const _MatChipGridMixinBase = mixinErrorState(MatChipGridBase);

/**
* An extension of the MatChipSet component used with MatChipRow chips and
* the matChipInputFor directive.
Expand Down Expand Up @@ -120,11 +82,10 @@ const _MatChipGridMixinBase = mixinErrorState(MatChipGridBase);
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MatChipGrid
extends _MatChipGridMixinBase
extends MatChipSet
implements
AfterContentInit,
AfterViewInit,
CanUpdateErrorState,
ControlValueAccessor,
DoCheck,
MatFormFieldControl<any>,
Expand All @@ -140,6 +101,7 @@ export class MatChipGrid
protected _chipInput: MatChipTextControl;

protected override _defaultRole = 'grid';
private _errorStateTracker: _ErrorStateTracker;

/**
* List of element ids to propagate to the chipInput's aria-describedby attribute.
Expand Down Expand Up @@ -244,7 +206,13 @@ export class MatChipGrid
protected _value: any[] = [];

/** An object used to control when error messages are shown. */
@Input() override errorStateMatcher: ErrorStateMatcher;
@Input()
get errorStateMatcher() {
return this._errorStateTracker.matcher;
}
set errorStateMatcher(value: ErrorStateMatcher) {
this._errorStateTracker.matcher = value;
}

/** Combined stream of all of the child chips' blur events. */
get chipBlurChanges(): Observable<MatChipEvent> {
Expand All @@ -270,27 +238,43 @@ export class MatChipGrid
// We need an initializer here to avoid a TS error. The value will be set in `ngAfterViewInit`.
override _chips: QueryList<MatChipRow> = undefined!;

/**
* Emits whenever the component state changes and should cause the parent
* form-field to update. Implemented as part of `MatFormFieldControl`.
* @docs-private
*/
readonly stateChanges = new Subject<void>();

/** Whether the chip grid is in an error state. */
get errorState() {
return this._errorStateTracker.errorState;
}
set errorState(value: boolean) {
this._errorStateTracker.errorState = value;
}

constructor(
elementRef: ElementRef,
changeDetectorRef: ChangeDetectorRef,
@Optional() dir: Directionality,
@Optional() parentForm: NgForm,
@Optional() parentFormGroup: FormGroupDirective,
defaultErrorStateMatcher: ErrorStateMatcher,
@Optional() @Self() ngControl: NgControl,
@Optional() @Self() public ngControl: NgControl,
) {
super(
elementRef,
changeDetectorRef,
dir,
defaultErrorStateMatcher,
parentForm,
parentFormGroup,
ngControl,
);
super(elementRef, changeDetectorRef, dir);

if (this.ngControl) {
this.ngControl.valueAccessor = this;
}

this._errorStateTracker = new _ErrorStateTracker(
defaultErrorStateMatcher,
ngControl,
parentFormGroup,
parentForm,
this.stateChanges,
);
}

ngAfterContentInit() {
Expand Down Expand Up @@ -407,6 +391,11 @@ export class MatChipGrid
this.stateChanges.next();
}

/** Refreshes the error state of the chip grid. */
updateErrorState() {
this._errorStateTracker.updateErrorState();
}

/** When blurred, mark the field as touched when focus moved outside the chip grid. */
_blur() {
if (!this.disabled) {
Expand Down
14 changes: 9 additions & 5 deletions tools/public_api_guard/material/chips.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
```ts

import { _AbstractConstructor } from '@angular/material/core';
import { AfterContentInit } from '@angular/core';
import { AfterViewInit } from '@angular/core';
import { CanUpdateErrorState } from '@angular/material/core';
import { ChangeDetectorRef } from '@angular/core';
import { _Constructor } from '@angular/material/core';
import { ControlValueAccessor } from '@angular/forms';
import { Directionality } from '@angular/cdk/bidi';
import { DoCheck } from '@angular/core';
Expand Down Expand Up @@ -172,7 +169,7 @@ export interface MatChipEvent {
}

// @public
export class MatChipGrid extends _MatChipGridMixinBase implements AfterContentInit, AfterViewInit, CanUpdateErrorState, ControlValueAccessor, DoCheck, MatFormFieldControl<any>, OnDestroy {
export class MatChipGrid extends MatChipSet implements AfterContentInit, AfterViewInit, ControlValueAccessor, DoCheck, MatFormFieldControl<any>, OnDestroy {
constructor(elementRef: ElementRef, changeDetectorRef: ChangeDetectorRef, dir: Directionality, parentForm: NgForm, parentFormGroup: FormGroupDirective, defaultErrorStateMatcher: ErrorStateMatcher, ngControl: NgControl);
protected _allowFocusEscape(): void;
_blur(): void;
Expand All @@ -187,7 +184,10 @@ export class MatChipGrid extends _MatChipGridMixinBase implements AfterContentIn
get disabled(): boolean;
set disabled(value: boolean);
get empty(): boolean;
errorStateMatcher: ErrorStateMatcher;
get errorState(): boolean;
set errorState(value: boolean);
get errorStateMatcher(): ErrorStateMatcher;
set errorStateMatcher(value: ErrorStateMatcher);
focus(): void;
get focused(): boolean;
// (undocumented)
Expand All @@ -203,6 +203,8 @@ export class MatChipGrid extends _MatChipGridMixinBase implements AfterContentIn
// (undocumented)
ngAfterViewInit(): void;
// (undocumented)
ngControl: NgControl;
// (undocumented)
ngDoCheck(): void;
// (undocumented)
ngOnDestroy(): void;
Expand All @@ -223,6 +225,8 @@ export class MatChipGrid extends _MatChipGridMixinBase implements AfterContentIn
setDescribedByIds(ids: string[]): void;
setDisabledState(isDisabled: boolean): void;
get shouldLabelFloat(): boolean;
readonly stateChanges: Subject<void>;
updateErrorState(): void;
get value(): any;
set value(value: any);
// (undocumented)
Expand Down

0 comments on commit 00e076e

Please sign in to comment.