arraysangularfirebaseionic-framework

How can I show elements from an array


I have been trying to show the elements of the array in each tab in the same way that I did in another of my pages but in the other it was a form and here it is not and that is why it gives me errors, 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, this is my code:

crucero.page.html

<ion-header>
  <ion-toolbar color="primary">
    <ion-buttons slot="start">
      <ion-menu-button></ion-menu-button>
    </ion-buttons>
    <ion-title>{{ crucero?.name }}</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
  <ion-tabs>
    <ion-tab-bar slot="bottom">
      <ion-tab-button tab="descripcion">
        <ion-icon name="book"></ion-icon>
        <ion-label>Descripción</ion-label>
      </ion-tab-button>
      <ion-tab-button tab="queHacer">
        <ion-icon name="walk"></ion-icon>
        <ion-label>Qué Hacer</ion-label>
      </ion-tab-button>
      <ion-tab-button tab="camarotes">
        <ion-icon name="bed"></ion-icon>
        <ion-label>Camarotes</ion-label>
      </ion-tab-button>
      <ion-tab-button tab="planos">
        <ion-icon name="boat"></ion-icon>
        <ion-label>Planos</ion-label>
      </ion-tab-button>
    </ion-tab-bar>

    <ion-tab tab="descripcion">
      <ion-content>
        <h2 class="align-center" *ngIf="crucero?.descripcion">{{ crucero?.descripcion }}</h2>
        <img [src]="crucero?.imagenDescripcion"/>
      </ion-content>
    </ion-tab>
    <ion-tab tab="queHacer">
      <ion-content>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloQueHacer1">{{ crucero?.tituloQueHacer1 }}</p>
        </ion-item>
        <img *ngIf="crucero?.imagenQueHacer1" [src]="crucero?.imagenQueHacer1"/>
        <p class="align-center" *ngIf="crucero?.descripcionQueHacer1">{{ crucero?.descripcionQueHacer1 }}</p>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloQueHacer2">{{ crucero?.tituloQueHacer2 }}</p>
        </ion-item>
        <img *ngIf="crucero?.imagenQueHacer2" [src]="crucero?.imagenQueHacer2"/>
        <p class="align-center" *ngIf="crucero?.descripcionQueHacer2">{{ crucero?.descripcionQueHacer2 }}</p>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloQueHacer3">{{ crucero?.tituloQueHacer3 }}</p>
        </ion-item>
        <img *ngIf="crucero?.imagenQueHacer3" [src]="crucero?.imagenQueHacer3"/>
        <p class="align-center" *ngIf="crucero?.descripcionQueHacer3">{{ crucero?.descripcionQueHacer3 }}</p>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloQueHacer4">{{ crucero?.tituloQueHacer4 }}</p>
        </ion-item>
        <img *ngIf="crucero?.imagenQueHacer4" [src]="crucero?.imagenQueHacer4"/>
        <p class="align-center" *ngIf="crucero?.descripcionQueHacer4">{{ crucero?.descripcionQueHacer4 }}</p>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloQueHacer5">{{ crucero?.tituloQueHacer5 }}</p>
        </ion-item>
        <img *ngIf="crucero?.imagenQueHacer5" [src]="crucero?.imagenQueHacer5"/>
        <p class="align-center" *ngIf="crucero?.descripcionQueHacer5">{{ crucero?.descripcionQueHacer5 }}</p>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloQueHacer6">{{ crucero?.tituloQueHacer6 }}</p>
        </ion-item>
        <img *ngIf="crucero?.imagenQueHacer6" [src]="crucero?.imagenQueHacer6"/>
        <p class="align-center" *ngIf="crucero?.descripcionQueHacer6">{{ crucero?.descripcionQueHacer6 }}</p>
      </ion-content>
    </ion-tab>
    <ion-tab tab="camarotes">
      <ion-content>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes1">{{ crucero?.tituloCamarotes1 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes1">{{ crucero?.descripcionCamarotes1 }}</p>
        <img *ngIf="crucero?.imagenCamarotes1" [src]="crucero?.imagenCamarotes1"/>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes2">{{ crucero?.tituloCamarotes2 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes2">{{ crucero?.descripcionCamarotes2 }}</p>
        <img *ngIf="crucero?.imagenCamarotes2" [src]="crucero?.imagenCamarotes2"/>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes3">{{ crucero?.tituloCamarotes3 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes3">{{ crucero?.descripcionCamarotes3 }}</p>
        <img *ngIf="crucero?.imagenCamarotes3" [src]="crucero?.imagenCamarotes3"/>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes4">{{ crucero?.tituloCamarotes4 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes4">{{ crucero?.descripcionCamarotes4 }}</p>
        <img *ngIf="crucero?.imagenCamarotes4" [src]="crucero?.imagenCamarotes4"/>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes5">{{ crucero?.tituloCamarotes5 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes5">{{ crucero?.descripcionCamarotes5 }}</p>
        <img *ngIf="crucero?.imagenCamarotes5" [src]="crucero?.imagenCamarotes5"/>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes6">{{ crucero?.tituloCamarotes6 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes6">{{ crucero?.descripcionCamarotes6 }}</p>
        <img *ngIf="crucero?.imagenCamarotes6" [src]="crucero?.imagenCamarotes6"/>
        <ion-item color="primary">
          <p class="centrar" *ngIf="crucero?.tituloCamarotes7">{{ crucero?.tituloCamarotes7 }}</p>
        </ion-item>
        <p class="align-center" *ngIf="crucero?.descripcionCamarotes7">{{ crucero?.descripcionCamarotes7 }}</p>
        <img *ngIf="crucero?.imagenCamarotes7" [src]="crucero?.imagenCamarotes7"/>
      </ion-content>
    </ion-tab>
    <ion-tab tab="planos">
      <ion-content>
        <ion-item>
          <ion-label>Selecciona un plano</ion-label>
          <ion-select [(ngModel)]="selectedPlano">
            <ion-select-option *ngFor="let plano of planosDisponibles" [value]="plano">
              {{ plano }}
            </ion-select-option>
          </ion-select>
        </ion-item>
        <img *ngIf="selectedPlano" [src]="crucero[selectedPlano]" alt="Plano seleccionado" />
      </ion-content>
    </ion-tab>
  </ion-tabs>
</ion-content>

crucero.page.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, RouterLink } from '@angular/router';
import { CrucerosService } from '../cruceros.service';
import { CommonModule } from '@angular/common';
import { IonicModule} from '@ionic/angular';
import { FormsModule } from '@angular/forms';
import { addIcons } from 'ionicons';
import { book, walk, bed, boat } from 'ionicons/icons';

@Component({
  selector: 'app-crucero',
  templateUrl: './crucero.page.html',
  styleUrls: ['./crucero.page.scss'],
  standalone: true,
  imports: [CommonModule, RouterLink, IonicModule, FormsModule]
})
export class CruceroPage implements OnInit {
  crucero: any = null;
  idCrucero: string = '';
  selectedPlano: string = '';
  planosDisponibles: string[] = [];

  constructor(
    private route: ActivatedRoute,
    private crucerosService: CrucerosService,
  ) { 
    addIcons({ book, walk, bed, boat });
  }

  ngOnInit() {
    this.idCrucero = this.route.snapshot.paramMap.get('id')!;
    this.loadCruceroDetails();
  }

  async loadCruceroDetails() {
    const cruceroDetails = await this.crucerosService.obtenerCruceroPorId(this.idCrucero);
    this.crucero = cruceroDetails;

    this.planosDisponibles = Object.keys(this.crucero)
      .filter(key => key.startsWith('plano'))
      .map(key => {
        const number = parseInt(key.replace('plano', ''), 10);
        return { key, number };
      })
      .filter(item => this.crucero[item.key] && this.crucero[item.key] !== '')
      .sort((a, b) => a.number - b.number)
      .map(item => item.key);

    this.selectedPlano = this.planosDisponibles.length > 0 ? this.planosDisponibles[0] : '';
  }
}

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;
        }
      }
}

Solution

  • Can you try below code?

    html

    <ion-header>
      <ion-toolbar color="primary">
        <ion-buttons slot="start">
          <ion-menu-button></ion-menu-button>
        </ion-buttons>
        <ion-title>{{ crucero?.name }}</ion-title>
      </ion-toolbar>
    </ion-header>
    
    <ion-content>
      <ion-tabs>
        <ion-tab-bar slot="bottom">
          <ion-tab-button tab="descripcion">
            <ion-icon name="book"></ion-icon>
            <ion-label>Descripción</ion-label>
          </ion-tab-button>
          <ion-tab-button tab="queHacer">
            <ion-icon name="walk"></ion-icon>
            <ion-label>Qué Hacer</ion-label>
          </ion-tab-button>
          <ion-tab-button tab="camarotes">
            <ion-icon name="bed"></ion-icon>
            <ion-label>Camarotes</ion-label>
          </ion-tab-button>
          <ion-tab-button tab="planos">
            <ion-icon name="boat"></ion-icon>
            <ion-label>Planos</ion-label>
          </ion-tab-button>
        </ion-tab-bar>
    
        <ion-tab tab="descripcion">
          <ion-content>
            <h2 class="align-center" *ngIf="crucero?.descripcion">{{ crucero?.descripcion }}</h2>
            <img [src]="crucero?.imagenDescripcion"/>
          </ion-content>
        </ion-tab>
        <ion-tab tab="queHacer">
          <ion-content>
            <div *ngFor="let item of crucero?.descripcionQueHacer">
              <ion-item color="primary">
                <p class="centrar">{{ item.titulo }}</p>
              </ion-item>
              <img *ngIf="item.imagen" [src]="item.imagen"/>
              <p class="align-center">{{ item.descripcion }}</p>
            </div>
          </ion-content>
        </ion-tab>
        <ion-tab tab="camarotes">
          <ion-content>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes1">{{ crucero?.tituloCamarotes1 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes1">{{ crucero?.descripcionCamarotes1 }}</p>
            <img *ngIf="crucero?.imagenCamarotes1" [src]="crucero?.imagenCamarotes1"/>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes2">{{ crucero?.tituloCamarotes2 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes2">{{ crucero?.descripcionCamarotes2 }}</p>
            <img *ngIf="crucero?.imagenCamarotes2" [src]="crucero?.imagenCamarotes2"/>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes3">{{ crucero?.tituloCamarotes3 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes3">{{ crucero?.descripcionCamarotes3 }}</p>
            <img *ngIf="crucero?.imagenCamarotes3" [src]="crucero?.imagenCamarotes3"/>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes4">{{ crucero?.tituloCamarotes4 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes4">{{ crucero?.descripcionCamarotes4 }}</p>
            <img *ngIf="crucero?.imagenCamarotes4" [src]="crucero?.imagenCamarotes4"/>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes5">{{ crucero?.tituloCamarotes5 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes5">{{ crucero?.descripcionCamarotes5 }}</p>
            <img *ngIf="crucero?.imagenCamarotes5" [src]="crucero?.imagenCamarotes5"/>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes6">{{ crucero?.tituloCamarotes6 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes6">{{ crucero?.descripcionCamarotes6 }}</p>
            <img *ngIf="crucero?.imagenCamarotes6" [src]="crucero?.imagenCamarotes6"/>
            <ion-item color="primary">
              <p class="centrar" *ngIf="crucero?.tituloCamarotes7">{{ crucero?.tituloCamarotes7 }}</p>
            </ion-item>
            <p class="align-center" *ngIf="crucero?.descripcionCamarotes7">{{ crucero?.descripcionCamarotes7 }}</p>
            <img *ngIf="crucero?.imagenCamarotes7" [src]="crucero?.imagenCamarotes7"/>
          </ion-content>
        </ion-tab>
        <ion-tab tab="planos">
          <ion-content>
            <ion-item>
              <ion-label>Selecciona un plano</ion-label>
              <ion-select [(ngModel)]="selectedPlano">
                <ion-select-option *ngFor="let plano of planosDisponibles" [value]="plano">
                  {{ plano }}
                </ion-select-option>
              </ion-select>
            </ion-item>
            <img *ngIf="selectedPlano" [src]="crucero[selectedPlano]" alt="Plano seleccionado" />
          </ion-content>
        </ion-tab>
      </ion-tabs>
    </ion-content>

    typescript

    You can leave it as it is :)

    import { Component, OnInit } from '@angular/core';
    import { ActivatedRoute, RouterLink } from '@angular/router';
    import { CrucerosService } from '../cruceros.service';
    import { CommonModule } from '@angular/common';
    import { IonicModule } from '@ionic/angular';
    import { FormsModule } from '@angular/forms';
    import { addIcons } from 'ionicons';
    import { book, walk, bed, boat } from 'ionicons/icons';
    
    @Component({
      selector: 'app-crucero',
      templateUrl: './crucero.page.html',
      styleUrls: ['./crucero.page.scss'],
      standalone: true,
      imports: [CommonModule, RouterLink, IonicModule, FormsModule]
    })
    export class CruceroPage implements OnInit {
      crucero: any = null;
      idCrucero: string = '';
      selectedPlano: string = '';
      planosDisponibles: string[] = [];
    
      constructor(
        private route: ActivatedRoute,
        private crucerosService: CrucerosService,
      ) { 
        addIcons({ book, walk, bed, boat });
      }
    
      ngOnInit() {
        this.idCrucero = this.route.snapshot.paramMap.get('id')!;
        this.loadCruceroDetails();
      }
    
      async loadCruceroDetails() {
        const cruceroDetails = await this.crucerosService.obtenerCruceroPorId(this.idCrucero);
        this.crucero = cruceroDetails;
    
        this.planosDisponibles = Object.keys(this.crucero)
          .filter(key => key.startsWith('plano'))
          .map(key => {
            const number = parseInt(key.replace('plano', ''), 10);
            return { key, number };
          })
          .filter(item => this.crucero[item.key] && this.crucero[item.key] !== '')
          .sort((a, b) => a.number - b.number)
          .map(item => item.key);
    
        this.selectedPlano = this.planosDisponibles.length > 0 ? this.planosDisponibles[0] : '';
      }
    }