29 June 2019
Angular (16) -- Template Driven Forms
by Jerry Zhang
Day 24: Template Driven Forms
Register the Form controls
To make Angular take over a form element, e.g. an Input, we need to add ngModel
and a name
for this input. Then,
this part of the form is under control of Angular.
<input
type="text"
id="username"
class="form-control"
ngModel
name="username"
>
Make the form submittable
Use the (ngSubmit)
directive on the form tag, instead of some buttons.
<form (ngSubmit)="onSubmit()">
To get the content in the form that we submit, we need to tag this form as ngForm
and pass it to the onSubmit()
method.
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
onSubmit(form: NgForm) {
console.log(form);
}
Then, if we open the console, we can see that there are many properties in the submitted NgForm Object, including the
value
.
-
Dirty: we have changed something in the form.
-
touched: we have clicked something in the form, not necessarily changed anything.
-
valid: this form is valid.
Accessing the Form with @ViewChild
We do not have to pass the f
in the method. Instead, we can use ViewChild.
<form (ngSubmit)="onSubmit()" #f="ngForm">
export class AppComponent {
@ViewChild('f', { static: false }) signUpForm: NgForm;
// onSubmit(form: NgForm) {
// console.log(form);
// }
onSubmit() {
console.log(this.signUpForm);
}
}
This gives the access to the very same form without passing it to onSubmit
.
This is useful if you need to access the form before submitting it.
Input Validation
- We can add a
required
attribute in the input element.
<input
type="text"
id="username"
class="form-control"
ngModel
name="username"
required
>
Then when we submit it, we can see in the console that the valid is true only this field is not empty. It tracks this on a per-control level, as well as the form level.
- email: email is an Angular directive that can validate an input is a valid email address.
<input
type="email"
id="email"
class="form-control"
ngModel
name="email"
required
email
#email="ngModel"
>
Additionally, you might also want to enable HTML5 validation (by default, Angular disables it). You can do so by adding the ngNativeValidate
to a control in your template.
- We can make the submit button disabled whenever the form is invalid.
<button
class="btn btn-primary"
type="submit"
[disabled]="!f.valid">Submit</button>
- We can also take advantage of the form state for CSS style.
input.ng-invalid.ng-touched {
border: 1px solid red;
}
- We can display some message after the invalid inputs.
<input
type="email"
id="email"
class="form-control"
ngModel
name="email"
required
email
#email="ngModel"
>
<span class="help-block" *ngIf="!email.valid && email.touched">Please enter a valid email!</span>
Here, we get a reference of the email input.
Default Values with ngModel
Change ngModel
to a property binding, and set value for it.
<select
id="secret"
class="form-control"
[ngModel]="defaultQuestion"
name="secret"
>
<option value="pet">Your first Pet?</option>
<option value="teacher">Your first teacher?</option>
</select>
defaultQuestion = 'pet';
Two-way-binding ngModel
<div class="form-group">
<textarea
name="questionAnswer"
rows="3"
class="form-control"
[(ngModel)]="answer"
></textarea>
</div>
<p>Your reply: </p>
Grouping Form Controls with ngModelGroup
We add a wrapping div on the elements that we want to group together, and add ngModelGroup
directive.
ngModelGroup
needs to be set up as a string, for example, “userData”. This will be the key name for this group.
<div
id="user-data"
ngModelGroup="userData"
#userData="ngModelGroup">
We have the whole control of this group.
Radio Buttons
<div class="radio" *ngFor="let gender of genders">
<label>
<input
type="radio"
name="gender"
ngModel
[value]="gender"
required
>
</label>
</div>
Setting and Patching Form Values with viewChild
Use the setValue()
method of the viewChild property we set up before. Here we need to pass a JavaScript object
representing our form.
@ViewChild('f', { static: false }) signUpForm: NgForm;
suggestUserName() {
const suggestedName = 'Superuser';
this.signUpForm.setValue({
userData: {
username: suggestedName,
email: ''
},
secret: 'pet',
questionAnswer: '',
gender: 'male'
});
}
Then we can bind a button with this method.
However, this approach does have one downside. If we already had some value in the form, clicking this button will overwrite all the values.
We can actually patch one single value via the form
attribute inside the signUpForm
object.
suggestUserName() {
const suggestedName = 'Superuser';
this.signUpForm.form.patchValue({
userData: {
username: suggestedName
}
});
}
Resetting Forms
this.signUpForm.reset();
It’s like the whole form was loaded again. Very helpful.
tags: Angular