diff --git a/src/material-experimental/mdc-chips/chip-grid.spec.ts b/src/material-experimental/mdc-chips/chip-grid.spec.ts index c21afccfb598..4c640740f9c0 100644 --- a/src/material-experimental/mdc-chips/chip-grid.spec.ts +++ b/src/material-experimental/mdc-chips/chip-grid.spec.ts @@ -732,7 +732,7 @@ describe('MDC-based MatChipGrid', () => { .withContext(`Expected placeholder not to have an asterisk, as control was not required.`) .toBeNull(); - fixture.componentInstance.isRequired = true; + fixture.componentInstance.chipGrid.required = true; fixture.detectChanges(); requiredMarker = fixture.debugElement.query(By.css('.mdc-floating-label--required'))!; @@ -741,6 +741,15 @@ describe('MDC-based MatChipGrid', () => { .toBeNull(); }); + it('should mark the component as required if the control has a required validator', () => { + fixture.destroy(); + fixture = TestBed.createComponent(InputChipGrid); + fixture.componentInstance.control = new FormControl(undefined, [Validators.required]); + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.mdc-floating-label--required')).toBeTruthy(); + }); + it('should blur the form field when the active chip is blurred', fakeAsync(() => { const formField: HTMLElement = fixture.nativeElement.querySelector('.mat-mdc-form-field'); @@ -1077,8 +1086,7 @@ class FormFieldChipGrid { template: ` New food... - + {{ food.viewValue }} @@ -1106,7 +1114,6 @@ class InputChipGrid { separatorKeyCodes = [ENTER, SPACE]; addOnBlur: boolean = true; - isRequired: boolean; add(event: MatChipInputEvent): void { const value = (event.value || '').trim(); diff --git a/src/material-experimental/mdc-chips/chip-grid.ts b/src/material-experimental/mdc-chips/chip-grid.ts index abfa0bee8123..924fe87fd713 100644 --- a/src/material-experimental/mdc-chips/chip-grid.ts +++ b/src/material-experimental/mdc-chips/chip-grid.ts @@ -27,7 +27,13 @@ import { Self, ViewEncapsulation } from '@angular/core'; -import {ControlValueAccessor, FormGroupDirective, NgControl, NgForm} from '@angular/forms'; +import { + ControlValueAccessor, + FormGroupDirective, + NgControl, + NgForm, + Validators, +} from '@angular/forms'; import { CanUpdateErrorState, CanUpdateErrorStateCtor, @@ -186,12 +192,14 @@ export class MatChipGrid extends _MatChipGridMixinBase implements AfterContentIn * @docs-private */ @Input() - get required(): boolean { return this._required; } + get required(): boolean { + return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false; + } set required(value: boolean) { this._required = coerceBooleanProperty(value); this.stateChanges.next(); } - protected _required: boolean = false; + protected _required: boolean | undefined; /** * Implemented as part of MatFormFieldControl. diff --git a/src/material/chips/chip-list.spec.ts b/src/material/chips/chip-list.spec.ts index 6d72b230b2ff..e5ae4ae44fc6 100644 --- a/src/material/chips/chip-list.spec.ts +++ b/src/material/chips/chip-list.spec.ts @@ -857,7 +857,7 @@ describe('MatChipList', () => { .withContext(`Expected placeholder not to have an asterisk, as control was not required.`) .toBeNull(); - fixture.componentInstance.isRequired = true; + fixture.componentInstance.chipList.required = true; fixture.detectChanges(); requiredMarker = fixture.debugElement.query(By.css('.mat-form-field-required-marker'))!; @@ -866,6 +866,13 @@ describe('MatChipList', () => { .not.toBeNull(); }); + it('should mark the component as required if the control has a required validator', () => { + fixture.componentInstance.control = new FormControl(undefined, [Validators.required]); + fixture.detectChanges(); + + expect(fixture.nativeElement.querySelector('.mat-form-field-required-marker')).toBeTruthy(); + }); + it('should be able to programmatically select a falsy option', () => { fixture.destroy(); TestBed.resetTestingModule(); @@ -1487,7 +1494,7 @@ class FormFieldChipList { selector: 'basic-chip-list', template: ` - {{ food.viewValue }} @@ -1508,7 +1515,6 @@ class BasicChipList { {value: 'sushi-7', viewValue: 'Sushi'}, ]; control = new FormControl(); - isRequired: boolean; tabIndexOverride: number; selectable: boolean; diff --git a/src/material/chips/chip-list.ts b/src/material/chips/chip-list.ts index ee007d48fbed..e574d08fe5c0 100644 --- a/src/material/chips/chip-list.ts +++ b/src/material/chips/chip-list.ts @@ -28,7 +28,13 @@ import { Self, ViewEncapsulation, } from '@angular/core'; -import {ControlValueAccessor, FormGroupDirective, NgControl, NgForm} from '@angular/forms'; +import { + ControlValueAccessor, + FormGroupDirective, + NgControl, + NgForm, + Validators, +} from '@angular/forms'; import { CanUpdateErrorState, ErrorStateMatcher, @@ -213,12 +219,14 @@ export class MatChipList extends _MatChipListBase implements MatFormFieldControl * @docs-private */ @Input() - get required(): boolean { return this._required; } + get required(): boolean { + return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false; + } set required(value: boolean) { this._required = coerceBooleanProperty(value); this.stateChanges.next(); } - protected _required: boolean = false; + protected _required: boolean | undefined; /** * Implemented as part of MatFormFieldControl. diff --git a/tools/public_api_guard/material/chips.md b/tools/public_api_guard/material/chips.md index c55e68db5839..d630f0e0fba3 100644 --- a/tools/public_api_guard/material/chips.md +++ b/tools/public_api_guard/material/chips.md @@ -259,7 +259,7 @@ export class MatChipList extends _MatChipListBase implements MatFormFieldControl get required(): boolean; set required(value: boolean); // (undocumented) - protected _required: boolean; + protected _required: boolean | undefined; get role(): string | null; get selectable(): boolean; set selectable(value: boolean);