Skip to content

Commit 3db132c

Browse files
committed
refactor: address feedback
1 parent 2481c3f commit 3db132c

File tree

8 files changed

+44
-58
lines changed

8 files changed

+44
-58
lines changed

src/lib/core/core.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ export {
127127
MdErrorModule,
128128
MdError,
129129
ErrorStateMatcher,
130-
ErrorOptions,
131-
showOnDirtyErrorStateMatcher,
130+
ShowOnDirtyErrorStateMatcher,
132131
} from './error/index';
133132

134133
@NgModule({

src/lib/core/error/error-options.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,18 @@
99
import {Injectable} from '@angular/core';
1010
import {FormGroupDirective, NgForm, NgControl} from '@angular/forms';
1111

12-
export type ErrorStateMatcher =
13-
(control: NgControl | null, form: FormGroupDirective | NgForm | null) => boolean;
14-
15-
/** Returns whether control is invalid and is either dirty or is a part of a submitted form. */
16-
export const showOnDirtyErrorStateMatcher: ErrorStateMatcher = (control, form) => {
17-
return control ? !!(control.invalid && (control.dirty || (form && form.submitted))) : false;
18-
};
12+
/** Error state matcher that matches when a control is invalid and dirty. */
13+
@Injectable()
14+
export class ShowOnDirtyErrorStateMatcher implements ErrorStateMatcher {
15+
match(control: NgControl | null, form: FormGroupDirective | NgForm | null): boolean {
16+
return control ? !!(control.invalid && (control.dirty || (form && form.submitted))) : false;
17+
}
18+
}
1919

20-
/**
21-
* Provider that defines how form controls behave with
22-
* regards to displaying error messages.
23-
*/
20+
/** Provider that defines how form controls behave with regards to displaying error messages. */
2421
@Injectable()
25-
export class ErrorOptions {
26-
isErrorState(control: NgControl | null, form: FormGroupDirective | NgForm | null): boolean {
22+
export class ErrorStateMatcher {
23+
match(control: NgControl | null, form: FormGroupDirective | NgForm | null): boolean {
2724
return control ? !!(control.invalid && (control.touched || (form && form.submitted))) : false;
2825
}
2926
}

src/lib/core/error/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
import {NgModule} from '@angular/core';
1111
import {MdError} from './error';
12-
import {ErrorOptions} from './error-options';
12+
import {ErrorStateMatcher} from './error-options';
1313

1414
@NgModule({
1515
declarations: [MdError],
1616
exports: [MdError],
17-
providers: [ErrorOptions],
17+
providers: [ErrorStateMatcher],
1818
})
1919
export class MdErrorModule {}
2020

src/lib/input/input-container.spec.ts

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import {
2222
getMdInputContainerPlaceholderConflictError
2323
} from './input-container-errors';
2424
import {MD_PLACEHOLDER_GLOBAL_OPTIONS} from '../core/placeholder/placeholder-options';
25-
import {ErrorOptions, showOnDirtyErrorStateMatcher} from '../core/error/error-options';
25+
import {ErrorStateMatcher, ShowOnDirtyErrorStateMatcher} from '../core/error/error-options';
2626

2727
describe('MdInputContainer without forms', function () {
2828
beforeEach(async(() => {
@@ -842,11 +842,7 @@ describe('MdInputContainer with forms', () => {
842842
declarations: [
843843
MdInputContainerWithFormErrorMessages
844844
],
845-
providers: [
846-
{
847-
provide: ErrorOptions,
848-
useValue: { isErrorState: globalErrorStateMatcher } }
849-
]
845+
providers: [{ provide: ErrorStateMatcher, useValue: { match: globalErrorStateMatcher } }]
850846
});
851847

852848
let fixture = TestBed.createComponent(MdInputContainerWithFormErrorMessages);
@@ -873,12 +869,7 @@ describe('MdInputContainer with forms', () => {
873869
declarations: [
874870
MdInputContainerWithFormErrorMessages
875871
],
876-
providers: [
877-
{
878-
provide: ErrorOptions,
879-
useValue: { isErrorState: showOnDirtyErrorStateMatcher }
880-
}
881-
]
872+
providers: [{ provide: ErrorStateMatcher, useClass: ShowOnDirtyErrorStateMatcher }]
882873
});
883874

884875
let fixture = TestBed.createComponent(MdInputContainerWithFormErrorMessages);
@@ -1207,7 +1198,9 @@ class MdInputContainerWithCustomErrorStateMatcher {
12071198
});
12081199

12091200
errorState = false;
1210-
customErrorStateMatcher = () => this.errorState;
1201+
customErrorStateMatcher: ErrorStateMatcher = {
1202+
match: () => this.errorState
1203+
};
12111204
}
12121205

12131206
@Component({

src/lib/input/input-container.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import {
4444
MD_PLACEHOLDER_GLOBAL_OPTIONS,
4545
PlaceholderOptions
4646
} from '../core/placeholder/placeholder-options';
47-
import {ErrorOptions, ErrorStateMatcher, MdError} from '../core/error/index';
47+
import {ErrorStateMatcher, MdError} from '../core/error/index';
4848
import {Subject} from 'rxjs/Subject';
4949

5050
// Invalid input type. Using one of these will throw an MdInputContainerUnsupportedTypeError.
@@ -188,7 +188,7 @@ export class MdInputDirective implements OnChanges, OnDestroy, DoCheck {
188188
get readonly() { return this._readonly; }
189189
set readonly(value: any) { this._readonly = coerceBooleanProperty(value); }
190190

191-
/** A function used to control when error messages are shown. */
191+
/** An object used to control when error messages are shown. */
192192
@Input() errorStateMatcher: ErrorStateMatcher;
193193

194194
/** The input element's value. */
@@ -217,7 +217,7 @@ export class MdInputDirective implements OnChanges, OnDestroy, DoCheck {
217217
constructor(private _elementRef: ElementRef,
218218
private _renderer: Renderer2,
219219
private _platform: Platform,
220-
private _errorOptions: ErrorOptions,
220+
private _globalErrorStateMatcher: ErrorStateMatcher,
221221
@Optional() @Self() public _ngControl: NgControl,
222222
@Optional() private _parentForm: NgForm,
223223
@Optional() private _parentFormGroup: FormGroupDirective) {
@@ -295,9 +295,8 @@ export class MdInputDirective implements OnChanges, OnDestroy, DoCheck {
295295
/** Re-evaluates the error state. This is only relevant with @angular/forms. */
296296
private _updateErrorState() {
297297
const oldState = this._isErrorState;
298-
const newState = this.errorStateMatcher ?
299-
this.errorStateMatcher(this._ngControl, this._parentFormGroup || this._parentForm) :
300-
this._errorOptions.isErrorState(this._ngControl, this._parentFormGroup || this._parentForm);
298+
const matcher = this.errorStateMatcher || this._globalErrorStateMatcher;
299+
const newState = matcher.match(this._ngControl, this._parentFormGroup || this._parentForm);
301300

302301
if (newState !== oldState) {
303302
this._isErrorState = newState;

src/lib/input/input.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,21 +125,23 @@ the error messages.
125125
```
126126

127127
```ts
128-
function myErrorStateMatcher(control: FormControl, form: FormGroupDirective | NgForm): boolean {
129-
// Error when invalid control is dirty, touched, or submitted
130-
const isSubmitted = form && form.submitted;
131-
return !!(control.invalid && (control.dirty || control.touched || isSubmitted)));
128+
class MyErrorStateMatcher implements ErrorStateMatcher {
129+
match(control: NgControl | null, form: FormGroupDirective | NgForm | null): boolean {
130+
// Error when invalid control is dirty, touched, or submitted
131+
const isSubmitted = form && form.submitted;
132+
return !!(control.invalid && (control.dirty || control.touched || isSubmitted)));
133+
}
132134
}
133135
```
134136

135137
A global error state matcher can be specified by setting the `ErrorOptions` provider. This applies
136-
to all inputs. For convenience, `showOnDirtyErrorStateMatcher` is available in order to globally
138+
to all inputs. For convenience, `ShowOnDirtyErrorStateMatcher` is available in order to globally
137139
cause input errors to show when the input is dirty and invalid.
138140

139141
```ts
140142
@NgModule({
141143
providers: [
142-
{provide: ErrorOptions, useValue: { isErrorState: showOnDirtyErrorStateMatcher }}
144+
{provide: ErrorOptions, useClass: ShowOnDirtyErrorStateMatcher}
143145
]
144146
})
145147
```

src/lib/select/select.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import {Subject} from 'rxjs/Subject';
3131
import {ViewportRuler} from '../core/overlay/position/viewport-ruler';
3232
import {dispatchFakeEvent, dispatchKeyboardEvent, wrappedErrorMessage} from '@angular/cdk/testing';
3333
import {ScrollDispatcher} from '../core/overlay/scroll/scroll-dispatcher';
34-
import {ErrorOptions} from '../core/error/error-options';
34+
import {ErrorStateMatcher} from '../core/error/error-options';
3535
import {
3636
FloatPlaceholderType,
3737
MD_PLACEHOLDER_GLOBAL_OPTIONS
@@ -2674,24 +2674,24 @@ describe('MdSelect', () => {
26742674
expect(component.control.invalid).toBe(false);
26752675
expect(component.select._isErrorState()).toBe(false);
26762676

2677-
customErrorFixture.componentInstance.errorStateMatcher = matcher;
2677+
customErrorFixture.componentInstance.errorStateMatcher = { match: matcher };
26782678
customErrorFixture.detectChanges();
26792679

26802680
expect(component.select._isErrorState()).toBe(true);
26812681
expect(matcher).toHaveBeenCalled();
26822682
});
26832683

26842684
it('should be able to override the error matching behavior via the injection token', () => {
2685-
const errorOptions: ErrorOptions = {
2686-
isErrorState: jasmine.createSpy('error state matcher').and.returnValue(true)
2685+
const errorOptions: ErrorStateMatcher = {
2686+
match: jasmine.createSpy('error state matcher').and.returnValue(true)
26872687
};
26882688

26892689
fixture.destroy();
26902690

26912691
TestBed.resetTestingModule().configureTestingModule({
26922692
imports: [MdSelectModule, ReactiveFormsModule, FormsModule, NoopAnimationsModule],
26932693
declarations: [SelectInsideFormGroup],
2694-
providers: [{ provide: ErrorOptions, useValue: errorOptions }],
2694+
providers: [{ provide: ErrorStateMatcher, useValue: errorOptions }],
26952695
});
26962696

26972697
const errorFixture = TestBed.createComponent(SelectInsideFormGroup);
@@ -2700,7 +2700,7 @@ describe('MdSelect', () => {
27002700
errorFixture.detectChanges();
27012701

27022702
expect(component.select._isErrorState()).toBe(true);
2703-
expect(errorOptions.errorStateMatcher).toHaveBeenCalled();
2703+
expect(errorOptions.match).toHaveBeenCalled();
27042704
});
27052705
});
27062706

@@ -3257,6 +3257,6 @@ class CustomErrorBehaviorSelect {
32573257
{ value: 'steak-0', viewValue: 'Steak' },
32583258
{ value: 'pizza-1', viewValue: 'Pizza' },
32593259
];
3260-
errorStateMatcher = () => false;
3260+
errorStateMatcher: ErrorStateMatcher;
32613261
}
32623262

src/lib/select/select.ts

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import {
5757
// tslint:disable-next-line:no-unused-variable
5858
import {ScrollStrategy, RepositionScrollStrategy} from '../core/overlay/scroll';
5959
import {Platform} from '@angular/cdk/platform';
60-
import {ErrorStateMatcher, ErrorOptions} from '../core/error/error-options';
60+
import {ErrorStateMatcher} from '../core/error/error-options';
6161

6262
/**
6363
* The following style constants are necessary to save here in order
@@ -360,7 +360,7 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
360360
/** Input that can be used to specify the `aria-labelledby` attribute. */
361361
@Input('aria-labelledby') ariaLabelledby: string = '';
362362

363-
/** A function used to control when error messages are shown. */
363+
/** An object used to control when error messages are shown. */
364364
@Input() errorStateMatcher: ErrorStateMatcher;
365365

366366
/** Combined stream of all of the child options' change events. */
@@ -389,7 +389,7 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
389389
private _changeDetectorRef: ChangeDetectorRef,
390390
private _overlay: Overlay,
391391
private _platform: Platform,
392-
private _errorOptions: ErrorOptions,
392+
private _globalErrorStateMatcher: ErrorStateMatcher,
393393
renderer: Renderer2,
394394
elementRef: ElementRef,
395395
@Optional() private _dir: Directionality,
@@ -637,12 +637,8 @@ export class MdSelect extends _MdSelectMixinBase implements AfterContentInit, On
637637

638638
/** Whether the select is in an error state. */
639639
_isErrorState(): boolean {
640-
if (this.errorStateMatcher) {
641-
return this.errorStateMatcher(this._control, this._parentFormGroup || this._parentForm);
642-
}
643-
644-
return this._errorOptions.isErrorState(this._control,
645-
this._parentFormGroup || this._parentForm);
640+
const matcher = this.errorStateMatcher || this._globalErrorStateMatcher;
641+
return matcher.match(this._control, this._parentFormGroup || this._parentForm);
646642
}
647643

648644
/**

0 commit comments

Comments
 (0)