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
}