Reactive Forms Make Errors Not Show Up Again

  • Learning Objectives
  • Validators
  • Class Command State
    • Muddied & Pristine
    • Touched & Untouched
    • Valid & Invalid
  • Validation Styling
    • Writing Shorter Validation Expressions
  • Validation Messages
  • Summary
  • List

Learning Objectives

  • How to add validation checks to our form via the form model.

  • How tostyle our form in lodge to requite visual feedback to the user and then they know when the fields don't laissez passer the validation checks.

  • How to add validation error messages to the form to requite hints to the user about why the field isn't passing a validation cheque.

Validators

Carrying on from the model-driven form we started in the previous lecture.

Our form is valid all the fourth dimension, regardless of what input the user types into the controls.

Validators are rules which an input control has to follow. If the input doesn't friction match the rule and so the command is said to exist invalid.

Since it's a signup form most of the fields should be required and I would want to specify some more complex validators on the countersign field to brand sure the user is entering a skillful potent password.

We tin can apply validators either by adding attributes to the template or by defining them on our FormControls in our model.

To stick to the theme of being model-driven we are going to add validators to the form model directly.

Angular comes with a small prepare of pre-built validators to match the ones we can ascertain via standard HTMLv attributes, namely required, minlegth, maxlength anddesign which we can access from theValidators module.

The first parameter of a FormControl constructor is the initial value of the command, we'll leave that as empty string. The 2nd parameter contains either a unmarried validator if we only want to apply one, or a list of validators if nosotros want to employ multiple validators to a single control.

Our model so looks something similar this:

                import { FormGroup, FormControl, Validators } from '@angular/forms'; . . . grade ModelFormComponent implements OnInit {   myform: FormGroup;    ngOnInit() {     myform = new FormGroup({         name: new FormGroup({             firstName: new FormControl('', Validators.required),                                    (i)                  lastName: new FormControl('', Validators.required),         }),         email: new FormControl('', [                                    (ii)                  Validators.required,             Validators.pattern("[^ @]*@[^ @]*")                                    (iii)                  ]),         password: new FormControl('', [             Validators.minLength(8),                                    (4)                  Validators.required         ]),         linguistic communication: new FormControl()                                    (5)                  });   } }              
1 Nosotros add a single required validator to mark this control as required.
2 We tin can also provide an array of validators.
3 We specify a blueprint validator which checks whether the email contains a@ character.
iv Theminlength validator checks to see if the countersign is a minimum of eight characters long.
five We don't add whatever validators to the language select box.

Form Command Land

The form command instance on our model encapsulates state most the control itself, such as if it is currently valid or if it'due south been touched.

Dirty & Pristine

We can go a reference to these form command instances in our template through thecontrols property of our myform model, for case we can impress out the the dingy state of the email field like then:

                  <pre>Dingy? {{ myform.controls.email.dirty }}</pre>                

dirty is true if the user has changed the value of the control.

The opposite ofdingy is pristine and then if we wrote:

                  <pre>Pristine? {{ myform.controls.e-mail.pristine }}</pre>                

This would be true if the user hasn't changed the value, andfalse if the user has.

Touched & Untouched

A controls is said to be touched if the the user focused on the control and then focused on something else. For example by clicking into the control and then pressing tab or clicking on another control in the grade.

The difference between touched anddirty is that with touched the user doesn't need to really modify the value of the input control.

                  <pre>Touched? {{ myform.controls.email.touched }}</pre>                

touched is true of the field has been touched by the user, otherwise information technology's false.

The opposite oftouched is the property untouched.

Valid & Invalid

We can also cheque thevalid country of the control with:

                  <pre>Valid? {{ myform.controls.email.valid }}</pre>                

valid is true of the field doesn't take any validators or if all the validators are passing.

Again the opposite ofvalid is invalid, so we could write:

                  <pre>Invalid? {{ myform.controls.email.invalid }}</pre>                

This would be true if the command was invalid andsimulated if it was valid.

Validation Styling

Bootstrap has classes for showing visual feedback for grade controls when they are invalid.

For instance if nosotros add thehas-danger class to the parent div of the input control with the class ofclass-group it adds ared border.

Conversely if we add thehas-success class it adds agreenish border.

Form Valid

Figure 1. Valid Form Control

Form Invalid

Effigy 2. Invalid Grade Control

Nosotros tin can combine Bootstrap classes with dirty andinvalid FormControl properties and the ngClass directive to give the user some nice visual feedback, like so:

                <div grade="form-group" [ngClass]="{   'has-danger': myform.controls.electronic mail.invalid && myform.controls.e-mail.dirty,                                    (i)                  'has-success': myform.controls.email.valid && myform.controls.email.dirty                                    (ii)                  }">              
one If the e-mail is invalid and information technology'south been touched by the user then we add thehas-danger grade giving the control a red border.
2 If the email is valid and it's been touched past the user and so nosotros add together thehas-success class giving the control a light-green border.

Tip

The reason we bank check for the dingy holding being true is so we don't show the user visual feedback when the form is first displayed. Instead we only prove the user feedback when they have had a chance to edit the field.

Now the input command shows thedark-green border when it'southward valid anddirty andcarmine if it's invalid anddirty.

Writing Shorter Validation Expressions

The above can chop-chop get cumbersome to use in our templates, especially for things like the nested firstName andlastName controls.

Since thefirstName andlastName FormControls exist under thename FormGroup to admission those from the template we need to utilise syntax like this:

                  <div class="form-group"        [ngClass]="{         'has-danger': myform.controls.name.controls.firstName.invalid && myform.controls.name.controls.firstName.dirty,         'has-success': myform.controls.proper noun.controls.firstName.valid && myform.controls.proper name.controls.firstName.dirty }">                

The length of the expression apace becomes unwieldy.

We can help ourselves here by creating local properties on our component to reflect the individual FormControls and binding directly to them in our template, like so:

List 1. script.ts

                    class ModelFormComponent implements OnInit {   langs: string[] = [     'English language',     'French',     'German',   ];   myform: FormGroup;   firstName: FormControl;                                            (1)                      lastName: FormControl;   email: FormControl;   countersign: FormControl;   linguistic communication: FormControl;    ngOnInit() {     this.createFormControls();     this.createForm();   }    createFormControls() {                                            (2)                      this.firstName = new FormControl('', Validators.required);     this.lastName = new FormControl('', Validators.required);     this.e-mail = new FormControl('', [       Validators.required,       Validators.blueprint("[^ @]*@[^ @]*")     ]);     this.countersign = new FormControl('', [       Validators.required,       Validators.minLength(8)     ]);     this.language = new FormControl('', Validators.required);   }    createForm() {                                            (3)                      this.myform = new FormGroup({       name: new FormGroup({         firstName: this.firstName,         lastName: this.lastName,       }),       email: this.email,       password: this.countersign,       language: this.language     });   } }                  
1 We declare theFormControls as properties of our component. Then we can bind to them straight in our tempalte without having to get through the peak-level myform model.
2 We first create theFormControls.
3 We then construct themyform model from the course controls we created previously and stored every bit properties on our component.

Now we can bind straight to our individual class controls in our template without having to traverse the tree from themyform instance.

We can therefore re-write thewordy firstName ngClass expression to something much more than succinct, like so:

                  <div class="grade-group"  [ngClass]="{   'has-danger': firstName.invalid && firstName.dirty,   'has-success': firstName.valid && firstName.muddy }">                

Validation Messages

Equally well as styling a form when information technology'south invalid it's likewise useful to show the user mistake messages with helpful hints about how they can make the course valid again.

Taking what we accept learnt about form validation styling we tin can utilize the same method to conditionally show or hide an mistake bulletin.

Bootstrap conveniently has some markup and classes for form controls which we can use to show these error letters, allow's add them to our countersign form command, similar then:

                <div grade="grade-group">   <label>Password</label>   <input blazon="password"          class="class-control"          formControlName="countersign">   <div class="form-control-feedback"                                    (i)                  *ngIf="countersign.invalid && password.dirty">                                    (2)                  Field is invalid   </div> </div>              
  1. The class class-control-feedback shows a message in reddish if the parent form-group div also has thehas-danger course, i.due east. when the field is invalid whatever text under this div will show as red.

  2. We only evidence the message when the countersign field is both invalid andmuddy.

At present when the input control is both dirty andinvalid we show the validation error message "Field is invalid".

Notwithstanding this field has two validators associated with information technology, the required validator and the minlength validator but with the above solution nosotros just show one generic validation error message. We can't tell the user what they need to exercise in order to make the field valid.

How to do we show a split validation error message for each of the validators?

Nosotros can do that past checking another property on our form control called errors.

This is an object which has one entry per validator, the cardinal is the proper noun of the validator and if the value is not zippo so the validator is failing.

                <div class="form-control-feedback" *ngIf="password.errors && (password.dirty || password.touched)">   <p *ngIf="countersign.errors.required">Countersign is required</p>   <p *ngIf="password.errors.minlength">Password must be 8 characters long</p> </div>              

Note

If theerrors object has a key ofrequired it means the command is failing because it'southward required and the user hasn't entered any value into the input field.

Digging a chip deeper into theerrors property. The value tin can contain useful bits of information which we tin can testify the user, for example theminlength validator gives us therequiredLength andactualLength properties.

                {   "minlength": {     "requiredLength": 8,     "actualLength": 1   } }              

We can use this in our validation mistake message to give the user a bit more than assistance in resolving the upshot, like so:

                <div class="form-control-feedback"      *ngIf="password.errors && (password.muddy || password.touched)">   <p *ngIf="countersign.errors.required">Countersign is required</p>   <p *ngIf="countersign.errors.minlength">Countersign must be 8 characters long, we need another {{password.errors.minlength.requiredLength - password.errors.minlength.actualLength}} characters </p> </div>              

password validation messages

Effigy 3. Course Validation Letters

Summary

We tin add together validators to our model form which check each field for validity.

Tin can render the controls with styling to show the user when fields are invalid.

Finally, we tin add validation error messages so the user knows how to make the form valid again.

Side by side up we'll look at how to submit and reset a model-driven form.

Listing

Listing ii. primary.ts

                import {     NgModule,     Component,     Pipe,     OnInit } from '@angular/core'; import {     ReactiveFormsModule,     FormsModule,     FormGroup,     FormControl,     Validators,     FormBuilder } from '@angular/forms'; import {BrowserModule} from '@athwart/platform-browser'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';   @Component({   selector: 'model-form',   template: `   <div form="container">   <form novalidate       [formGroup]="myform">    <fieldset formGroupName="name">     <div form="form-group"          [ngClass]="{         'has-danger': firstName.invalid && (firstName.muddied || firstName.touched),         'has-success': firstName.valid && (firstName.muddied || firstName.touched)       }">       <label>First Name</label>       <input type="text"              form="form-control"              formControlName="firstName"              required>       <div class="class-control-feedback"            *ngIf="firstName.errors && (firstName.dirty || firstName.touched)">         <p *ngIf="firstName.errors.required">First Name is required</p>       </div>        <!--         <pre>Valid? {{ myform.controls.name.controls.firstName.valid }}</pre>         <pre>Dirty? {{ myform.controls.proper name.controls.firstName.dirty }}</pre>       -->     </div>      <div class="course-group"          [ngClass]="{         'has-danger': lastName.invalid && (lastName.muddy || lastName.touched),         'has-success': lastName.valid && (lastName.muddy || lastName.touched)       }">       <label>Last Proper noun</characterization>       <input type="text"              form="class-control"              formControlName="lastName"              required>       <div course="grade-control-feedback"            *ngIf="lastName.errors && (lastName.dirty || lastName.touched)">         <p *ngIf="lastName.errors.required">Last Name is required</p>       </div>     </div>   </fieldset>     <div course="grade-group"        [ngClass]="{         'has-danger': electronic mail.invalid && (email.dirty || email.touched),         'has-success': email.valid && (email.dirty || email.touched)    }">     <label>Email</label>     <input type="email"            class="form-control"            formControlName="email"            required>     <div course="form-control-feedback"          *ngIf="email.errors && (email.dirty || email.touched)">       <p *ngIf="email.errors.required">E-mail is required</p>       <p *ngIf="password.errors.pattern">The email accost must contain at least the @ graphic symbol</p>     </div>      <!--       <pre>Valid? {{ myform.controls.email.valid }}</pre>       <pre>Dirty? {{ myform.controls.e-mail.dirty }}</pre>     -->    </div>    <div grade="grade-group"        [ngClass]="{         'has-danger': password.invalid && (password.muddy || password.touched),         'has-success': password.valid && (countersign.dirty || password.touched)    }">     <label>Password</characterization>     <input type="password"            class="form-control"            formControlName="password"            required>     <div class="form-command-feedback"          *ngIf="password.errors && (password.dirty || password.touched)">       <p *ngIf="countersign.errors.required">Countersign is required</p>       <p *ngIf="password.errors.minlength">Countersign must be eight characters long, we demand another {{password.errors.minlength.requiredLength - password.errors.minlength.actualLength}} characters </p>     </div>   </div>    <!--     <pre>{{ countersign.errors | json }}</pre>   -->    <div grade="form-group"        [ngClass]="{         'has-danger': language.invalid && (linguistic communication.dirty || linguistic communication.touched),         'has-success': language.valid && (language.dirty || language.touched)       }">     <label>Language</label>     <select class="class-control"             formControlName="language">       <option value="">Please select a language</option>       <pick *ngFor="let lang of langs"               [value]="lang">{{lang}}       </option>     </select>   </div>    <pre>{{myform.value | json}}</pre> </form> </div>` }) course ModelFormComponent implements OnInit {   langs: string[] = [     'English',     'French',     'German',   ];   myform: FormGroup;   firstName: FormControl;   lastName: FormControl;   email: FormControl;   password: FormControl;   linguistic communication: 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.blueprint("[^ @]*@[^ @]*")     ]);     this.password = new FormControl('', [       Validators.required,       Validators.minLength(eight)     ]);     this.language = new FormControl('');   }    createForm() {     this.myform = new FormGroup({       proper name: new FormGroup({         firstName: this.firstName,         lastName: this.lastName,       }),       e-mail: this.email,       password: this.password,       language: this.language     });   } }   @Component({   selector: 'app',   template: `<model-form></model-form>` }) class AppComponent { }   @NgModule({   imports: [     BrowserModule,     FormsModule,     ReactiveFormsModule],   declarations: [     AppComponent,     ModelFormComponent   ],   bootstrap: [     AppComponent   ], }) form AppModule { }  platformBrowserDynamic().bootstrapModule(AppModule);              

frymanhusbad.blogspot.com

Source: https://codecraft.tv/courses/angular/forms/model-driven-validation/

0 Response to "Reactive Forms Make Errors Not Show Up Again"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel