Email must be on the {{ email.errors.emailDomain.requiredDomain }} domain
Now if we change the domain name in the global provider like so: @NgModule({ providers: [ {provide: 'RequiredDomain', useValue: 'example.com'} ] }) The email domain validator now check against this new domain instead: Bindable template driven validators We can also configure out template validator directive via property binding in the template instead, like so: ① We can configure the validator via template property binding Then we update our EmailDomainValidator class so it can take the required domain as an input: 10 11 12 13 14 15 16 class EmailDomainValidator { @Input('emailDomain') emailDomain: string; ① private valFn = Validators.nullValidator; ngOnChanges(): void { ② if (this.emailDomain) { this.valFn = CodeCraftValidators.emailDomain(this.emailDomain) } else { this.valFn = Validators.nullValidator; } } validate(control: FormControl) { return this.valFn(control); } } ① First we create an input property on our directive named the same as our selector ② We know the emailDomain input property has been set when the ngOnChanges lifecycle function is called, this is where we now initialise our directive with the configured validator function Our directive needs one more change in order to function, we are providing this as a class, we need to provide as an alias so we get exactly the same instance provided to the validators 10 @Directive({ selector: '[emailDomain][ngModel]', providers: [ { provide: NG_VALIDATORS, useExisting: EmailDomainValidator, multi: true } ] }) Now we have a template driven form validator which can be configured via input property binding Summary For model driven forms we use a factory function which returns a validator function configured as we want For template driven forms we create a validator class, often re-using the same factory function as was used in model driven forms Model Driven Listing http://plnkr.co/edit/mLdGJG23cyPkhzncye5t?p=preview Listing 1 script.ts import { NgModule, Component, Pipe, OnInit } from '@angular/core'; import { ReactiveFormsModule, FormsModule, FormGroup, FormControl, Validators, FormBuilder } from '@angular/forms'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; function emailDomainValidator(control: FormControl) { let email = control.value; if (email && email.indexOf("@") != -1) { let [_, domain] = email.split("@"); if (domain !== "codecraft.tv") { return { emailDomain: { parsedDomain: domain } } } } return null; } @Component({ selector: 'model-form', template: ` First NameLast Name is required
Last NameLast Name is required
EmailEmail is required
The email address must contain at least the @ character
Email must be on the codecraft.tv domain
PasswordPassword is required
Password must be 8 characters long, we need another {{password.errors.minlength.requiredLength - password.errors.minlength.actualLength}} characters
Language Please select a language {{lang}} {{myform.value | json}} ` }) class ModelFormComponent implements OnInit { langs: string[] = [ 'English', 'French', 'German', ]; myform: FormGroup; firstName: FormControl; lastName: FormControl; email: FormControl; password: FormControl; language: FormControl; ngOnInit() { this.createFormControls(); this.createForm(); } createFormControls() { this.firstName = new FormControl('', Validators.required); this.lastName = new FormControl('', Validators.required); this.email = new FormControl('', [ Validators.required, Validators.pattern("[^ @]*@[^ @]*"), emailDomainValidator ]); this.password = new FormControl('', [ Validators.required, Validators.minLength(8) ]); this.language = new FormControl(''); } createForm() { this.myform = new FormGroup({ name: new FormGroup({ firstName: this.firstName, lastName: this.lastName, }), email: this.email, password: this.password, language: this.language }); } } @Component({ selector: 'app', template: `` }) class AppComponent { } @NgModule({ imports: [ BrowserModule, FormsModule, ReactiveFormsModule], declarations: [ AppComponent, ModelFormComponent ], bootstrap: [ AppComponent ] }) class AppModule { } platformBrowserDynamic().bootstrapModule(AppModule); Template Driven Listing http://plnkr.co/edit/iXI6fJaV02xPN9PcRY3b?p=preview Listing 2 script.ts import { NgModule, Component, OnInit, ViewChild, Directive, Inject, Input, } from '@angular/core'; import { NG_VALIDATORS, FormsModule, FormGroup, FormControl, ValidatorFn, Validators } from '@angular/forms'; import {BrowserModule} from '@angular/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; class Signup { constructor(public firstName: string = '', public lastName: string = '', public email: string = '', public password: string = '', public language: string = '') { } } function emailDomainValidator(control: FormControl) { let email = control.value; if (email && email.indexOf("@") != -1) { let [_, domain] = email.split("@"); if (domain !== "codecraft.tv") { return { emailDomain: { parsedDomain: domain } } } } return null; } @Directive({ selector: '[emailDomain][ngModel]', providers: [ { provide: NG_VALIDATORS, useValue: emailDomainValidator, multi: true } ] }) class EmailDomainValidator { } @Component({ selector: 'template-form', template: ` First NameFirst name is required
Last NameLast name is required
EmailEmail is required
Email must contain at least the @ character
Email must be on the codecraft.tv domain >Email must be on the {{ email.errors.emailDomain.requiredDomain }} domain
PasswordPassword is required
Password must be at least 8 characters long
Language Please select a language {{lang}} Submit {{f.value | json}} ` }) class TemplateFormComponent { model: Signup = new Signup(); @ViewChild('f') form: any; langs: string[] = [ 'English', 'French', 'German', ]; onSubmit() { if (this.form.valid) { console.log("Form Submitted!"); this.form.reset(); } } } @Component({ selector: 'app', template: `` }) class AppComponent { } @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, TemplateFormComponent, EmailDomainValidator ], bootstrap: [ AppComponent ] }) class AppModule { } platformBrowserDynamic().bootstrapModule(AppModule); ... our example above @Component has one parameter called selector, this tells Angular 2 which tag to link this class too By setting the selector to joke we’ve told angular that whenever it finds a tag in the HTML like to use an instance of the JokeComponent class to control it... We’ve defined a component with a custom tag, added the tag to our HTML but we haven’t told Angular that we want to use Angular on this page To do that we need to do something called bootstrapping In Angular 1 when we added np-app="module-name" to the top of the HTML page it bootstrapped the application... You might be asking yourself why Angular 2 doesn’t do this for us like it did in Angular 1? In Angular 2 bootstrapping is platform specific Angular 1 assumed that Angular would only ever be run in a browser, Angular 2 makes no such