I don't know why is this happening and I have been trying a lot of things but I can't fix this problem. The problem is for example if I edit my "Crucero" and change tituloQueHacer
from "hola" to "adios" at first in the FireStore it was like this:
But then when I edit it it shows like this:
And I dont want to have the "descripcion" thing there
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</ion-title>
</ion-item>
<div formArrayName="tituloQueHacer">
<ion-item *ngFor="let item of tituloQueHacer.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Título Que Hacer ' + (i + 1)" [clearInput]="true" placeholder="Añade el titulo de Que Hacer" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addTituloQueHacerButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Imagen Que Hacer</ion-title>
</ion-item>
<div formArrayName="imagenQueHacer">
<ion-item *ngFor="let item of imagenQueHacer.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Imagen Que Hacer ' + (i + 1)" [clearInput]="true" placeholder="Añade la imagen de Que Hacer" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addImagenQueHacerButton()">+</ion-button>
</div>
<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 ' + (i + 1)" [clearInput]="true" placeholder="Añade la descripcion de Que Hacer" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addDescripcionQueHacerButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Título Camarotes</ion-title>
</ion-item>
<div formArrayName="tituloCamarotes">
<ion-item *ngFor="let item of tituloCamarotes.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Titulo Camarotes ' + (i + 1)" [clearInput]="true" placeholder="Añade el titulo de Camarotes" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addTituloCamarotesButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Descripción Camarotes</ion-title>
</ion-item>
<div formArrayName="descripcionCamarotes">
<ion-item *ngFor="let item of descripcionCamarotes.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Descripción Camarotes ' + (i + 1)" [clearInput]="true" placeholder="Añade la descripcion de Camarotes" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addDescripcionCamarotesButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Imagen Camarotes</ion-title>
</ion-item>
<div formArrayName="imagenCamarotes">
<ion-item *ngFor="let item of imagenCamarotes.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Imagen Camarotes ' + (i + 1)" [clearInput]="true" placeholder="Añade la imagen de Camarotes" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addImagenCamarotesButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Imagen de Planos</ion-title>
</ion-item>
<div formArrayName="planos">
<ion-item *ngFor="let item of planos.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Imagen Planos ' + (i + 1)" [clearInput]="true" placeholder="Añade la imagen de Planos" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addPlanosButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Lugares</ion-title>
</ion-item>
<div formArrayName="lugares">
<ion-item *ngFor="let item of lugares.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Nombre Lugares ' + (i + 1)" [clearInput]="true" placeholder="Añade el nombre de Lugares" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addLugaresButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Precio Lugares</ion-title>
</ion-item>
<div formArrayName="precioLugares">
<ion-item *ngFor="let item of precioLugares.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Precio Lugares ' + (i + 1)" [clearInput]="true" placeholder="Añade el precio de Lugares" formControlName="descripcion" type="number"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addPrecioLugaresButton()">+</ion-button>
</div>
<ion-item class="titulo" color="primary">
<ion-title>Puertos</ion-title>
</ion-item>
<div formArrayName="puertos">
<ion-item *ngFor="let item of puertos.controls; let i = index" [formGroupName]="i">
<ion-input [label]="'Nombre Puertos ' + (i + 1)" [clearInput]="true" placeholder="Añade el nombre de Puertos" formControlName="descripcion"></ion-input>
</ion-item>
</div>
<div class="titulo">
<ion-button (click)="addPuertosButton()">+</ion-button>
</div>
<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 { FormArray, FormBuilder, FormControl, 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: [''],
tituloQueHacer: this.fb.array([]),
imagenQueHacer: this.fb.array([]),
descripcionQueHacer: this.fb.array([]),
tituloCamarotes: this.fb.array([]),
descripcionCamarotes: this.fb.array([]),
imagenCamarotes: this.fb.array([]),
planos: this.fb.array([]),
lugares: this.fb.array([]),
precioLugares: this.fb.array([]),
puertos: this.fb.array([])
});
}
ngOnInit() {
this.cruceroId = this.activatedRoute.snapshot.paramMap.get('id')!;
this.loadCrucero();
}
addTituloQueHacerButton() {
(this.editForm.get('tituloQueHacer') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getTituloQueHacerControls() {
return (this.editForm.get('tituloQueHacer') as FormArray).controls;
}
addImagenQueHacerButton() {
(this.editForm.get('imagenQueHacer') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getImagenQueHacerControls() {
return (this.editForm.get('imagenQueHacer') as FormArray).controls;
}
addDescripcionQueHacerButton() {
(this.editForm.get('descripcionQueHacer') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getDescripcionQueHacerControls() {
return (this.editForm.get('descripcionQueHacer') as FormArray).controls;
}
addTituloCamarotesButton() {
(this.editForm.get('tituloCamarotes') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getTituloCamarotesControls() {
return (this.editForm.get('tituloCamarotes') as FormArray).controls;
}
addDescripcionCamarotesButton() {
(this.editForm.get('descripcionCamarotes') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getDescripcionCamarotesControls() {
return (this.editForm.get('descripcionCamarotes') as FormArray).controls;
}
addImagenCamarotesButton() {
(this.editForm.get('imagenCamarotes') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getImagenCamarotesControls() {
return (this.editForm.get('imagenCamarotes') as FormArray).controls;
}
addPlanosButton() {
(this.editForm.get('planos') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getPlanosControls() {
return (this.editForm.get('planos') as FormArray).controls;
}
addLugaresButton() {
(this.editForm.get('lugares') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getLugaresControls() {
return (this.editForm.get('lugares') as FormArray).controls;
}
addPrecioLugaresButton() {
(this.editForm.get('precioLugares') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getPrecioLugaresControls() {
return (this.editForm.get('precioLugares') as FormArray).controls;
}
addPuertosButton() {
(this.editForm.get('puertos') as FormArray).push(this.fb.group({
descripcion: ['']
}));
}
getPuertosControls() {
return (this.editForm.get('puertos') as FormArray).controls;
}
get tituloQueHacer(): FormArray {
return this.editForm.get('tituloQueHacer') as FormArray;
}
addTituloQueHacer(descripcion: string) {
this.tituloQueHacer.push(this.fb.group({
descripcion: [descripcion]
}));
}
get imagenQueHacer(): FormArray {
return this.editForm.get('imagenQueHacer') as FormArray;
}
addImagenQueHacer(descripcion: string) {
this.imagenQueHacer.push(this.fb.group({
descripcion: [descripcion]
}));
}
get descripcionQueHacer(): FormArray {
return this.editForm.get('descripcionQueHacer') as FormArray;
}
addDescripcionQueHacer(descripcion: string) {
this.descripcionQueHacer.push(this.fb.group({
descripcion: [descripcion]
}));
}
get tituloCamarotes(): FormArray {
return this.editForm.get('tituloCamarotes') as FormArray;
}
addTituloCamarotes(descripcion: string) {
this.tituloCamarotes.push(this.fb.group({
descripcion: [descripcion]
}));
}
get descripcionCamarotes(): FormArray {
return this.editForm.get('descripcionCamarotes') as FormArray;
}
addDescripcionCamarotes(descripcion: string) {
this.descripcionCamarotes.push(this.fb.group({
descripcion: [descripcion]
}));
}
get imagenCamarotes(): FormArray {
return this.editForm.get('imagenCamarotes') as FormArray;
}
addImagenCamarotes(descripcion: string) {
this.imagenCamarotes.push(this.fb.group({
descripcion: [descripcion]
}));
}
get planos(): FormArray {
return this.editForm.get('planos') as FormArray;
}
addPlanos(descripcion: string) {
this.planos.push(this.fb.group({
descripcion: [descripcion]
}));
}
get lugares(): FormArray {
return this.editForm.get('lugares') as FormArray;
}
addLugares(descripcion: string) {
this.lugares.push(this.fb.group({
descripcion: [descripcion]
}));
}
get precioLugares(): FormArray {
return this.editForm.get('precioLugares') as FormArray;
}
addPrecioLugares(descripcion: string) {
this.precioLugares.push(this.fb.group({
descripcion: [descripcion]
}));
}
get puertos(): FormArray {
return this.editForm.get('puertos') as FormArray;
}
addPuertos(descripcion: string) {
this.puertos.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.tituloQueHacer.forEach((titulo: string) => {
this.addTituloQueHacer(titulo);
});
this.crucero.imagenQueHacer.forEach((imagen: string) => {
this.addImagenQueHacer(imagen);
});
this.crucero.descripcionQueHacer.forEach((descripcion: string) => {
this.addDescripcionQueHacer(descripcion);
});
this.crucero.tituloCamarotes.forEach((titulo: string) => {
this.addTituloCamarotes(titulo);
});
this.crucero.descripcionCamarotes.forEach((descripcion: string) => {
this.addDescripcionCamarotes(descripcion);
});
this.crucero.imagenCamarotes.forEach((imagen: string) => {
this.addImagenCamarotes(imagen);
});
this.crucero.planos.forEach((planos: string) => {
this.addPlanos(planos);
});
this.crucero.lugares.forEach((lugares: string) => {
this.addLugares(lugares);
});
this.crucero.precioLugares.forEach((precioLugares: string) => {
this.addPrecioLugares(precioLugares);
});
this.crucero.puertos.forEach((puertos: string) => {
this.addPuertos(puertos);
});
}
} 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,
tituloQueHacer: any[],
imagenQueHacer: any[],
descripcionQueHacer: any[],
tituloCamarotes: any[],
descripcionCamarotes: any[],
imagenCamarotes: any[],
planos: any[],
lugares: any[],
precioLugares: any[],
puertos: any[]
) {
const obj ={
"idCrucero" : idCrucero,
"name" : name,
"subtitle" : subtitle,
"imagenCrucero" : imagenCrucero,
"descripcion" : descripcion,
"imagenDescripcion" : imagenDescripcion,
"tituloQueHacer" : tituloQueHacer,
"imagenQueHacer" : imagenQueHacer,
"descripcionQueHacer" : descripcionQueHacer,
"tituloCamarotes" : tituloCamarotes,
"descripcionCamarotes" : descripcionCamarotes,
"imagenCamarotes" : imagenCamarotes,
"planos" : planos,
"lugares": lugares,
"precioLugares": precioLugares,
"puertos": puertos
};
const Ref = collection(this.firestore, 'Cruceros');
const docRef = await addDoc(Ref, obj);
this.idCrucero = docRef.id;
console.log(this.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;
}
}
}
Solution 1
Since you are constructing an array of FormGroup
instance for tituloQueHacer
, you can transform the objects to string by extracting descripcion
before sending the request.
async saveChanges() {
...
try {
const formData = this.editForm.value;
// Transform objects to strings
formData.tituloQueHacer = formData.tituloQueHacer.map((x: any) => x.descripcion);
await this.crucerosService.actualizarCrucero(this.cruceroId, formData);
this.router.navigate(['/gestor-cruceros']);
} catch (error) {
console.error('Error guardando cambios:', error);
}
}
Solution 2
Otherwise, you need to change the tituloQueHacer
structure to a FormArray
of FormControl
(s) instead of FormGroup
(s)
<ion-item
*ngFor="let item of tituloQueHacer.controls; let i = index"
>
<ion-input
[label]="'Título Que Hacer ' + (i + 1)"
[clearInput]="true"
placeholder="Añade el titulo de Que Hacer"
[formControlName]="i"
></ion-input>
</ion-item>
And some changes to make when manipulating the control in the tituloQueHacer
FormArray
.
addTituloQueHacer(descripcion: string) {
this.tituloQueHacer.push(this.fb.control(descripcion));
}
addTituloQueHacerButton() {
(this.editForm.get('tituloQueHacer') as FormArray).push(
this.fb.control('')
);
}