90 - Formularios reactivos - FormGroup anidados

Cuando trabajamos con formularios reactivos en Angular normalmente creamos un FormGroup para agrupar los controles visuales que se les asocian un objeto de la clase FormControl a cada uno.

Podemos crear dentro de un FormGroup otro FormGroup que agrupe un conjunto de controles relacionados.

Problema

Confeccionar un formulario que permita cargar los siguientes datos de un alumno: dni, nombre, materia y sus tres notas. Agrupar las tres notas dentro de un FormGroup anidado al principal.

Al presionar un botón mostrar un mensaje si se encuentra aprobado (todas las notas mayores o iguales a 4)

  • Crearemos primero el proyecto:

    ng new proyecto058
    
  • Importamos la clase 'ReactiveFormModule' modificando el archivo 'app.module.ts':

    import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { ReactiveFormsModule } from '@angular/forms';
    
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        ReactiveFormsModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
    
    
  • Modificamos la vista de la componente que muestra el formulario reactivo (app.component.html):

    <form [formGroup]="formAlumno" (ngSubmit)="submit()">
      <p>Dni:
        <input type="text" formControlName="dni">
      </p>
      <p>Nombre:
        <input type="text" formControlName="nombre">
      </p>
      <div formGroupName="notas">
        <p>Primer nota:
          <input type="text" formControlName="nota1">
        </p>
        <p>Segunda nota:
          <input type="text" formControlName="nota2">
        </p>
        <p>Tercer nota:
          <input type="text" formControlName="nota3">
        </p>
      </div>
      <p><button type="submit">Confirmar</button></p>
    </form>
    <div>
      <p>Resultado:{{resultado}}</p>
    </div>
    

    Analizaremos este archivo en conjunto luego de presentar 'app.component.ts'

  • La clase asociada a la vista es (app.component.ts):

    import { Component } from '@angular/core';
    import { FormGroup, FormControl } from '@angular/forms';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      resultado!:string;
    
      formAlumno = new FormGroup({
        dni: new FormControl(''),
        nombre: new FormControl(''),
        notas: new FormGroup({
          nota1: new FormControl(''),
          nota2: new FormControl(''),
          nota3: new FormControl('')
        })
      });
    
      submit() {
        let nota1=parseInt(this.formAlumno.value.notas.nota1);
        let nota2=parseInt(this.formAlumno.value.notas.nota2);
        let nota3=parseInt(this.formAlumno.value.notas.nota3);
        if (nota1>=4 && nota2>=4 && nota3>=4)
          this.resultado="El alumno queda aprobado por esas notas";
        else
          this.resultado="El alumno no aprueba por esas notas";
      }
    
    }
    

    Creamos un objeto de la clase FormGroup y dentro de este otro objeto de la clase FormGroup que agrupa las tres notas:

      formAlumno = new FormGroup({
        dni: new FormControl(''),
        nombre: new FormControl(''),
        notas: new FormGroup({
          nota1: new FormControl(''),
          nota2: new FormControl(''),
          nota3: new FormControl('')
        })
      });
    

    Esto provoca en la vista que cuando asociemos las tres notas debemos agruparlas dentro de un etiqueta HTML que defina una propiedad 'formGroupName':

      <div formGroupName="notas">
        <p>Primer nota:
          <input type="text" formControlName="nota1">
        </p>
        <p>Segunda nota:
          <input type="text" formControlName="nota2">
        </p>
        <p>Tercer nota:
          <input type="text" formControlName="nota3">
        </p>
      </div>
    

    Cuando se presiona el botón se verifica si las tres notas ingresadas son mayores o iguales a 4 para mostrar por pantalla si el alumno se encuentra aprobado o no:

      submit() {
        let nota1=parseInt(this.formAlumno.value.notas.nota1);
        let nota2=parseInt(this.formAlumno.value.notas.nota2);
        let nota3=parseInt(this.formAlumno.value.notas.nota3);
        if (nota1>=4 && nota2>=4 && nota3>=4)
          this.resultado="El alumno queda aprobado por esas notas";
        else
          this.resultado="El alumno no aprueba por esas notas";
      }
    

Si ejecutamos la aplicación tenemos una interfaz similar a:

Formularios reactivos angular ReactiveFormsModule FormControl FormGroup anidados

Podemos probar esta aplicación en la web aquí.