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.
Instale los paquetes de su proyecto con:
 npm i
  Levante los servicios, con:
 ionic serve
  Edite el archivo src/app/tabs/tabs.page.ts, con:
 ...
 /* 1. Importe la referencia al ícono peopleCircle */ 
 import { clipboardOutline, ... } from 'ionicons/icons';
 ...
 export class TabsPage {
 ...
 constructor() {
     /* 2. Agregue el ícono peopleCircle */
     addIcons({ clipboardOutline, ... });
   }
 }
Edite el archivo src/app/tabs/tabs.page.html, con:
 <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>
(STOP 1) Compruebe el resultado en el navegador.
Edite el archivo src/app/tab2/tab2.page.ts, con:
 ...
 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 { ... }
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>
(STOP 2) Compruebe el resultado en el navegador.
Edite el archivo src/app/tab2/tab2.page.ts, con:
 ...
 /* 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 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)
       });
 }
Edite el archivo src/app/tab2/tab2.page.html, con:
 ...
 <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>
 ...
(STOP 3) Compruebe el resultado en el navegador.
Edite el archivo src/app/tab2/tab2.page.ts, con:
 ...
 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()
     }
 }
Edite el archivo src/app/tab2/tab2.page.html, con:
 ...
 <form ... (ngSubmit)="onSubmit()">
     ...
 </form>
(STOP 4) Compruebe el resultado en el navegador.
Cree el archivo src/credentials.ts, con:
 export const firebaseConfig = {
     apiKey: "<APIKEY>",
     authDomain: "<AUTHDOMAIN>",
     projectId: "<PROJECTID>",
     storageBucket: "<STORAGEBUCKET>",
     messagingSenderId: "<MESSAGINGSENDERID>",
     appId: "<APPID>"
 };
Edite el .gitignore, con:
 ...
 /src/credentials.ts
Instale los módulos firebase y @angular/fire, con:
 npm install firebase @angular/fire
  Edite main.ts, con:
 ...
 /* 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()),
   ],
 });
(STOP 5) Compruebe la importación de los paquetes en el package.json y que el archivo credentials no se encuentre versionado.
Desde la línea de comandos, cree el servicio proveedor de datos, con:
 ionic g service services/provider
  Edite el servicio src/app/services/provider.service.ts, con:
 /* 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() { }
 }
 ...
 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);
     }
 }
Edite src/app/tab2/tab2.page.ts, con:
 ...
 /* 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()
         });
     }
 }
(STOP 6) Compruebe el funcionamiento en el navegador y el resultado en Firestore.
Edite src/app/services/provider.service.ts, con:
 ...
 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' });
     }
 }
Edite src/app/tab2/tab2.page.ts, con:
 ...
 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;
         });
     }
 }
Edite src/app/tab2/tab2.page.html, con:
 <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>
(STOP 7) Compruebe el funcionamiento en el navegador.
🧵#HowToAngular
— Alfredo (@brolag) May 11, 2021
¿Cuáles son los patrones de diseño que te van a ayudar a entender #Angular a profundidad?
- Module
- Observer
- Dependency Injection
- Singleton
- Decorator
- Factory
- Adapter
- Facade
Exacto. Está no es una guía "Convierte en Angular Dev en 30 min" 😉 pic.twitter.com/pZh1wJiI5t
formularios reactivos, directivas, servicios