Formularios Angular 2

En este capítulo presentaremos cómo construir un formulario Angular utilizando componentes y plantillas.

Con las plantillas de Angular, podemos crear varios tipos de formularios, por ejemplo: formularios de inicio de sesión, formularios de contacto, formularios de detalles de productos, etc., y también añadimos validación de datos para los campos de estos formularios.

A continuación, implementaremos las funciones del formulario paso a paso.


Crear proyecto

Importar el proyecto inicial.

Puedes consultar la creación completa del proyecto en:Configuración del entorno TypeScript de Angular 2

O descarga directamente el código fuente:Haz clic para descargar

Después de descomprimir, cambia el nombre del directorio a angular-forms y modifica el archivo angular-forms/package.json en"name": "angular-quickstart"Para"name": "angular-forms"。

Cuando termines, ejecutamoscnpm installpara cargar los paquetes de dependencias.

Crear el modelo Site

A continuación se crea una clase de modelo simple Site, que contiene tres campos obligatorios: id, name, url, y un campo opcional: alexa.

Crea el archivo site.ts en el directorio angular-forms/app, el código es el siguiente:

Archivo app/site.ts:

export class Site { constructor( public id: number, public name: string, public url: string, public alexa?: number ) { } }

En el siguiente código, los marcados como public son campos públicos; agregar un signo de interrogación (?) después de alexa indica que es un campo opcional.

Crear un componente de formulario

Cada formulario Angular se divide en dos partes: una plantilla basada en HTML y un componente basado en código, que se utiliza para manejar los datos y la interacción del usuario.

Crea el archivo site-form.component.ts en el directorio angular-forms/app, el código es el siguiente:

Archivo app/site-form.component.ts:

import { Component } from '@angular/core'; import { Site } from './site'; @Component({ moduleId: module.id, selector: 'site-form', templateUrl: 'site-form.component.html' }) export class SiteFormComponent { urls = ['www.example.com', 'www.google.com', 'www.taobao.com', 'www.facebook.com']; model = new Site(1, 'Ejemplo', this.urls[0], 10000); submitted = false; onSubmit() { this.submitted = true; } //TODO: eliminar después de completar get diagnostic() { return JSON.stringify(this.model); } }

En el ejemplo se importan el decorador Component y el modelo Site.

El selector @Component "site-form" indica que podemos, mediante una<site-form>etiqueta, insertar este formulario en la plantilla padre.

La propiedad templateUrl apunta a un archivo de plantilla HTML independiente llamado site-form.component.html.

La propiedad diagnostic se utiliza para devolver la forma JSON de este modelo.

Definir el módulo raíz de la aplicación

Modifica app.module.ts para definir el módulo raíz de la aplicación. En el módulo se especifican las referencias externas y se declaran los componentes que pertenecen a este módulo, como SiteFormComponent.

Debido a que los formularios basados en plantillas tienen su propio módulo, debemos agregar FormsModule a la matriz imports de la aplicación para poder usar formularios.

El código del archivo app/app.module.ts es el siguiente

Archivo app/app.module.ts:

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { SiteFormComponent } from './site-form.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, SiteFormComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }

Crear el componente raíz

Modifica el archivo del componente raíz app.component.ts y coloca SiteFormComponent en él.

Archivo app/app.component.ts:

import { Component } from '@angular/core'; @Component({ selector: 'my-app', template: '<site-form></site-form>' }) export class AppComponent { }

Crear una plantilla de formulario HTML inicial

Crea el archivo de plantilla site-form.component.html, el código se muestra a continuación:

Archivo app/site-form.component.html:

<div class="container"> <h1>Formulario de sitio web</h1> <form> <div class="form-group"> <label for="name">Nombre del sitio</label> <input type="text" class="form-control" id="name" required> </div> <div class="form-group"> <label for="alexa">Ranking Alexa</label> <input type="text" class="form-control" id="alexa"> </div> <button type="submit" class="btn btn-default">Enviar</button> </form> </div>

El atributo required establece que el campo es obligatorio; si no se establece, es opcional.

En el directorio angular-forms, ejecuta el siguiente comando:

cnpm install bootstrap --save

Abre el archivo index.html y agrega los siguientes enlaces de estilo a <head>:

<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">

Ejecutanpm startDespués, visita: http://localhost:3000/, el resultado se muestra a continuación:


Usar ngModel para el enlace de datos bidireccional

A continuación, usaremos ngModel para el enlace de datos bidireccional, escuchando eventos DOM para actualizar las propiedades del componente.

Modifica app/site-form.component.html, usa ngModel para vincular nuestro formulario al modelo. El código se muestra a continuación:

Archivo app/site-form.component.html:

<div class="container"> <h1>Formulario de sitio web</h1> <form> {{diagnostic}} <div class="form-group"> <label for="name">Nombre del sitio</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name"> </div> <div class="form-group"> <label for="alexa">Ranking Alexa</label> <input type="text" class="form-control" id="alexa" [(ngModel)]="model.alexa" name="alexa"> </div> <div class="form-group"> <label for="url">URL del sitio</label> <select class="form-control" id="url" required [(ngModel)]="model.url" name="url"> <option *ngFor="let p of urls" [value]="p">{{p}}</option> </select> </div> <button type="submit" class="btn btn-default">Enviar</button> </form> </div>
  • Cada elemento input tiene un atributo id, que es utilizado por el atributo for del elemento label para vincular la etiqueta con el input correspondiente.

  • Cada elemento input tiene un atributo name; el módulo de formularios de Angular lo necesita para registrar el control del formulario.

Ejecuta el ejemplo anterior, el resultado es el siguiente:

{{diagnostic}} Solo se usa para mostrar datos durante las pruebas.

También podemos usar ngModel para rastrear el estado de modificación y la validación. Utiliza tres clases CSS para actualizar los controles y reflejar el estado actual.

Estado Clase cuando es true Clase cuando es false
El control ha sido visitado ng-touched ng-untouched
El valor del control ha cambiado ng-dirty ng-pristine
El valor del control es válido ng-valid ng-invalid

De esta manera podemos agregar CSS personalizado para reflejar el estado del formulario.

Crea el archivo forms.css en el directorio angular-forms, el código es el siguiente:

Archivo forms.css:

.ng-valid[required], .ng-valid.required { border-left: 5px solid #4276A9; /* green */ } .ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */ }

Abre el archivo index.html y agrega los siguientes enlaces de estilo a <head>:

<link rel="stylesheet" href="forms.css">

Modifica app/site-form.component.html, el código se muestra a continuación:

Archivo app/site-form.component.html:

<div class="container"> <h1>Formulario de sitio web</h1> <form> {{diagnostic}} <div class="form-group"> <label for="name">Nombre del sitio</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel" > <div [hidden]="name.valid || name.pristine" class="alert alert-danger">El nombre del sitio es obligatorio</div> </div> <div class="form-group"> <label for="alexa">Ranking Alexa</label> <input type="text" class="form-control" id="alexa" [(ngModel)]="model.alexa" name="alexa"> </div> <div class="form-group"> <label for="url">URL del sitio</label> <select class="form-control" id="url" required [(ngModel)]="model.url" name="url"> <option *ngFor="let p of urls" [value]="p">{{p}}</option> </select> </div> <button type="submit" class="btn btn-default">Enviar</button> </form> </div>

En la plantilla, al vincular el atributo hidden del elemento div a una propiedad del control name, podemos controlar la visibilidad del mensaje de error del campo "name".

Elimina los datos del campo name, el resultado se muestra a continuación:

Añadir un sitio web

A continuación, crearemos un formulario para añadir sitios web. Agrega un botón en app/site-form.component.html:

Archivo app/site-form.component.html:

<button type="button" class="btn btn-default" (click)="newSite()">Añadir sitio web</button>

Vincula el evento del botón anterior a un método del componente:

Archivo app/site-form.component.ts:

active = true; newSite() { this.model = new Site(5, '', ''); this.active = false; setTimeout(() => this.active = true, 0); }

Añadimos un marcador `active` al componente y lo inicializamos como `true`. Cuando añadimos un nuevo sitio web, establece el marcador `active` como `false`, y luego, mediante una rápida función `setTimeout`, lo vuelve a establecer como `true`.

Enviar el formulario mediante ngSubmit

Podemos usar la directiva `NgSubmit` de Angular para enviar el formulario y, mediante el mecanismo de enlace de eventos, vincularla al método `SiteFormComponent.submit()`.

<form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm">

Definimos una variable de referencia de plantilla `#siteForm` y la inicializamos como `"ngForm"`.

Esta variable `siteForm` ahora hace referencia a la directiva `NgForm`, que representa el formulario en su totalidad.

El código completo del archivo `site-form.component.ts` es el siguiente:

Archivo app/site-form.component.ts:

import { Component } from '@angular/core'; import { Site } from './site'; @Component({ moduleId: module.id, selector: 'site-form', templateUrl: 'site-form.component.html' }) export class SiteFormComponent { urls = ['www.example.com', 'www.google.com', 'www.taobao.com', 'www.facebook.com']; model = new Site(1, 'Tutorial Ejemplo', this.urls[0], 10000); submitted = false; onSubmit() { this.submitted = true; } //TODO: eliminar al terminar get diagnostic() { return JSON.stringify(this.model); } active = true; newSite() { this.model = new Site(5, '', ''); this.active = false; setTimeout(() => this.active = true, 0); } }

El código completo de `app/site-form.component.html` es el siguiente:

Archivo app/site-form.component.html:

<div class="container"> <div [hidden]="submitted"> <h1>Formulario de sitio web</h1> <form *ngIf="active" (ngSubmit)="onSubmit()" #siteForm="ngForm"> {{diagnostic}} <div class="form-group"> <label for="name">Nombre del sitio web</label> <input type="text" class="form-control" id="name" required [(ngModel)]="model.name" name="name" #name="ngModel" > <div [hidden]="name.valid || name.pristine" class="alert alert-danger">El nombre del sitio web es obligatorio</div> </div> <div class="form-group"> <label for="alexa">Ranking Alexa</label> <input type="text" class="form-control" id="alexa" [(ngModel)]="model.alexa" name="alexa"> </div> <div class="form-group"> <label for="url">URL del sitio web</label> <select class="form-control" id="url" required [(ngModel)]="model.url" name="url"> <option *ngFor="let p of urls" [value]="p">{{p}}</option> </select> </div> <button type="submit" class="btn btn-default" [disabled]="!siteForm.form.valid">Enviar</button> <button type="button" class="btn btn-default" (click)="newSite()">Añadir sitio web</button> </form> </div> <div [hidden]="!submitted"> <h2>La información que ha enviado es la siguiente:</h2> <div class="row"> <div class="col-xs-3">Nombre del sitio web</div> <div class="col-xs-9 pull-left">{{ model.name }}</div> </div> <div class="row"> <div class="col-xs-3">Ranking Alexa del sitio web</div> <div class="col-xs-9 pull-left">{{ model.alexa }}</div> </div> <div class="row"> <div class="col-xs-3">URL del sitio web</div> <div class="col-xs-9 pull-left">{{ model.url }}</div> </div> <br> <button class="btn btn-default" (click)="submitted=false">Editar</button> </div> </div>

En la plantilla vinculamos el atributo `hidden` a la propiedad `SiteFormComponent.submitted`.

El formulario principal es visible desde el principio porque la propiedad `submitted` es `false`; cuando enviamos el formulario, se oculta y la propiedad `submitted` es `true`:

submitted = false; onSubmit() { this.submitted = true; }

La estructura de directorios final es:

El código fuente utilizado en este artículo se puede descargar mediante el siguiente enlace, sin incluir los directorios `node_modules` y `typings`.

Descargar código fuente

La demostración completa en GIF es la siguiente:

Otras extensiones