Guía 17

Guía 17

DAWM / Proyecto04

Objetivo general

Desarrollar una aplicación híbrida utilizando tecnologías que integren modelos de aprendizaje automático previamente entrenados en un entorno funcional y accesible para resolver problemas específicos mediante el reconocimiento de patrones, objetos o sonidos fomentando habilidades prácticas en el desarrollo de aplicaciones móviles con tecnologías modernas y la implementación de inteligencia artificial.

Actividades previas

Firestore

  1. En Firebase, cree el proyecto hibrida
  2. Agregue el servicio Firebase - Firestore
  3. Obtenga las credenciales y copie el objeto firebaseConfig.

Hibrida

  1. Clona localmente tu repositorio hibrida.
  2. Instale los paquetes de su proyecto con:

     npm i
    
  3. Levante los servicios, con:

     ionic serve
    

Actividades en clases

IonTab

  1. Edite el archivo src/app/tabs/tabs.page.ts, con:

    • Importe y agregue la referencia al ícono clipboardOutline en la función addIcons.
     ...
    
     /* 1. Importe la referencia al ícono peopleCircle */ 
     import { clipboardOutline, ... } from 'ionicons/icons';
    
     ...
    
     export class TabsPage {
     ...
    
     constructor() {
    
         /* 2. Agregue el ícono peopleCircle */
         addIcons({ clipboardOutline, ... });
    
       }
     }
    
  2. Edite el archivo src/app/tabs/tabs.page.html, con:

    • En el tab2 el nombre del ícono “clipboard-outline” y el texto del ícono “Opinión”
     <ion-tabs>
       <ion-tab-bar slot="bottom">
            
         ...
    
         <ion-tab-button tab="tab2" href="/tabs/tab2">
               
            <!-- 1. Ícono y nombre del tab -->
            <ion-icon name="clipboard-outline"></ion-icon>
            <ion-label>Opinión</ion-label>
    
         </ion-tab-button>
    
       </ion-tab-bar>
     </ion-tabs>
    
  3. (STOP 1) Compruebe el resultado en el navegador.

Formulario

  1. Edite el archivo src/app/tab2/tab2.page.ts, con:

    • Importe y registre los componentes visuales mediante el decorador de la clase.
     ...
     import {  
         /* Importe los componentes de la UI */
         IonCard, IonCardHeader, IonCardTitle, IonCardContent,
         IonSelect, IonSelectOption, IonTextarea,IonButton,
         IonList, IonItem, IonLabel,
         ... 
     } from '@ionic/angular/standalone';
    	
     @Component({
         ...
         imports: [
    
             /* Registre los componentes de la UI */
             IonCard, IonCardHeader, IonCardTitle, IonCardContent,
             IonSelect, IonSelectOption, IonTextarea,IonButton,
             IonList, IonItem, IonLabel,
             ...
         ]
     })
     export class Tab2Page { ... }
    
  2. Reemplace todo el contenido en el archivo src/app/tab2/tab2.page.html, por:

     <ion-header [translucent]="true">
       <ion-toolbar>
         <ion-title>
           Retroalimentación
         </ion-title>
       </ion-toolbar>
     </ion-header>
    
     <ion-content [fullscreen]="true">
    
       <ion-card class="ion-padding-bottom ion-margin-bottom">
    
         <ion-card-header>
           <ion-card-title>Su opinión es importante</ion-card-title>
         </ion-card-header>
    
         <ion-card-content class="ion-text-center">
    
           <form>
    	        
             <ion-select label="Calificación" placeholder="Seleccione un valor">
               <ion-select-option value="bueno">Bueno</ion-select-option>
               <ion-select-option value="regular">Regular</ion-select-option>
               <ion-select-option value="malo">Malo</ion-select-option>
             </ion-select>
    
             <ion-textarea label="Opinión" placeholder="Agregue aquí su descripción"></ion-textarea>
    	        
             <ion-button type="submit">Enviar</ion-button>
    	        
           </form>
    
         </ion-card-content>
       </ion-card>
    
       <ion-card class="ion-padding-bottom ion-margin-bottom">
    
             <ion-card-header>
                 <ion-card-title>Opiniones</ion-card-title>
             </ion-card-header>
    
             <ion-card-content>
    
             <ion-list>
    
                 <!-- CARGA DE DATOS - INICIO -->
    				
                 <!-- CARGA DE DATOS - FIN -->
    
             </ion-list>
    
             </ion-card-content>
         </ion-card>
    
     </ion-content>
    
  3. (STOP 2) Compruebe el resultado en el navegador.

Formulario Reactivo

  1. Edite el archivo src/app/tab2/tab2.page.ts, con:

    • Importe y registre ReactiveFormsModule mediante el decorador de la clase.
     ...
     /* Importe el módulo para formularios reactivos */
     import { ReactiveFormsModule } from '@angular/forms';
    	
     @Component({
         ...
         imports: [
    
             /* Registre el módulo para formularios reactivos */
     		ReactiveFormsModule,
    			
             ...
         ]
     })
     export class Tab2Page { ... }
    
    • Importe los módulos FormGroup, FormControl y Validators. Instancie un formulario del tipo FormGroup.
     ...
     /* Importe los constructores del formulario */
     import { FormGroup, FormControl, Validators } from '@angular/forms';
    	
     @Component({ ... })
     export class Tab2Page {
    
           /* Instancie un formulario */
           myForm: FormGroup = new FormGroup({
             score: new FormControl("", Validators.required),
             opinion: new FormControl("", Validators.required)
           });
    
     }
    
  2. Edite el archivo src/app/tab2/tab2.page.html, con:

    • Asocie el modelo con la vista mediante las directivas formGroup y formControlName.
    • Condicione la disponibilidad del botón mediante la directiva disabled.
     ...
     <form [formGroup]="myForm">
    
         <ion-select formControlName="score" ... > ... </ion-select>
         <ion-textarea formControlName="opinion" ... > ... </ion-textarea>
         <ion-button type="submit" [disabled]="!myForm.valid"> ... </ion-button>
    
     </form>
     ...
    
  3. (STOP 3) Compruebe el resultado en el navegador.

Eventos

  1. Edite el archivo src/app/tab2/tab2.page.ts, con:

    • Agregue el callback onSubmit.
     ...
     export class Tab2Page {
    
         ...
    
         /* El método onSubmit para enviar los datos del formulario mediante el servicio */
         onSubmit() {
             console.log(this.myForm.value);
             alert(this.myForm.controls["score"].value)
             this.myForm.reset()
         }
    
     }
    
  2. Edite el archivo src/app/tab2/tab2.page.html, con:

    • Agregue la directiva ngSubmit con el nombre del callback a ejecutar.
     ...
     <form ... (ngSubmit)="onSubmit()">
         ...
     </form>
    
  3. (STOP 4) Compruebe el resultado en el navegador.

Firebase SDK

  1. Cree el archivo src/credentials.ts, con:

    • Exporte la constante firebaseConfig.
     export const firebaseConfig = {
         apiKey: "<APIKEY>",
         authDomain: "<AUTHDOMAIN>",
         projectId: "<PROJECTID>",
         storageBucket: "<STORAGEBUCKET>",
         messagingSenderId: "<MESSAGINGSENDERID>",
         appId: "<APPID>"
     };
    
  2. Edite el .gitignore, con:

    • Agregue la referencia a /src/credentials.ts
     ...
    
     /src/credentials.ts
    
  3. Instale los módulos firebase y @angular/fire, con:

     npm install firebase @angular/fire
    
  4. Edite main.ts, con:

    • Importe las variables de ambiente con las credenciales de Firebase
    • Importe e inyecte los módulos de AngularFire
     ...
    
     /* Importe las credenciales */
     import { firebaseConfig } from './credentials';
    
     /* Importe los módulos de AngularFire */
     import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
     import { provideFirestore, getFirestore } from '@angular/fire/firestore';
    
     bootstrapApplication(AppComponent, {
       providers: [
         ...
    
         /* Inyecte los módulos de AngularFire */
         provideFirebaseApp(() => initializeApp(firebaseConfig)),
         provideFirestore(() => getFirestore()),
    
       ],
     });
    
  5. (STOP 5) Compruebe la importación de los paquetes en el package.json y que el archivo credentials no se encuentre versionado.

Servicio Proveedor de Datos / Escritura

  1. Desde la línea de comandos, cree el servicio proveedor de datos, con:

     ionic g service services/provider
    
  2. Edite el servicio src/app/services/provider.service.ts, con:

    • Agregue la función inject
    • Importe el módulo Firestore e inyecte la dependencia.
     /* Agregue la función inject */
     import { Injectable, inject } from '@angular/core';
    
     /* Importe los módulos de AngularFire */
     import { Firestore, collection, addDoc, collectionData } from '@angular/fire/firestore';
     import { Observable } from 'rxjs';
    	
     ...
     export class ProviderService { 
    
         /* Inyecte de dependencia AngularFire */
         firestoreService = inject(Firestore);
    
         constructor() { }
     }
    
    • Agregue el método para escribir (createDocument) un documento en una colección de Firestore.
     ...
     export class ProviderService { 
    
         constructor(...) { }
    
         /* Método para crear un documento en la colección */
         createDocument(collectionName: string, data: any): Promise<any> {
             const colRef = collection(this.firestoreService, collectionName);
             return addDoc(colRef, data);
         }
    
     }
    
  3. Edite src/app/tab2/tab2.page.ts, con:

    • Importe e inyecte el servicio ProviderService en el constructor.
    • Defina una variable con el nombre de la colección.
    • Modifique el método onSubmit para enviar los datos del formulario mediante el servicio.
     ...
    
     /* Importe el servicio */
     import { ProviderService } from '../services/provider.service';
    
     @Component({ ... })
     export class Tab2Page {
    
         ...
    		
         /* Nombre de la colección */
         collectionName = 'reviews';
    
         /* Inyecte la dependencia a Firestore */
         constructor(private providerService: ProviderService) { }
    
         /* El método onSubmit para enviar los datos del formulario mediante el servicio */
         onSubmit() {
             this.providerService.createDocument(this.collectionName, this.myForm.value).then(() => {
                 this.myForm.reset()
             });
         }
    
     }
    
  4. (STOP 6) Compruebe el funcionamiento en el navegador y el resultado en Firestore.

Servicio Proveedor de Datos / Lectura

  1. Edite src/app/services/provider.service.ts, con:

    • Agregue el método para leer (readCollection) una colección de Firestore.
     ...
     export class ProviderService { 
    
         constructor(...) { }
    
         createDocument(...): Promise<any> { ... }
    
         /* Método para leer una colección */
         readCollection(collectionName: string): Observable<any[]> {
             const colRef = collection(this.firestoreService, collectionName);
             return collectionData(colRef, { idField: 'id' });
         }
    
     }
    
  2. Edite src/app/tab2/tab2.page.ts, con:

    • Arreglo para cargar los datos en el componente.
    • Agregue los métodos ngOnInit y loadData para cargar la colección de documentos mediante el servicio.
     ...
     export class Tab2Page {
    
         ...
    		
         /* Arreglo con datos locales */
         dataList: any[] = [];
    
         constructor( ... ) { }
    
         onSubmit() { ... }
    
         /* Al inicializar, carga los datos  */
         ngOnInit() {
             this.loadData();
         }
    
         loadData() {
             this.providerService.readCollection(this.collectionName).subscribe((data) => {
                 this.dataList = data;
             });
         }
    
     }
    
  3. Edite src/app/tab2/tab2.page.html, con:

    • Agregue la tarjeta CARGA DE DATOS.
     <ion-header [translucent]="true">
         ...
     </ion-header>
    
     <ion-content [fullscreen]="true">
    
       	<ion-card class="ion-padding-bottom ion-margin-bottom">
       		...
       	</ion-card>
    	  	
         <ion-card class="ion-padding-bottom ion-margin-bottom">
    
             <ion-card-header>
                 <ion-card-title>Opiniones</ion-card-title>
             </ion-card-header>
    
             <ion-card-content>
    
             <ion-list>
    
                 <!-- CARGA DE DATOS - INICIO -->
                 @for (datum of dataList; track $index) {
                     <ion-item>
                       <ion-label>  {{  datum?.score  }}  </ion-label>
                       <ion-label>  {{  datum?.opinion  }}  </ion-label>
                     </ion-item>
                 }
                 <!-- CARGA DE DATOS - FIN -->
    
             </ion-list>
    
             </ion-card-content>
         </ion-card>
    		
     </ion-content>
    
  4. (STOP 7) Compruebe el funcionamiento en el navegador.

Documentación

Fundamental

Términos

formularios reactivos, directivas, servicios

Referencias