Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Angular V16: Dúvida sobre carregar component dinâmicamente

Pessoal, estou iniciando um projeto no Angular (v16) e precisava de uma luz para inserir de forma dinâmica um component dentro do tabs. Estou usando Material Tabs; Um serviço para gerenciar as Tabs abertas, onde estas são inseridas dinâmicamente também. A ideia é renderizar o component no 'corpo' do tab de acordo com a escolha do usuário no menu, ou seja, com um evento click. Meu component tab esta definido da seguinte forma:

<ng-container *ngIf="openTabs.length > 0; else noTabs">
  <mat-tab-group
    class="mat-tab-group"
    (selectedTabChange)="tabChanged($event)"
    [selectedIndex]="openTabs.length - 1"
  >
    <mat-tab *ngFor="let tab of openTabs; let i = index">
      <ng-template mat-tab-label>
        {{ tab.label }}
        <button mat-icon-button (click)="closeTab(i)" title="Fechar aba">
          <mat-icon>close</mat-icon>
        </button>
      </ng-template>
    </mat-tab>
  </mat-tab-group>
  <mat-grid-list
    class="mat-grid-list"
    *ngFor="let tab of openTabs.reverse(); let i = index"
    [style.display]="tab.active ? 'block' : 'none'"
    [cols]="0"
    [rowHeight]="rowHeight"
    style="overflow-y: auto"
  >
    <mat-grid-tile>

      <app-reports-iframe-new [url]="tab.url"></app-reports-iframe-new>

    </mat-grid-tile>
  </mat-grid-list>
</ng-container>
<ng-template #noTabs>
  <app-logo-centro></app-logo-centro>
</ng-template>

Estou passando de forma estática o component ReportsIframeNew. Porém gostaria de poder passar como opção meus components de tela de cadastros, tabelas e etc...

O serviço que gerencia as tabs:

import { Injectable, Type } from '@angular/core';
import { Router } from '@angular/router';
import { SafeUrl, DomSanitizer } from '@angular/platform-browser';
import { ApiService } from './api.service';
import { Tab } from '../models/tab';

@Injectable({
  providedIn: 'root',
})
export class TabService {
  //openTabs: any[] = []; // Matriz que guarda abas abertas
  openTabs: Tab[] = [];

  constructor(
    private router: Router,
    private sanitizer: DomSanitizer,
    private apiService: ApiService
  ) {}

  addTab(tabData: { label: string; url: string }) {
    if (this.openTabs.length < 5) {
      // Const que recebera true somente quando o tamanho da matriz de tabs for 0
      // Então o valor booleano irá para o construtor da primeira tab no método push mais abaixo
      const isFirstTab = this.openTabs.length === 0;
      // Usando o método bypassSecurityTrustResourceUrl para sanitizar a URL
      // Ajuda nos ataques de injeção de código
      const sanitizedUrl: SafeUrl =
        this.sanitizer.bypassSecurityTrustResourceUrl(tabData.url);

      // Aqui usa o méto push para incluir uma nova tab na matriz de tabs
      this.openTabs.push({
        label: tabData.label,
        url: sanitizedUrl,
        active: isFirstTab,
      }); // Adicionar uma nova aba à matriz

      // Essa linha usa-se se necessário criar uma regra de roteamento
      // No app-routing esta comentado o trecho que a torna funcional
      this.router.navigate(['/relatorios-tabs']);
      console.log('TAB ATIVA: ', this.openTabs.length - 1);
    } else {
      this.apiService.showMessage('Limitado a 5 abas abertas simultaneamente!');
      this.router.navigate(['/relatorios-tabs']);
    }

  }

  getTabs() {
    return this.openTabs;
  }

  closeTab(index: number) {
    if (index >= 0 && index < this.openTabs.length) {
      this.openTabs.splice(index, 1); // Fechar a aba com base no índice
    }
  }
}

Existe também uma interface que define a Tab:

import { Type } from '@angular/core';

export interface Tab {
  label: string;
  url?: any;
  active: boolean;
  componentType?: Type<any>; // Campo para a classe de componente
}
1 resposta
solução!

Oi Thiago! Tudo ok por aí?

Eu dei uma comentada sobre isso aqui:

Veja se ajuda.

Abraços e bons estudos.