In the template driven approach you define the form behaviour and configuration in the template: validators, and so on.
You can find a more detailed tutorial at: https://angular.dev/guide/forms/template-driven-forms#
We will start with this simple example made in ionic (but you can do in html exactly the same):
<ion-row>
<ion-col>
<ion-input name="jugadorName"
placeholder="Nombre"
autofocus="true"
inputmode="text"
autocorrect="off"
type="text"></ion-input>
</ion-col>
</ion-row>
<!-- begin rest of the fields -->
<form> <-- HERE
<ion-row>
<ion-col>
<ion-input name="jugadorName"
placeholder="Nombre"
autofocus="true"
inputmode="text"
autocorrect="off"
type="text"></ion-input>
</ion-col>
</ion-row>
Add "ngModel" to every control to make angular aware that your control forms part of your form. You don't need to use the two-way binding, it's not needed:
<form>
<ion-row>
<ion-col>
<ion-input name="jugadorName"
placeholder="Nombre"
autofocus="true"
inputmode="text"
autocorrect="off"
type="text"
ngModel></ion-input>
</ion-col>
</ion-row>
If it is necesary, you can use the two-way binding to link the value in the form with a property in your component's code:
<ion-input name="jugadorName"
placeholder="Nombre"
autofocus="true"
inputmode="text"
autocorrect="off"
type="text"
[(ngModel)]="jugadorName"></ion-input>
export class EditarComponent {
jugadorName: string;
import { FormsModule, ReactiveFormsModule } from "@angular/forms";
@NgModule({
imports: [
CommonModule,
IonicModule,
FormsModule,
AdminJugadoresRoutingModule],
declarations: [
EquipoPipe,
AdminJugadoresPage,
BuscarComponent,
EditarComponent
]
})
export class AdminJugadoresModule{ }
Like this:
<ion-input name="jugadorName"
placeholder="Nombre"
autofocus="true"
inputmode="text"
autocorrect="off"
type="text"
ngModel></ion-input>
<form #datosJugador="ngForm">
With this, we will get access to the form data in the component code. We have to assign it the special value "ngForm" to let angular know that it is a form of type NgForm, that it will be created and managed by Angular.
You can create a (ngSubmit)
event binding that will be triggered
when the form is submitted:
<form #datosJugador="ngForm" (ngSubmit)="onSubmit( datosJugador )">
At the same time in your component you have to program the
onSubmit
method:
public onSubmit( datosJugador: NgForm ){
}
You can add standard html validation attributes like:
- required
- email: to tell angular that this field is an email
- minlength: minimum length of the field
- min: minimum value -if the field accepts numeric inputs-
- max: maximum value -if the field accepts numeric inputs-
<ion-col>
<ion-checkbox name="jugadorEsPortero"
labelPlacement="end" [(ngModel)]="jugadorEsPortero">
<span *ngIf="jugadorEsPortero" style="color: red;">Si</span>
<span *ngIf="!jugadorEsPortero" style="color: gray;">No</span> juega como portero</ion-checkbox>
</ion-col>
In this case, jugadorEsPortero
will represent the
internal control Angular makes for the form control. This
way, you can check the value, or if it is valid, if it
has been touched, etc.
<ion-col>
<ion-checkbox name="jugadorEsPortero"
labelPlacement="end" ngModel #jugadorEsPortero="ngModel">
<span *ngIf="jugadorEsPortero.value" style="color: red;">Si</span>
<span *ngIf="!jugadorEsPortero.value" style="color: gray;">No</span> juega como portero</ion-checkbox>
</ion-col>
Angular sets many clases dynamically to help in notifiying the user if there are validation issues in the form's code:
- ng-invalid: is assigned to every control that is in an invalid state
- ng-valid: sets if the control becomes valid
- ng-untouched: when the control haven't been touched by the user yet
- ng-touched: everytime the control is touched
- ng-pristine: the control is like the first time showed (this class dissapears when the control is touched first)
- ng-dirty
We can use these classes to show visual aids to the user when a control becames invalid.
<ion-input name="jugadorName"
id="jugadorName"
#jugadorName="ngModel"
placeholder="Nombre"
autofocus="true"
inputmode="text"
autocorrect="off"
type="text"
ngModel
required></ion-input>
<ion-label for="jugadorName"
class="validation-helper"
*ngIf="jugadorName.touched && jugadorName.invalid">
Jugador es obligatorio</ion-label>
In the css class I've defined the validation-helper class as:
.validation-helper {
color: var(--ion-color-danger);
font-size: 0.75rem;
}
If you are planning to block the submit button in the case of some of the values are not valid, the best you can do is to show up under the save button specific messages about which of the controls are not valid:
@if(datosJugador.touched && !datosJugador.valid) {
<ion-row>
<ion-col>
<label for="btnSave" class="validation-helper">Algunos datos no son correctos:</label>
</ion-col>
</ion-row>
}
@if( jugadorName.touched && jugadorName.invalid ){
<ion-row>
<ion-col>
<label class="validation-helper">El nombre del jugador es un dato obligatorio</label>
</ion-col>
</ion-row>
}
Note: is convenient to add a more "generic" validation message also in the case that we have missing some of the validations: the user will still see a message "some data is incorrect" that gives it a hint about he problem despite our omission.
Given that we've named our form as datosJugador
:
<form #datosJugador="ngForm" (ngSubmit)="onSubmit( datosJugador )">
We can access programmatically to them by initializing it as viewchild:
private datosJugador = viewChild<NgForm>('datosJugador');
And then, we can use to set values:
public ngOnInit(): void {
console.log("on init");
setTimeout( () => {
this.datosJugador().setValue({
"jugadorName": "raul",
"jugadorSurname": "luna",
"jugadorGenero": "Masculino",
"jugadorEdad": 15,
"jugadorEsPortero": false,
"jugadorCategoria": ["Alevin"],
"jugadorTelefono": "",
"jugadorTipoTelefono": "Personal",
"jugadorEmail": null,
"jugadorNotas": null });
}, 1 );
}
The call to setTimeout
is needed because when calling the
first time the initialization, the form isn't fully initialized,
but if it is called as a callback function after just one millisecond,
will solve the problem.