Building a Basic Form
<form>
<div class="form-group">
<label for="firstName">First Name</label>
<input id="firstName" type="text" class="form-control">
</div>
<div class="form-group">
<label for="comment">Comment</label>
<textarea id="comment" cols="30" rows="10" class="form-control"></textarea>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
Control and ControlGroup
Now Want to upgrade form into an angular form
Control class represents a single input field, whether value, touched, untouched, dirty, pristine, valid, errors
Control Group represents a group of controls in a form
Form can contain multiple contorl group e.g. shipping address and billing address
Accessing each control group is easier than iterating through each individual controls in the group
Both Control and ControlGroup inherit from base class AbstractControl
Two ways to create control objects. Implicit and Explicit
Explicit has more contorl over validation logic - and unit test them. Comes with downside that need to write more code. Both are fine, depending on our scenario
WE will explore implicit creation.
ngControl
<form>
<div class="form-group">
<label for="firstName">First Name</label>
<!-- implicit creation of Control objects
#firstName is temporary variable
-->
<input ngControl="firstName"
#firstName="ngForm"
id="firstName"
type="text"
class="form-control">
</div>
<div class="form-group">
<label for="comment">Comment</label>
<!-- ngControl and id identifier no relationship-->
<textarea ngControl="comment" id="comment" cols="30" rows="10" class="form-control"></textarea>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
- required
- minlength
- maxlength
<form>
<div class="form-group">
<label for="firstName">First Name</label>
<!-- implicit creation of Control objects
#firstName is temporary variable
-->
<input
ngControl="firstName"
#firstName="ngForm"
id="firstName"
type="text"
class="form-control"
required>
<!-- display validation error-->
<div class="alert alert-danger"
*ngIf="firstName.touched && !firstName.valid ">
First name is required
</div>
</div>
<div class="form-group">
<label for="comment">Comment</label>
<!-- ngControl and id identifier no relationship-->
<textarea
#comment="ngForm"
ngControl="comment"
id="comment"
cols="30"
rows="10"
class="form-control"
required>
</textarea>
<div *ngIf="comment.touched && !comment.valid"
class="alert alert-danger">Comment is required.</div>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
styles.css
.ng-touched.ng-invalid{
border: 1px solid red;
}
but how do I know .ng-touched.ng-invalid?
Check Chrome developer tools
Before i fill in the input field
<input class="form-control ng-untouched ng-pristine ng-invalid" id="firstName" ngcontrol="firstName" required="" type="text" ng-reflect-name="firstName">
When input field is touched and empty
<input class="form-control ng-touched ng-dirty ng-invalid" id="firstName" ngcontrol="firstName" required="" type="text" ng-reflect-name="firstName">
When input field is filled
<input class="form-control ng-touched ng-dirty ng-valid" id="firstName" ngcontrol="firstName" required="" type="text" ng-reflect-name="firstName">
Showing Specific Validation Errors
What if an input field need multiple validation?
e.g. input field is not only required but need at least three characters
<div class="form-group">
<label for="firstName">First Name</label>
<!-- implicit creation of Control objects
#firstName is temporary variable
-->
<input
ngControl="firstName"
#firstName="ngForm"
id="firstName"
type="text"
class="form-control"
required
minlength="3">
<!-- display validation error-->
<div *ngIf="firstName.touched && firstName.errors">
<div class="alert alert-danger"
*ngIf="firstName.errors.required">
First name is required
</div>
<div class="alert alert-danger"
*ngIf="firstName.errors.minlength">
First name should be minimum 3 characters.
</div>
</div>
</div>
But should we hardcode '3'?
<div *ngIf="firstName.touched && firstName.errors">
<div class="alert alert-danger"
*ngIf="firstName.errors.required">
First name is required
</div>
<div class="alert alert-danger"
*ngIf="firstName.errors.minlength">
First name should be minimum {{firstName.errors.minlength.requiredLength}} characters.
</div>
</div>
But how do we know its minlength.requiredLength?
{{firstName.errors | json}}
For e.g.
<div *ngIf="firstName.touched && firstName.errors">
{{firstName.errors | json}}
<div class="alert alert-danger"
*ngIf="firstName.errors.required">
First name is required
</div>
<div class="alert alert-danger"
*ngIf="firstName.errors.minlength">
First name should be minimum {{firstName.errors.minlength.requiredLength}} characters.
</div>
</div>
output
{ "minlength": { "requiredLength": 3, "actualLength": 1 } }
Therefore {{firstName.errors.minlength.requiredLength}}
ngForm
ngForm binds entire form to ControlGroup object.
<form #f="ngForm" (ngSubmit)="onSubmit(f.form)">
contact-form.component.ts
@Component({
selector: 'contact-form',
templateUrl: 'app/contact-form.component.html'
})
export class ContactFormComponent {
onSubmit(form){
// call server api
console.log(form);
}
}
Disabling Submit Button
<button class="btn btn-primary" type="submit" [disabled]="!f.valid">Submit</button>
Extended form with dropdown
contact-form.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'contact-form',
templateUrl: 'app/contact-form.component.html'
})
export class ContactFormComponent {
frequencies = [
{ id: 1, label: 'Daily' },
{ id: 2, label: 'Weekly' },
{ id: 3, label: 'Monthly' }
];
onSubmit(form){
// call server api
console.log(form);
}
}
Add below just before Submit button.
contact-form.component.html
<div class="form-group">
<label for="frequency">Frequency of emails</label>
<select
ngControl="frequency"
#frequency="ngForm"
id="frequency"
class="form-control"
required>
<option value=""></option>
<option *ngFor="#frequency of frequencies" value="{{ frequency.id }}">
{{ frequency.label }}
</option>
</select>
<div
class="alert alert-danger"
*ngIf="frequency.touched && !frequency.valid">
This field is required.
</div>
</div>
No comments:
Post a Comment