I have changed the elements in Firebase in the Cruceros document so that instead of being descripcionQueHacer1, descripcionQueHacer2, etc., it is an array called descripcionQueHacer with all the elements but I don't know how to make it display, I had to delete some code but is still understandable,this is my code:
edit-crucero.page.html
<ion-header>
<ion-toolbar color="primary">
<ion-buttons slot="start">
<ion-back-button defaultHref="/gestor-cruceros"></ion-back-button>
</ion-buttons>
<ion-title>Editar Crucero</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form [formGroup]="editForm" (ngSubmit)="saveChanges()">
<ion-item class="titulo" color="primary">
<ion-title>Crucero</ion-title>
</ion-item>
<ion-item>
<ion-input label="Nombre del Crucero:" [clearInput]="true" placeholder="Añade el nombre del Crucero" name="name" formControlName="name"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Subtitulo</ion-title>
</ion-item>
<ion-item>
<ion-input label="Subtitulo del Crucero" [clearInput]="true" placeholder="Añade el subtitulo del Crucero" name="subtitle" formControlName="subtitle"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Imagen del Crucero</ion-title>
</ion-item>
<ion-item>
<ion-input label="Imagen del Crucero" [clearInput]="true" placeholder="Añade la imagen del Crucero" name="imagenCrucero" formControlName="imagenCrucero"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Descripción</ion-title>
</ion-item>
<ion-item>
<ion-input label="Descripción del Crucero" [clearInput]="true" placeholder="Añade la descripción del Crucero" name="descripcion" formControlName="descripcion"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Imagen de la Descripción</ion-title>
</ion-item>
<ion-item>
<ion-input label="Imagen de la Descripción" [clearInput]="true" placeholder="Añade la imagen de la descripcion" name="imagenDescripcion" formControlName="imagenDescripcion"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Título Que Hacer 1</ion-title>
</ion-item>
<ion-item>
<ion-input label="Título Que Hacer 1" [clearInput]="true" placeholder="Añade el titulo de Que Hacer 1" name="tituloQueHacer1" formControlName="tituloQueHacer1"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Imagen Que Hacer 1</ion-title>
</ion-item>
<ion-item>
<ion-input label="Imagen Que Hacer 1" [clearInput]="true" placeholder="Añade la imagen de Que Hacer 1" name="imagenQueHacer1" formControlName="imagenQueHacer1"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Descripción Que Hacer 1</ion-title>
</ion-item>
<ion-item>
<ion-input label="Descripción Que Hacer 1" [clearInput]="true" placeholder="Añade la descripcion de Que Hacer 1" name="descripcionQueHacer1" formControlName="descripcionQueHacer1"></ion-input>
</ion-item>
<ion-button expand="full" type="submit" color="success">Guardar Cambios</ion-button>
</form>
</ion-content>
edit-crucero.page.ts
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { CrucerosService } from '../cruceros.service';
@Component({
selector: 'app-edit-crucero',
templateUrl: './edit-crucero.page.html',
styleUrls: ['./edit-crucero.page.scss'],
standalone: true,
imports: [CommonModule, IonicModule, ReactiveFormsModule, RouterLink]
})
export class EditCruceroPage implements OnInit {
cruceroId: string = "";
crucero: any = {};
editForm: FormGroup;
constructor(
private activatedRoute: ActivatedRoute,
private crucerosService: CrucerosService,
private router: Router,
private fb: FormBuilder
) {
this.editForm = this.fb.group({
name: [''],
subtitle: [''],
imagenCrucero: [''],
descripcion: [''],
imagenDescripcion: [''],
tituloQueHacer1: [''],
imagenQueHacer1: [''],
descripcionQueHacer1: [''],
tituloQueHacer2: [''],
imagenQueHacer2: [''],
descripcionQueHacer2: [''],
tituloQueHacer3: [''],
imagenQueHacer3: [''],
descripcionQueHacer3: [''],
tituloQueHacer4: [''],
imagenQueHacer4: [''],
descripcionQueHacer4: [''],
tituloQueHacer5: [''],
imagenQueHacer5: [''],
descripcionQueHacer5: [''],
tituloQueHacer6: [''],
imagenQueHacer6: [''],
descripcionQueHacer6: [''],
tituloCamarotes1: [''],
descripcionCamarotes1: [''],
imagenCamarotes1: [''],
tituloCamarotes2: [''],
descripcionCamarotes2: [''],
imagenCamarotes2: [''],
tituloCamarotes3: [''],
descripcionCamarotes3: [''],
imagenCamarotes3: [''],
tituloCamarotes4: [''],
descripcionCamarotes4: [''],
imagenCamarotes4: [''],
tituloCamarotes5: [''],
descripcionCamarotes5: [''],
imagenCamarotes5: [''],
tituloCamarotes6: [''],
descripcionCamarotes6: [''],
imagenCamarotes6: [''],
tituloCamarotes7: [''],
descripcionCamarotes7: [''],
imagenCamarotes7: [''],
plano2: [''],
plano3: [''],
plano4: [''],
plano5: [''],
plano6: [''],
plano7: [''],
plano8: [''],
plano9: [''],
plano10: [''],
plano11: [''],
plano12: [''],
plano13: [''],
plano14: [''],
plano15: [''],
plano16: [''],
plano17: [''],
plano18: [''],
plano19: [''],
plano20: [''],
lugar1: [''],
lugar2: [''],
lugar3: [''],
lugar4: [''],
lugar5: [''],
lugar6: [''],
lugar7: [''],
lugar8: [''],
precioLugar1: [''],
precioLugar2: [''],
precioLugar3: [''],
precioLugar4: [''],
precioLugar5: [''],
precioLugar6: [''],
precioLugar7: [''],
precioLugar8: [''],
puertos1: [''],
puertos2: [''],
puertos3: [''],
puertos4: [''],
puertos5: [''],
puertos6: [''],
puertos7: [''],
puertos8: ['']
});
}
ngOnInit() {
this.cruceroId = this.activatedRoute.snapshot.paramMap.get('id')!;
this.loadCrucero();
}
async loadCrucero() {
try {
const cruceroData = await this.crucerosService.obtenerCruceros();
this.crucero = cruceroData.find(c => c.id === this.cruceroId);
if (this.crucero) {
this.editForm.patchValue({
name: this.crucero.name,
subtitle: this.crucero.subtitle,
imagenCrucero: this.crucero.imagenCrucero,
descripcion: this.crucero.descripcion,
imagenDescripcion: this.crucero.imagenDescripcion,
tituloQueHacer1: this.crucero.tituloQueHacer1,
imagenQueHacer1: this.crucero.imagenQueHacer1,
descripcionQueHacer1: this.crucero.descripcionQueHacer1,
tituloQueHacer2: this.crucero.tituloQueHacer2,
imagenQueHacer2: this.crucero.imagenQueHacer2,
descripcionQueHacer2: this.crucero.descripcionQueHacer2,
tituloQueHacer3: this.crucero.tituloQueHacer3,
imagenQueHacer3: this.crucero.imagenQueHacer3,
descripcionQueHacer3: this.crucero.descripcionQueHacer3,
tituloQueHacer4: this.crucero.tituloQueHacer4,
imagenQueHacer4: this.crucero.imagenQueHacer4,
descripcionQueHacer4: this.crucero.descripcionQueHacer4,
tituloQueHacer5: this.crucero.tituloQueHacer5,
imagenQueHacer5: this.crucero.imagenQueHacer5,
descripcionQueHacer5: this.crucero.descripcionQueHacer5,
tituloQueHacer6: this.crucero.tituloQueHacer6,
imagenQueHacer6: this.crucero.imagenQueHacer6,
descripcionQueHacer6: this.crucero.descripcionQueHacer6,
tituloCamarotes1: this.crucero.tituloCamarotes1,
descripcionCamarotes1: this.crucero.descripcionCamarotes1,
imagenCamarotes1: this.crucero.imagenCamarotes1,
tituloCamarotes2: this.crucero.tituloCamarotes2,
descripcionCamarotes2: this.crucero.descripcionCamarotes2,
imagenCamarotes2: this.crucero.imagenCamarotes2,
tituloCamarotes3: this.crucero.tituloCamarotes3,
descripcionCamarotes3: this.crucero.descripcionCamarotes3,
imagenCamarotes3: this.crucero.imagenCamarotes3,
tituloCamarotes4: this.crucero.tituloCamarotes4,
descripcionCamarotes4: this.crucero.descripcionCamarotes4,
imagenCamarotes4: this.crucero.imagenCamarotes4,
tituloCamarotes5: this.crucero.tituloCamarotes5,
descripcionCamarotes5: this.crucero.descripcionCamarotes5,
imagenCamarotes5: this.crucero.imagenCamarotes5,
tituloCamarotes6: this.crucero.tituloCamarotes6,
descripcionCamarotes6: this.crucero.descripcionCamarotes6,
imagenCamarotes6: this.crucero.imagenCamarotes6,
tituloCamarotes7: this.crucero.tituloCamarotes7,
descripcionCamarotes7: this.crucero.descripcionCamarotes7,
imagenCamarotes7: this.crucero.imagenCamarotes7,
plano2: this.crucero.plano2,
plano3: this.crucero.plano3,
plano4: this.crucero.plano4,
plano5: this.crucero.plano5,
plano6: this.crucero.plano6,
plano7: this.crucero.plano7,
plano8: this.crucero.plano8,
plano9: this.crucero.plano9,
plano10: this.crucero.plano10,
plano11: this.crucero.plano11,
plano12: this.crucero.plano12,
plano13: this.crucero.plano13,
plano14: this.crucero.plano14,
plano15: this.crucero.plano15,
plano16: this.crucero.plano16,
plano17: this.crucero.plano17,
plano18: this.crucero.plano18,
plano19: this.crucero.plano19,
plano20: this.crucero.plano20,
lugar1: this.crucero.lugar1,
lugar2: this.crucero.lugar2,
lugar3: this.crucero.lugar3,
lugar4: this.crucero.lugar4,
lugar5: this.crucero.lugar5,
lugar6: this.crucero.lugar6,
lugar7: this.crucero.lugar7,
lugar8: this.crucero.lugar8,
precioLugar1: this.crucero.precioLugar1,
precioLugar2: this.crucero.precioLugar2,
precioLugar3: this.crucero.precioLugar3,
precioLugar4: this.crucero.precioLugar4,
precioLugar5: this.crucero.precioLugar5,
precioLugar6: this.crucero.precioLugar6,
precioLugar7: this.crucero.precioLugar7,
precioLugar8: this.crucero.precioLugar8,
puertos1: this.crucero.puertos1,
puertos2: this.crucero.puertos2,
puertos3: this.crucero.puertos3,
puertos4: this.crucero.puertos4,
puertos5: this.crucero.puertos5,
puertos6: this.crucero.puertos6,
puertos7: this.crucero.puertos7,
puertos8: this.crucero.puertos8
});
}
} catch (error) {
console.error('Error loading crucero:', error);
}
}
async saveChanges() {
if (this.editForm.invalid) {
console.log('Formulario inválido');
return;
}
try {
const formData = this.editForm.value;
await this.crucerosService.actualizarCrucero(this.cruceroId, formData);
this.router.navigate(['/gestor-cruceros']);
} catch (error) {
console.error('Error guardando cambios:', error);
}
}
}
cruceros.service.ts
import { inject, Injectable } from "@angular/core";
import { addDoc, collection, doc, Firestore, getDoc, getDocs, orderBy, query, setDoc } from "@angular/fire/firestore";
@Injectable({
providedIn: 'root',
})
export class CrucerosService {
private firestore = inject(Firestore);
public idCrucero: string = "";
async guardarCrucero(
idCrucero: any,
name: any,
subtitle: any,
imagenCrucero: any,
descripcion: any,
imagenDescripcion: any,
tituloQueHacer1: any,
imagenQueHacer1: any,
descripcionQueHacer1: any,
tituloQueHacer2: any,
imagenQueHacer2: any,
descripcionQueHacer2: any,
tituloQueHacer3: any,
imagenQueHacer3: any,
descripcionQueHacer3: any,
tituloQueHacer4: any,
imagenQueHacer4: any,
descripcionQueHacer4: any,
tituloQueHacer5: any,
imagenQueHacer5: any,
descripcionQueHacer5: any,
tituloQueHacer6: any,
imagenQueHacer6: any,
descripcionQueHacer6: any,
tituloCamarotes1: any,
descripcionCamarotes1: any,
imagenCamarotes1: any,
tituloCamarotes2: any,
descripcionCamarotes2: any,
imagenCamarotes2: any,
tituloCamarotes3: any,
descripcionCamarotes3: any,
imagenCamarotes3: any,
tituloCamarotes4: any,
descripcionCamarotes4: any,
imagenCamarotes4: any,
tituloCamarotes5: any,
descripcionCamarotes5: any,
imagenCamarotes5: any,
tituloCamarotes6: any,
descripcionCamarotes6: any,
imagenCamarotes6: any,
tituloCamarotes7: any,
descripcionCamarotes7: any,
imagenCamarotes7: any,
plano2: any,
plano3: any,
plano4: any,
plano5: any,
plano6: any,
plano7: any,
plano8: any,
plano9: any,
plano10: any,
plano11: any,
plano12: any,
plano13: any,
plano14: any,
plano15: any,
plano16: any,
plano17: any,
plano18: any,
plano19: any,
plano20: any,
lugar1: any,
lugar2: any,
lugar3: any,
lugar4: any,
lugar5: any,
lugar6: any,
lugar7: any,
lugar8: any,
precioLugar1: any,
precioLugar2: any,
precioLugar3: any,
precioLugar4: any,
precioLugar5: any,
precioLugar6: any,
precioLugar7: any,
precioLugar8: any,
puertos1: any,
puertos2: any,
puertos3: any,
puertos4: any,
puertos5: any,
puertos6: any,
puertos7: any,
puertos8: any
) {
const obj ={
"idCrucero" : idCrucero,
"name" : name,
"subtitle" : subtitle,
"imagenCrucero" : imagenCrucero,
"descripcion" : descripcion,
"imagenDescripcion" : imagenDescripcion,
"tituloQueHacer1" : tituloQueHacer1,
"imagenQueHacer1" : imagenQueHacer1,
"descripcionQueHacer1" : descripcionQueHacer1,
"tituloQueHacer2" : tituloQueHacer2,
"imagenQueHacer2" : imagenQueHacer2,
"descripcionQueHacer2" : descripcionQueHacer2,
"tituloQueHacer3" : tituloQueHacer3,
"imagenQueHacer3" : imagenQueHacer3,
"descripcionQueHacer3" : descripcionQueHacer3,
"tituloQueHacer4" : tituloQueHacer4,
"imagenQueHacer4" : imagenQueHacer4,
"descripcionQueHacer4" : descripcionQueHacer4,
"tituloQueHacer5" : tituloQueHacer5,
"imagenQueHacer5" : imagenQueHacer5,
"descripcionQueHacer5" : descripcionQueHacer5,
"tituloQueHacer6" : tituloQueHacer6,
"imagenQueHacer6" : imagenQueHacer6,
"descripcionQueHacer6" : descripcionQueHacer6,
"tituloCamarotes1" : tituloCamarotes1,
"descripcionCamarotes1" : descripcionCamarotes1,
"imagenCamarotes1" : imagenCamarotes1,
"tituloCamarotes2" : tituloCamarotes2,
"descripcionCamarotes2" : descripcionCamarotes2,
"imagenCamarotes2" : imagenCamarotes2,
"tituloCamarotes3" : tituloCamarotes3,
"descripcionCamarotes3" : descripcionCamarotes3,
"imagenCamarotes3" : imagenCamarotes3,
"tituloCamarotes4" : tituloCamarotes4,
"descripcionCamarotes4" : descripcionCamarotes4,
"imagenCamarotes4" : imagenCamarotes4,
"tituloCamarotes5" : tituloCamarotes5,
"descripcionCamarotes5" : descripcionCamarotes5,
"imagenCamarotes5" : imagenCamarotes5,
"tituloCamarotes6" : tituloCamarotes6,
"descripcionCamarotes6" : descripcionCamarotes6,
"imagenCamarotes6" : imagenCamarotes6,
"tituloCamarotes7" : tituloCamarotes7,
"descripcionCamarotes7" : descripcionCamarotes7,
"imagenCamarotes7" : imagenCamarotes7,
"plano2" : plano2,
"plano3" : plano3,
"plano4" : plano4,
"plano5" : plano5,
"plano6" : plano6,
"plano7" : plano7,
"plano8" : plano8,
"plano9" : plano9,
"plano10" : plano10,
"plano11" : plano11,
"plano12" : plano12,
"plano13" : plano13,
"plano14" : plano14,
"plano15" : plano15,
"plano16" : plano16,
"plano17" : plano17,
"plano18" : plano18,
"plano19" : plano19,
"plano20" : plano20,
"lugar1": lugar1,
"lugar2": lugar2,
"lugar3": lugar3,
"lugar4": lugar4,
"lugar5": lugar5,
"lugar6": lugar6,
"lugar7": lugar7,
"lugar8": lugar8,
"precioLugar1": precioLugar1,
"precioLugar2": precioLugar2,
"precioLugar3": precioLugar3,
"precioLugar4": precioLugar4,
"precioLugar5": precioLugar5,
"precioLugar6": precioLugar6,
"precioLugar7": precioLugar7,
"precioLugar8": precioLugar8,
"puertos1": puertos1,
"puertos2": puertos2,
"puertos3": puertos3,
"puertos4": puertos4,
"puertos5": puertos5,
"puertos6": puertos6,
"puertos7": puertos7,
"puertos8": puertos8
};
const Ref = collection(this.firestore, 'Cruceros');
const docRef = await addDoc(Ref, obj);
this.idCrucero = docRef.id;
console.log(idCrucero)
}
async obtenerCruceros(){
const Ref = collection(this.firestore, 'Cruceros');
const q = query(Ref, orderBy('name'));
const querySnapshot = await getDocs(q);
const cruceros = querySnapshot.docs.map(doc => ({ id:doc.id, ...doc.data()}));
return cruceros
}
async actualizarCrucero(id: string, formData: any) {
const cruceroRef = doc(this.firestore, 'Cruceros', id.toString());
await setDoc(cruceroRef, formData, { merge: true });
}
async obtenerCruceroPorId(id: string) {
const Ref = doc(this.firestore, 'Cruceros', id);
const docSnap = await getDoc(Ref);
if (docSnap.exists()) {
return docSnap.data();
} else {
console.log("No such document!");
return null;
}
}
}
It can be done easily using FormArray. Refer below code(You might have to make a few changes as per your specific requirement):
component.ts
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormBuilder, FormGroup, FormArray, FormControl, ReactiveFormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
import { CrucerosService } from '../cruceros.service';
@Component({
selector: 'app-edit-crucero',
templateUrl: './edit-crucero.page.html',
styleUrls: ['./edit-crucero.page.scss'],
standalone: true,
imports: [CommonModule, IonicModule, ReactiveFormsModule, RouterLink]
})
export class EditCruceroPage implements OnInit {
cruceroId: string = "";
crucero: any = {};
editForm: FormGroup;
constructor(
private activatedRoute: ActivatedRoute,
private crucerosService: CrucerosService,
private router: Router,
private fb: FormBuilder
) {
this.editForm = this.fb.group({
name: [''],
subtitle: [''],
imagenCrucero: [''],
descripcion: [''],
imagenDescripcion: [''],
descripcionQueHacer: this.fb.array([]),
});
}
ngOnInit() {
this.cruceroId = this.activatedRoute.snapshot.paramMap.get('id')!;
this.loadCrucero();
}
get descripcionQueHacer(): FormArray {
return this.editForm.get('descripcionQueHacer') as FormArray;
}
addDescripcionQueHacer(descripcion: string) {
this.descripcionQueHacer.push(this.fb.group({
descripcion: [descripcion]
}));
}
async loadCrucero() {
try {
const cruceroData = await this.crucerosService.obtenerCruceros();
this.crucero = cruceroData.find(c => c.id === this.cruceroId);
if (this.crucero) {
this.editForm.patchValue({
name: this.crucero.name,
subtitle: this.crucero.subtitle,
imagenCrucero: this.crucero.imagenCrucero,
descripcion: this.crucero.descripcion,
imagenDescripcion: this.crucero.imagenDescripcion,
});
this.crucero.descripcionQueHacer.forEach((descripcion: string) => {
this.addDescripcionQueHacer(descripcion);
});
}
} catch (error) {
console.error('Error loading crucero:', error);
}
}
async saveChanges() {
if (this.editForm.invalid) {
console.log('Formulario inválido');
return;
}
try {
const formData = this.editForm.value;
await this.crucerosService.actualizarCrucero(this.cruceroId, formData);
this.router.navigate(['/gestor-cruceros']);
} catch (error) {
console.error('Error guardando cambios:', error);
}
}
}
component.html
<ion-header>
<ion-toolbar color="primary">
<ion-buttons slot="start">
<ion-back-button defaultHref="/gestor-cruceros"></ion-back-button>
</ion-buttons>
<ion-title>Editar Crucero</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form [formGroup]="editForm" (ngSubmit)="saveChanges()">
<ion-item class="titulo" color="primary">
<ion-title>Crucero</ion-title>
</ion-item>
<ion-item>
<ion-input label="Nombre del Crucero:" [clearInput]="true" placeholder="Añade el nombre del Crucero" name="name" formControlName="name"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Subtitulo</ion-title>
</ion-item>
<ion-item>
<ion-input label="Subtitulo del Crucero" [clearInput]="true" placeholder="Añade el subtitulo del Crucero" name="subtitle" formControlName="subtitle"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Imagen del Crucero</ion-title>
</ion-item>
<ion-item>
<ion-input label="Imagen del Crucero" [clearInput]="true" placeholder="Añade la imagen del Crucero" name="imagenCrucero" formControlName="imagenCrucero"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Descripción</ion-title>
</ion-item>
<ion-item>
<ion-input label="Descripción del Crucero" [clearInput]="true" placeholder="Añade la descripción del Crucero" name="descripcion" formControlName="descripcion"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Imagen de la Descripción</ion-title>
</ion-item>
<ion-item>
<ion-input label="Imagen de la Descripción" [clearInput]="true" placeholder="Añade la imagen de la descripcion" name="imagenDescripcion" formControlName="imagenDescripcion"></ion-input>
</ion-item>
<ion-item class="titulo" color="primary">
<ion-title>Descripción Que Hacer</ion-title>
</ion-item>
<div formArrayName="descripcionQueHacer">
<ion-item *ngFor="let item of descripcionQueHacer.controls; let i = index" [formGroupName]="i">
<ion-input label="Descripción Que Hacer" [clearInput]="true" placeholder="Añade la descripcion de Que Hacer" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<ion-button expand="full" type="submit" color="success">Guardar Cambios</ion-button>
</form>
</ion-content>