Книга: Angular 2 Cookbook
Назад: Implementing simple two-way data binding with ngModel
Дальше: Bundling controls with a FormGroup

Implementing basic field validation with a FormControl

The simplest form behavior imaginable would be the validation of a single input field. Most of the time, utilizing <form> tags and going through the rest of the boilerplate is good practice, but for the purpose of checking a single input, it's preferable to distill this down to the bare minimum required in order to use input checking.

Note

The code, links, and a live example related to this recipe are available at .

Getting ready

Suppose the following is your initial setup:

[app/article-editor.component.ts]      import {Component} from '@angular/core';      @Component({     selector: 'article-editor',     template: `       <p>Article title (required):</p>       <input required>       <button>Save</button>       <h1>{{title}}</h1>     `   })   export class ArticleEditorComponent {     title:string;   }   

Your goal is to change this in a way that clicking the save button will validate the input and update the title member only if it is valid.

How to do it...

The most elemental component of Angular forms is the FormControl object. In order to be able to assess the state of the field, you first need to instantiate this object inside the component and associate it with the field using the formControl directive. FormControl lives inside ReactiveFormsModule. Add it as a module import:

[app/app.module.ts]      import {NgModule} from '@angular/core';   import {BrowserModule} from '@angular/platform-browser';   import {ReactiveFormsModule} from '@angular/forms';   import {ArticleEditorComponent} from './article-editor.component';      @NgModule({     imports: [       BrowserModule,       ReactiveFormsModule     ],     declarations: [       ArticleEditorComponent      ],     bootstrap: [       ArticleEditorComponent      ]   })   export class AppModule {}   

With this, you can use FormControl inside ArticleEditorComponent. Instantiate FormControl inside the component and bind the input element to it using the formControl directive:

[app/article-editor.component.ts]      import {Component} from '@angular/core';   import {FormControl} from '@angular/forms';      @Component({     selector: 'article-editor',     template: `       <p>Article title (required):</p>       <input [formControl]="titleControl" required>       <button>Save</button>       <h1>{{title}}</h1>        `   })   export class ArticleEditorComponent  {     title:string;     titleControl:FormControl = new FormControl();   }   

Now that you have created a FormControl object and associated it with an input field, you will be able to use its validation API to check the state of the field. All that is left is to use it inside the submit click handler:

[app/article-editor.component.ts]      import {Component} from '@angular/core';   import {FormControl} from '@angular/forms';      @Component({     selector: 'article-editor',     template: `       <p>Article title (required):</p>       <input [formControl]="titleControl" required>       <button (click)="submitTitle()">Save</button>       <h1>{{title}}</h1>        `   })   export class ArticleEditorComponent  {     title:string;     titleControl:FormControl = new FormControl();          submitTitle():void {       if(this.titleControl.valid) {         this.title = this.titleControl.value;       } else {         alert("Title required");       }     }   }   

With this, the submit click handler will be able to check the input's validation state and value with the same object.

How it works...

The formControl directive serves only to bind an existing FormControl object to a DOM element. The FormControl object that you instantiate inside the component constructor can either utilize validation attributes inside an HTML tag (as is done in this example), or accept Angular validators when initialized; or, it can do both.

Note

It's extremely important to note that just because the FormControl object is instantiated, it does not mean that it is able to validate the input immediately.

Without an initialized value, an empty input field will begin its life with a value of null, which in the presence of a required attribute is of course invalid. However, in this example, if you were to check whether the FormControl object becomes valid immediately after you instantiate it in the constructor, the FormControl object would dutifully inform you that the state is valid since it has not been bound to the DOM element yet, and therefore, no validations are being violated. Since the input element's formControl binding will not occur until the component template becomes part of the actual DOM, you will not be able to check the input state until the binding is complete or inside the ngAfterContentChecked life cycle hook. Note that this pertains to the example under consideration.

Once the formControl directive completes the binding, the FormControl object will exist as an input wrapper, allowing you to use its valid and value members.

There's more...

This recipe uses ReactiveFormsModule, which is simpler to understand since all of the setup is explicit. When you use FormsModule instead, you discover that a lot of what is accomplished in this recipe could be done automatically for you, such as the instantiation and binding of FormControl objects. It also revolves around the presence of a <form> tag, which is the de facto top-level FormControl container. This recipe serves to demonstrate one of the simplest forms of Angular form behavior.

Validators and attribute duality

As mentioned in this recipe, validation definitions can come from two places. Here, you used a standardized HTML tag attribute that Angular recognizes and automatically incorporates into the FormControl validation specification. You could have just as easily elected to utilize an Angular Validator to accomplish the same task instead. This can be accomplished by importing Angular's default Validators and initializing the FormControl object with the required validator:

[app/article-editor.component.ts]      import {Component} from '@angular/core';   import {FormControl, Validators} from '@angular/forms';      @Component({     selector: 'article-editor',     template: `       <p>Article title (required):</p>       <input [formControl]="titleControl">       <button (click)="submitTitle()">Save</button>       <h1>{{title}}</h1>        `   })   export class ArticleEditorComponent  {     title:string;     // First argument is the default input value     titleControl:FormControl =        new FormControl(null, Validators.required);        submitTitle():void {       if(this.titleControl.valid) {         this.title = this.titleControl.value;       } else {         alert("Title required");       }     }   }   

Tagless controls

As you might suspect, there is no reason a FormControl must be bound to a DOM element. FormControl is an elemental piece of form logic that acts as an atomic piece of stateful information, whether or not this information is derived from <input>. Say you wanted to add a FormControl that would prevent quick form submission by only becoming valid after 10 seconds. You could explicitly create a FormControl object that would tie into the combined form validation but would not be associated with a DOM element.

See also

  • Implementing simple two-way data binding with ngModel demonstrates the new way in Angular 2 to control bidirectional data flow
  • Bundling FormControls with a FormGroup shows how to combine FormControl objects
  • Bundling FormControls with a FormArray shows how to handle iterable form elements
Назад: Implementing simple two-way data binding with ngModel
Дальше: Bundling controls with a FormGroup

thank you
Flame
cant read the code since it is all on a single line. Also this comments section is russian
Rakuneque
DATA COLLECTION AND ANALYSIS Two reviewers extracted data and assessed methodological quality independently lasix torsemide conversion Many others were in that space already