Búsqueda de sitios web

angular - Cómo agregar elementos a la página en tiempo de ejecución


Estoy creando una aplicación web de demostración en Angular para la universidad y quiero hacer clic en un button para agregar un nuevo nodo al árbol DOM. En JavaScript, usaría

document.getElementById('ticket-container').appendChild('app-ticket');

No parece que pueda encontrar una respuesta a esto y hubiera pensado que sería sencillo.

¿Cuál es la mejor manera de hacer esto en Angular 8?

*ngFor="let ticket of ticketcount; index as i;

Aquí está mi archivo ts del componente padre:

import { Component, OnInit } from '@angular/core';

class Ticket {
  name: string;
  price: number;

  constructor(x: string, y: number){
    this.name = x;
    this.price = y;
  }
}

@Component({
  selector: 'app-purchase-tickets',
  templateUrl: './purchase-tickets.component.html',
  styleUrls: ['./purchase-tickets.component.scss']
})

export class PurchaseTicketsComponent implements OnInit {
  total: number;
  ticketCount: number;

  constructor() {
   }

  ngOnInit() {
    this.total = 0;
    this.ticketCount = 0;
  }

  incrementTotal() {
    this.total += 5;
    this.ticketCount ++;
    this.renderNewTicket();
  }

  renderNewTicket() {
    //render ticket code here
  }
}

y el archivo de plantilla es:

<main id='ticket-container'>
  <app-ticket ></app-ticket>
  <button mat-icon-button aria-label="new ticket" id="add-ticket" (click)="incrementTotal()" >
    <mat-icon>add</mat-icon> 
  </button>
</main>

<p>Total: €{{total}}</p>

Respuesta #1

Como mencioné en mis comentarios, parece que necesitas usar un arreglo para almacenar los elementos y luego listarlos en la interfaz de usuario usando un *ngFor

Aquí, prueba esto:

import { Component } from "@angular/core";

interface Ticket {
  name: string;
  price: number;
}

@Component({
  selector: "grid-list-overview-example",
  styleUrls: ["grid-list-overview-example.css"],
  templateUrl: "grid-list-overview-example.html"
})
export class GridListOverviewExample {
  tickets: Array<Ticket> = [];
  total: number;

  ngOnInit() {
    this.addTicket();
  }

  addTicket() {
    this.tickets.push({
      name: `Ticket ${this.tickets.length + 1}`,
      price: 10
    });
    this.calculateTotal();
  }

  calculateTotal() {
    this.total = this.tickets
      .map(ticket => ticket.price)
      .reduce((a, b) => a + b, 0);
  }
}

Y en tu plantilla:

<main id='ticket-container'>
    <mat-grid-list cols="2" rowHeight="2:1">
        <mat-grid-tile *ngFor="let ticket of tickets">{{ ticket.name }}</mat-grid-tile>
    </mat-grid-list>

    <button mat-icon-button aria-label="new ticket" id="add-ticket" (click)="addTicket()" >
    <mat-icon>add</mat-icon> 
  </button>

  <p>Total: €{{total}}</p>
</main>

Aquí hay un ejemplo funcional en StackBlitz para tu referencia.

Respuesta #2

Estás usando *ngfor, así que almacena los valores relacionados con el ticket en un arreglo (arreglo de objetos ticket) y úsalo en la plantilla (con *ngfor). ticketCount es un número y *ngfor espera un arreglo. Agrega un método en el archivo TS para manejar el evento de clic del botón y en ese método agrega un nuevo valor a ese arreglo. La interfaz de usuario se actualiza en consecuencia.