Note
Para ver la versión de este proyecto utilizando Ionic/React, haz click aquí.
Ayudante: Sebastián García Delgadillo (@sgarciaddev).
Semestre: 1er/2024
Este proyecto contiene un ejemplo de aplicación de Ionic, utilizando Angular, donde se cubren 2 contenidos principales:
- Lectura de archivo JSON para cargar las regiones y comunas del país, dentro del formulario.
- Creación y validación de un formulario utilizando componentes de Ionic y conceptos de desarrollo en Angular.
Para ejecutar este proyecto, se debe clonar el repositorio y ejecutar los siguientes comandos en la terminal:
git clone -b angular https://github.com/sgarciaddev/ay-ingweb-ejemplo-form-ionic.git
cd ay-ingweb-ejemplo-form-ionic
npm install
ionic serve
Nombre archivo | Ruta completa | Descripción |
---|---|---|
formulario.module.ts |
src/app/formulario/formulario.module.ts |
Archivo de módulo de la página de formulario. |
Formulario.page.ts |
src/app/formulario/formulario.page.ts |
Archivo con la lógica de la página de formulario. Contiene toda la lógica de validación de formularios. |
Formulario.page.html |
src/app/formulario/formulario.page.html |
Archivo HTML de la página de formulario. Contiene la estructura del formulario. |
regiones.service.ts |
src/app/misc/regiones.service.ts |
Servicio de Angular para cargar las regiones y comunas del país. |
Form-errors.ts |
src/app/misc/form-errors.ts |
Archivo con los mensajes de error de los campos del formulario. |
Form-validations.ts |
src/app/misc/form-validators.ts |
Archivo con las funciones de validación de los campos del formulario. |
regiones-comunas.json |
src/assets/regiones-comunas.json |
Archivo JSON con la información de las regiones y comunas del país. |
Para la creaciónd de formularios utilizando Ionic y Angular, se deben seguir los siguientes pasos:
Primero hay que agregar las importaciones necesarias en los archivos de Angular, para poder trabajar con formularios. Esto lo hacemos de la siguiente manera:
- En el archivo de módulo del componente o página, se deben importar los módulos necesarios para trabajar con formularios. En este caso, se importaron los módulos
ReactiveFormsModule
yFormsModule
de Angular:
import { ReactiveFormsModule, FormsModule } from "@angular/forms";
- Luego, se deben agregar estos módulos al arreglo de
imports
del módulo:
@NgModule({
imports: [
...
FormsModule,
ReactiveFormsModule,
],
});
- En el archivo de componente o página, se deben importar las clases necesarias para trabajar con formularios. En este caso, se importaron las clases
FormGroup
,FormControl
,Validators
yFormBuilder
de Angular:
import { FormGroup, FormControl, Validators, FormBuilder } from "@angular/forms";
- Luego, se deben crear las instancias necesarias para trabajar con formularios. En este caso, se creó un atributo
formulario
de tipoFormGroup
en el componente:
@Component({
selector: 'app-formulario',
templateUrl: 'formulario.page.html',
})
export class FormularioPage {
formulario: FormGroup;
...
constructor(private fb: FormBuilder, private regionService: RegionesService) {
// Se inicializa el formulario con los campos requeridos y las validaciones
this.formulario = this.fb.group({
nombre: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(20)]],
apellido: ['', [Validators.required, Validators.minLength(3), Validators.maxLength(20)]],
rut: ['', [Validators.required, rutValidator]],
email: ['', [Validators.required, Validators.email]],
password: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(20)]],
passwordConfirm: ['', [Validators.required, passwordMatchValidator]],
region: ['', Validators.required],
comuna: [{value: '', disabled: true}, Validators.required],
tyc: [false, Validators.requiredTrue],
});
}}
En el ejemplo anterior, podemos ver que dentro del constructor del componente, se inicializa el formulario con los campos requeridos y las validaciones necesarias. En este caso, se utilizan las validaciones por defecto de Angular, como required
, minLength
, maxLength
, email
, entre otras. Además, se utilizan validaciones personalizadas, como rutValidator
y passwordMatchValidator
. Estas funciones se importan desde el archivo form-validators.ts
. Ya con esto configurado, podemos proceder a crear el formulario en el archivo HTML.
Luego se debe crear el formulario en el componente de Angular. Para esto, se deben utilizar los componentes de Ionic dedicados a formularios. Puedes verlos en la documentación oficial de Ionic. En este ejemplo, se creó el siguiente formulario:
<form [formGroup]="formulario" (ngSubmit)="onSubmit()">
<ion-item>
<ion-input
type="text"
formControlName="nombre"
labelPlacement="stacked"
[errorText]="formError('nombre')"
>
<div slot="label">Nombre <ion-text color="danger">(requerido)</ion-text></div>
</ion-input>
</ion-item>
<ion-item lines="none">
<ion-input
type="text"
formControlName="apellido"
labelPlacement="stacked"
[errorText]="formError('apellido')"
>
<div slot="label">Apellido <ion-text color="danger">(requerido)</ion-text></div>
</ion-input>
</ion-item>
<ion-item lines="none">
<ion-input
type="text"
formControlName="rut"
labelPlacement="stacked"
[errorText]="formError('rut')"
>
<div slot="label">RUT <ion-text color="danger">(requerido)</ion-text></div>
</ion-input>
</ion-item>
<ion-item lines="none">
<ion-input
type="email"
formControlName="email"
labelPlacement="stacked"
[errorText]="formError('email')"
>
<div slot="label">Email <ion-text color="danger">(requerido)</ion-text></div>
</ion-input>
</ion-item>
<ion-item lines="none">
<ion-input
type="password"
formControlName="password"
labelPlacement="stacked"
[errorText]="formError('password')"
>
<div slot="label">Contraseña <ion-text color="danger">(requerido)</ion-text></div>
<ion-input-password-toggle color="medium" slot="end"></ion-input-password-toggle>
</ion-input>
</ion-item>
<ion-item lines="none">
<ion-input
type="password"
formControlName="passwordConfirm"
labelPlacement="stacked"
[errorText]="formError('passwordConfirm')"
>
<div slot="label">Confirma tu contraseña <ion-text color="danger">(requerido)</ion-text></div>
<ion-input-password-toggle color="medium" slot="end"></ion-input-password-toggle>
</ion-input>
</ion-item>
<ion-item lines="full">
<ion-select
formControlName="region"
interface="action-sheet"
labelPlacement="stacked"
(ionChange)="onRegionChange()"
>
<div slot="label">Región <ion-text color="danger">(requerido)</ion-text></div>
<ion-select-option
*ngFor="let region of regiones"
[value]="region.valor"
>
{{region.nombre}}
</ion-select-option
>
</ion-select>
</ion-item>
<ion-item lines="full">
<ion-select
formControlName="comuna"
interface="action-sheet"
labelPlacement="stacked"
>
<div slot="label">Comuna <ion-text color="danger">(requerido)</ion-text></div>
<ion-select-option
*ngFor="let comuna of comunas"
[value]="comuna"
>
{{comuna}}
</ion-select-option
>
</ion-select>
</ion-item>
<ion-item class="ion-margin-vertical" lines="none">
<ion-toggle formControlName="tyc" labelPlacement="start" color="success">
Acepto los términos y condiciones <ion-text color="danger">(requerido)</ion-text>
</ion-toggle>
</ion-item>
<ion-button
expand="full"
class="ion-padding"
type="submit"
[color]="btnColor"
[disabled]="!formulario.valid"
>{{btnText}}</ion-button
>
</form>
En este formulario, se utilizan los componentes de Ionic para formularios, como ion-input
, ion-select
, ion-toggle
, entre otros. Cada componente tiene un atributo formControlName
que se corresponde con el nombre del campo en el formulario de Angular. Además, se utilizan los atributos labelPlacement
, errorText
, interface
, ionChange
, entre otros, para personalizar el formulario. También se utilizan los atributos disabled
y color
de los componentes de Ionic para deshabilitar el botón de envío del formulario si no se cumplen las condiciones de validación.
La validación de formularios con Angular se realiza al momento de crear el formulario en el componente. En este caso, se utilizan las validaciones por defecto de Angular, como required
, minLength
, maxLength
, email
, entre otras. Para mostrar los mensajes de error en el formulario, se utilizan los elementos que se encuentran en el archivo form-errors.ts
. Estos elementos se utilizan en el archivo HTML del formulario, y se muestran debajo de los campos correspondientes.
Además, se utilizan validaciones personalizadas, como rutValidator
y passwordMatchValidator
. Estas funciones se importan desde el archivo form-validators.ts
. La validación personalizada se realiza en el archivo de componente, y se utiliza en el formulario de la siguiente manera:
this.formulario = this.fb.group({
...
rut: ['', [Validators.required, rutValidator]],
...
password: ['', [Validators.required, Validators.minLength(6), Validators.maxLength(20)]],
passwordConfirm: ['', [Validators.required, passwordMatchValidator]],
...
});
Por ejemplo, la validación del RUT se realiza con la función rutValidator
, que se encuentra en el archivo form-validators.ts
.
function validaDV(rut: string) {
// Se separa el número del dígito verificador
const [numero, dv] = rut.replace('-K', '-k').split('-');
// Aquí se debe aplicar módulo 11. La función se extrajo de:
// https://validarutchile.cl/calcular-rut-en-javascript.php
// ! OJO: Es una función que se llama a sí misma.
const dvVer = ((T: number): string => {
let M = 0,
S = 1;
for (; T; T = Math.floor(T / 10)) S = (S + (T % 10) * (9 - (M++ % 6))) % 11;
return S ? (S - 1).toString() : 'k';
})(Number.parseInt(numero));
// Se compara el dígito verificador calculado con el ingresado
return dvVer == dv;
}
/**
* Función que valida el formato y dígito verificador de un RUT
* @param control Control que contiene el RUT a validar
* @returns Objeto con la validación o nulo si es válida
*/
export const rutValidator: ValidatorFn = (
control: AbstractControl
): ValidationErrors | null => {
const rut = control.value;
if (!rut) {
return null;
}
const dvValid = validaDV(rut);
const formatValid = /^[0-9]{7,8}-[0-9Kk]{1}$/.test(rut);
return formatValid ? (dvValid ? null : { rutDv: true }) : { rutFormat: true };
};
En este caso, la función rutValidator
valida el formato y el dígito verificador de un RUT. Si el RUT es válido, la función retorna null
, si no, retorna un objeto con la validación correspondiente (par clave/true). Esta función se utiliza en el formulario para validar el campo del RUT.
Otra parte importante de este ejemplo es la lectura de un archivo JSON para cargar las regiones y comunas del país. Para esto:
- Se debe crear un archivo JSON con la información necesaria. En este caso, se creó el archivo
regiones.json
en la carpetapublic/assets
. - Para cargar la información del archivo JSON, se debe crear un servicio de Angular. En este caso, se creó el archivo
regiones.service.ts
en la carpetasrc/app/misc
. Este servicio se encarga de cargar la información del archivo JSON y devolverla en un formato adecuado, y para ello utiliza el móduloHttpClient
de Angular. Para poder utilizar este módulo, se debe importar el móduloHttpClientModule
en el archivo de módulo de la aplicación (app.module.ts
).
import { HttpClientModule } from '@angular/common/http';
...
@NgModule({
declarations: [AppComponent],
imports: [..., HttpClientModule],
providers: [...],
bootstrap: [AppComponent],
})
export class AppModule {}
- Una vez obtenidos los datos, se pueden utilizar en el componente de Angular. En este caso, se utilizó el archivo
formulario.page.ts
para cargar las regiones y comunas del país. Para esto, se utilizó el servicioRegionesService
en el constructor del componente, y se llamó al métodogetRegiones()
para obtener la información del archivo JSON.
También se creó la interfaz RegionesJSON
para tipar la información del archivo JSON. Esto es importante para que TypeScript pueda inferir los tipos de datos, y para que el código sea más legible. Estas interfaces son propias de este ejemplo, y deben ser creadas según la estructura del archivo JSON. En este caso, se crearon de la siguiente manera:
interface RegionesJSON {
regiones: {
[key: string]: {
nombre: string;
valor: number;
comunas: string[];
};
};
}
Toda la lógica de la validación, mensajes de error, y carga de regiones y comunas se encuentra en el archivo formulario.page.ts
. En este archivo, se utilizan los métodos del servicio RegionesService
para cargar la información del archivo JSON, y se utilizan las funciones de validación para validar los campos del formulario.