66 FormGroupDirective ,
77 FormsModule ,
88 NgForm ,
9+ NgControl ,
910 ReactiveFormsModule ,
1011 Validators
1112} from '@angular/forms' ;
@@ -23,6 +24,7 @@ import {
2324 getMdInputContainerPlaceholderConflictError
2425} from './input-container-errors' ;
2526import { MD_PLACEHOLDER_GLOBAL_OPTIONS } from '../core/placeholder/placeholder-options' ;
27+ import { MD_ERROR_GLOBAL_OPTIONS } from '../core/error/error-options' ;
2628
2729describe ( 'MdInputContainer' , function ( ) {
2830 beforeEach ( async ( ( ) => {
@@ -56,6 +58,7 @@ describe('MdInputContainer', function () {
5658 MdInputContainerWithDynamicPlaceholder ,
5759 MdInputContainerWithFormControl ,
5860 MdInputContainerWithFormErrorMessages ,
61+ MdInputContainerWithCustomErrorStateMatcher ,
5962 MdInputContainerWithFormGroupErrorMessages ,
6063 MdInputContainerWithId ,
6164 MdInputContainerWithPrefixAndSuffix ,
@@ -705,6 +708,116 @@ describe('MdInputContainer', function () {
705708 } ) ;
706709 } ) ) ;
707710
711+ it ( 'should display an error message when a custom error matcher returns true' , async ( ( ) => {
712+ fixture . destroy ( ) ;
713+
714+ let customFixture = TestBed . createComponent ( MdInputContainerWithCustomErrorStateMatcher ) ;
715+ let component : MdInputContainerWithCustomErrorStateMatcher ;
716+
717+ customFixture . detectChanges ( ) ;
718+ component = customFixture . componentInstance ;
719+ containerEl = customFixture . debugElement . query ( By . css ( 'md-input-container' ) ) . nativeElement ;
720+
721+ expect ( component . formControl . invalid ) . toBe ( true , 'Expected form control to be invalid' ) ;
722+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length ) . toBe ( 0 , 'Expected no error messages' ) ;
723+
724+ component . formControl . markAsTouched ( ) ;
725+ customFixture . detectChanges ( ) ;
726+
727+ customFixture . whenStable ( ) . then ( ( ) => {
728+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length )
729+ . toBe ( 0 , 'Expected no error messages after being touched.' ) ;
730+
731+ component . errorState = true ;
732+ customFixture . detectChanges ( ) ;
733+
734+ customFixture . whenStable ( ) . then ( ( ) => {
735+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length )
736+ . toBe ( 1 , 'Expected one error messages to have been rendered.' ) ;
737+ } ) ;
738+ } ) ;
739+ } ) ) ;
740+
741+ it ( 'should display an error message when global error matcher returns true' , ( ) => {
742+
743+ // Global error state matcher that will always cause errors to show
744+ function globalErrorStateMatcher ( ) {
745+ return true ;
746+ }
747+
748+ TestBed . resetTestingModule ( ) ;
749+ TestBed . configureTestingModule ( {
750+ imports : [
751+ FormsModule ,
752+ MdInputModule ,
753+ NoopAnimationsModule ,
754+ ReactiveFormsModule ,
755+ ] ,
756+ declarations : [
757+ MdInputContainerWithFormErrorMessages
758+ ] ,
759+ providers : [
760+ {
761+ provide : MD_ERROR_GLOBAL_OPTIONS ,
762+ useValue : { errorStateMatcher : globalErrorStateMatcher } }
763+ ]
764+ } ) ;
765+
766+ let customFixture = TestBed . createComponent ( MdInputContainerWithFormErrorMessages ) ;
767+ customFixture . detectChanges ( ) ;
768+
769+ containerEl = customFixture . debugElement . query ( By . css ( 'md-input-container' ) ) . nativeElement ;
770+ testComponent = customFixture . componentInstance ;
771+
772+ // Expect the control to still be untouched but the error to show due to the global setting
773+ expect ( testComponent . formControl . untouched ) . toBe ( true , 'Expected untouched form control' ) ;
774+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length ) . toBe ( 1 , 'Expected an error message' ) ;
775+ } ) ;
776+
777+ it ( 'should display an error message when global setting shows errors on dirty' , async ( ) => {
778+ TestBed . resetTestingModule ( ) ;
779+ TestBed . configureTestingModule ( {
780+ imports : [
781+ FormsModule ,
782+ MdInputModule ,
783+ NoopAnimationsModule ,
784+ ReactiveFormsModule ,
785+ ] ,
786+ declarations : [
787+ MdInputContainerWithFormErrorMessages
788+ ] ,
789+ providers : [
790+ { provide : MD_ERROR_GLOBAL_OPTIONS , useValue : { showOnDirty : true } }
791+ ]
792+ } ) ;
793+
794+ let customFixture = TestBed . createComponent ( MdInputContainerWithFormErrorMessages ) ;
795+ customFixture . detectChanges ( ) ;
796+
797+ containerEl = customFixture . debugElement . query ( By . css ( 'md-input-container' ) ) . nativeElement ;
798+ testComponent = customFixture . componentInstance ;
799+
800+ expect ( testComponent . formControl . invalid ) . toBe ( true , 'Expected form control to be invalid' ) ;
801+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length ) . toBe ( 0 , 'Expected no error messages' ) ;
802+
803+ testComponent . formControl . markAsTouched ( ) ;
804+ customFixture . detectChanges ( ) ;
805+
806+ customFixture . whenStable ( ) . then ( ( ) => {
807+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length )
808+ . toBe ( 0 , 'Expected no error messages when touched' ) ;
809+
810+ testComponent . formControl . markAsDirty ( ) ;
811+ customFixture . detectChanges ( ) ;
812+
813+ customFixture . whenStable ( ) . then ( ( ) => {
814+ expect ( containerEl . querySelectorAll ( 'md-error' ) . length )
815+ . toBe ( 1 , 'Expected one error message when dirty' ) ;
816+ } ) ;
817+ } ) ;
818+
819+ } ) ;
820+
708821 it ( 'should hide the errors and show the hints once the input becomes valid' , async ( ( ) => {
709822 testComponent . formControl . markAsTouched ( ) ;
710823 fixture . detectChanges ( ) ;
@@ -1018,6 +1131,29 @@ class MdInputContainerWithFormErrorMessages {
10181131 renderError = true ;
10191132}
10201133
1134+ @Component ( {
1135+ template : `
1136+ <form #form="ngForm" novalidate>
1137+ <md-input-container>
1138+ <input mdInput
1139+ [formControl]="formControl"
1140+ [errorStateMatcher]="customErrorStateMatcher.bind(this)">
1141+ <md-hint>Please type something</md-hint>
1142+ <md-error>This field is required</md-error>
1143+ </md-input-container>
1144+ </form>
1145+ `
1146+ } )
1147+ class MdInputContainerWithCustomErrorStateMatcher {
1148+ @ViewChild ( 'form' ) form : NgForm ;
1149+ formControl = new FormControl ( '' , Validators . required ) ;
1150+ errorState = false ;
1151+
1152+ customErrorStateMatcher ( ) : boolean {
1153+ return this . errorState ;
1154+ }
1155+ }
1156+
10211157@Component ( {
10221158 template : `
10231159 <form [formGroup]="formGroup" novalidate>
0 commit comments