Angular has two ways to develop submit forms: one easier to use and the other freer but more powerful, for more intricate customizations.
Template-driven Form:
We can think this first type of form as a simple way to make forms for those that have not much time. We’ll use it for simple forms, how can be a sign-in one.

form-template-driven.component.ts 💾
import {Component} from '@angular/core';
import {NgForm} from "@angular/forms";
@Component({
selector: 'app-form-template-driven',
templateUrl: './form-template-driven.component.html',
styleUrls: ['./form-template-driven.component.scss']
})
export class FormTemplateDrivenComponent {
public username: string;
public password: string;
constructor() { }
public handleSubmit(f: NgForm): void {
console.log('NgForm: ', f);
if (f.invalid) {
return;
}
console.log(this.username + ' ' + this.password);
}
}
form-template-driven.component.html 💾
<form #f="ngForm" (ngSubmit)="handleSubmit(f)">
<div class="form-group">
<!-- username field -->
<label for="username">Username: </label>
<input #usr="ngModel" id="username" name="username"
[(ngModel)]="username" class="form-control" required minlength="3">
<div *ngIf="usr.touched">
<small *ngIf="usr.hasError('required')" class="text-danger">
Required field
</small>
<small *ngIf="usr.hasError('minlength')" class="text-danger">
At least 3 characters
</small>
</div>
<!-- password field -->
<label for="password">Password: </label>
<input #pwd="ngModel" type="password" id="password" name="password"
[(ngModel)]="password" class="form-control" required minlength="3">
<!-- submit button -->
<button type="submit" class="btn btn-primary" [disabled]="f.invalid">SEND</button>
</div>
</form>
Reactive Form:
We can think this second type of form as a complete and dinamic way to make forms with every type of custom validation and with much more control from Component. We’ll use it for complex forms, how can be a registration one.

form-reactive-driven.component.ts 💾
import { Component, OnInit } from '@angular/core';
import {AbstractControl, FormControl, FormGroup, Validators} from '@angular/forms';
import {rangeValidator} from "../../validators/range.validator";
@Component({
selector: 'app-form-reactive-driven',
templateUrl: './form-reactive-driven.component.html',
styleUrls: ['./form-reactive-driven.component.scss']
})
export class FormReactiveDrivenComponent implements OnInit {
public formGruppo: FormGroup;
constructor() {
this.formGruppo = new FormGroup({
username: new FormControl('', [
Validators.required,
Validators.minLength(3)
]),
numberInRange: new FormControl('', [
Validators.required,
rangeValidator(2, 10)
]),
});
}
ngOnInit() {
}
get username(): AbstractControl {
return this.formGruppo.get('username');
}
get numberInRange(): AbstractControl {
return this.formGruppo.get('numberInRange');
}
public handle(): void {
console.log('FormGroup: ', this.formGruppo);
if (this.formGruppo.invalid) {
return;
}
console.log(this.username);
}
}
form-reactive-driven.component.html 💾
<form [formGroup]="formGruppo" (ngSubmit)="handle()">
<div class="form-group">
<label for="username">Username:</label>
<input id="username" name="username" formControlName="username" class="form-control">
<div *ngIf="username.dirty">
<small *ngIf="username.hasError('required')">Required field</small>
<small *ngIf="username.hasError('minlength')">At least 3 characters</small>
</div>
<br>
<label for="numberInRange">numberInRange:</label>
<input id="numberInRange" name="numberInRange" formControlName="numberInRange"
class="form-control" type="number">
<div *ngIf="numberInRange.dirty">
<small *ngIf="numberInRange.hasError('range')">Not valid range</small>
</div>
<br>
<button class="btn btn-primary" type="submit">SEND</button>
</div>
</form>