Skip to content

Commit

Permalink
fix(select): errors not shown on submit (#7640)
Browse files Browse the repository at this point in the history
Fixes `mat-select` error messages not being shown when the parent form is submitted.

Fixes #7634.
  • Loading branch information
crisbeto authored and andrewseguin committed Oct 9, 2017
1 parent dc76c09 commit d2f41a4
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 9 deletions.
13 changes: 13 additions & 0 deletions src/lib/select/select.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2947,6 +2947,17 @@ describe('MatSelect', () => {
.toBe('true', 'Expected aria-invalid to be set to true.');
});

it('should render the error messages when the parent form is submitted', () => {
const debugEl = fixture.debugElement.nativeElement;

expect(debugEl.querySelectorAll('mat-error').length).toBe(0, 'Expected no error messages');

dispatchFakeEvent(fixture.debugElement.query(By.css('form')).nativeElement, 'submit');
fixture.detectChanges();

expect(debugEl.querySelectorAll('mat-error').length).toBe(1, 'Expected one error message');
});

it('should be able to override the error matching behavior via an @Input', () => {
fixture.destroy();

Expand Down Expand Up @@ -3652,6 +3663,8 @@ class InvalidSelectInForm {
<mat-option value="steak-0">Steak</mat-option>
<mat-option value="pizza-1">Pizza</mat-option>
</mat-select>
<mat-error>This field is required</mat-error>
</mat-form-field>
</form>
`
Expand Down
35 changes: 26 additions & 9 deletions src/lib/select/select.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import {
Self,
ViewChild,
ViewEncapsulation,
DoCheck,
} from '@angular/core';
import {
ControlValueAccessor,
Expand Down Expand Up @@ -188,7 +189,7 @@ export class MatSelectTrigger {}
providers: [{provide: MatFormFieldControl, useExisting: MatSelect}],
})
export class MatSelect extends _MatSelectMixinBase implements AfterContentInit, OnDestroy, OnInit,
ControlValueAccessor, CanDisable, HasTabIndex, MatFormFieldControl<any> {
DoCheck, ControlValueAccessor, CanDisable, HasTabIndex, MatFormFieldControl<any> {
/** Whether or not the overlay panel is open. */
private _panelOpen = false;

Expand Down Expand Up @@ -458,6 +459,12 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
});
}

ngDoCheck() {
if (this.ngControl) {
this._updateErrorState();
}
}

ngOnDestroy() {
this._dropSubscriptions();
this._changeSubscription.unsubscribe();
Expand Down Expand Up @@ -690,13 +697,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
}

/** Whether the select is in an error state. */
get errorState(): boolean {
const parent = this._parentFormGroup || this._parentForm;
const matcher = this.errorStateMatcher || this._defaultErrorStateMatcher;
const control = this.ngControl ? this.ngControl.control as FormControl : null;

return matcher.isErrorState(control, parent);
}
errorState: boolean;

private _initializeSelection(): void {
// Defer setting the value in order to avoid the "Expression
Expand Down Expand Up @@ -1200,6 +1201,20 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
return this._triggerFontSize * SELECT_ITEM_HEIGHT_EM;
}

/** Updates the select's error state. Only relevant when used with @angular/forms. */
private _updateErrorState() {
const oldState = this.errorState;
const parent = this._parentFormGroup || this._parentForm;
const matcher = this.errorStateMatcher || this._defaultErrorStateMatcher;
const control = this.ngControl ? this.ngControl.control as FormControl : null;
const newState = matcher.isErrorState(control, parent);

if (newState !== oldState) {
this.errorState = newState;
this.stateChanges.next();
}
}

// Implemented as part of MatFormFieldControl.
setDescribedByIds(ids: string[]) {
this._ariaDescribedby = ids.join(' ');
Expand All @@ -1212,5 +1227,7 @@ export class MatSelect extends _MatSelectMixinBase implements AfterContentInit,
}

// Implemented as part of MatFormFieldControl.
get shouldPlaceholderFloat(): boolean { return this._panelOpen || !this.empty; }
get shouldPlaceholderFloat(): boolean {
return this._panelOpen || !this.empty;
}
}

0 comments on commit d2f41a4

Please sign in to comment.