angular - Flikens innehåll med prestandaproblem
Jag försöker göra tre flikar med hjälp av ngFor och ngIf. Det fungerar faktiskt men med ett prestandaproblem. Titta på koden
<mat-nav-list class="op-content">
<h5>Listar Usuários</h5>
<input matInput [(ngModel)]="searchText" placeholder="Filtrar por nome" class="filter-input">
<mat-tab-group>
<mat-tab label="Todos" [(ngModel)]="searchText" name="todos" ngDefaultControl>
<ng-container *ngFor="let op of tboperadores | filter : searchText">
<mat-list-item>
<a matLine [routerLink]="['/operadores', op.id_operador]">
<span class="badge badge-primary"> {{op.id_operador}}</span>
Nome: {{ op.nome }} CPF: {{ op.identificacao }}</a>
</mat-list-item>
</ng-container>
</mat-tab>
<mat-tab label="Habilitados" [(ngModel)]="searchText" name="habilitado" ngDefaultControl>
<ng-container *ngFor="let op of tboperadores | filter : searchText">
<ng-container *ngIf="op.habilitado =='S'">
<mat-list-item>
<a matLine [routerLink]="['/operadores', op.id_operador]">
<span class="badge badge-primary"> {{op.id_operador}}</span>
Nome: {{ op.nome }} CPF: {{ op.identificacao }}</a>
</mat-list-item>
</ng-container>
</ng-container>
</mat-tab>
<mat-tab label="Desabilitados" [(ngModel)]="searchText" name="desabilitado" ngDefaultControl>
<ng-container *ngFor="let op of tboperadores | filter : searchText">
<ng-container *ngIf="op.habilitado=='N'">
<mat-list-item>
<a matLine [routerLink]="['/operadores', op.id_operador]">
<span class="badge badge-primary"> {{op.id_operador}}</span>
Nome: {{ op.nome }} CPF: {{ op.identificacao }}</a>
</mat-list-item>
</ng-container>
</ng-container>
</mat-tab>
</mat-tab-group>
</mat-nav-list>
<div class="loader" *ngIf="!subscription?.closed" #loading>
</div>
Som du kan se, har jag en ngfor för varje gång jag öppnar en ny flik. Jag har försökt att ha bara en för hela sidan, men jag kunde inte få det att fungera.
Någon som har en idé om hur man fixar det?
REDIGERA:
Min operador.component.ts
import { Component, OnInit, } from '@angular/core';
import { Operador } from './operador';
import { OperadorService } from './operador.service';
import { Subscription, Observable } from 'rxjs';
@Component({
selector: 'app-operador',
templateUrl: './operador.component.html',
styleUrls: ['./operador.component.css']
})
//export class OperadorComponent implements OnInit, PipeTransform {
export class OperadorComponent implements OnInit {
tboperadores: Operador[];
checkedOperadors: Operador[];
subscription: Subscription;
mode = 'indeterminate';
constructor(private operadorService: OperadorService) {
}
ngOnInit(): void {
this.subscription = this.getOperadores();
}
getOperadores() {
return this.operadorService.getOperadores()
.subscribe(ob => {
console.log(ob);
this.tboperadores = ob;
});
}
}
Och, min filter.pipe.ts:
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter'
})
export class FilterPipe implements PipeTransform {
transform(items: any[], searchText: string): any[] {
if(!items) return [];
if(!searchText) return items;
searchText = searchText.toLowerCase();
return items.filter( it => {
return it.nome.toLowerCase().includes(searchText);
});
}
}
- min operador.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { Operador } from './operador';
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
@Injectable({
providedIn: 'root'
})
export class OperadorService {
private operadoresUrl = '******'; // URL to web api
constructor(
private http: HttpClient
) { }
getOperadores (): Observable<Operador[]> {
return this.http.get<Operador[]>(this.operadoresUrl)
}
getOperador(id_operador: number): Observable<Operador> {
const url = `${this.operadoresUrl}/${id_operador}`;
return this.http.get<Operador>(url);
}
addOperador (operador: Operador): Observable<Operador> {
return this.http.post<Operador>(this.operadoresUrl, operador, httpOptions);
}
deleteOperador (operador: Operador | number): Observable<Operador> {
const id_operador = typeof operador === 'number' ? operador : operador.id_operador;
const url = `${this.operadoresUrl}/${id_operador}`;
return this.http.delete<Operador>(url, httpOptions);
}
updateOperador (operador: Operador): Observable<any> {
return this.http.put(this.operadoresUrl, operador, httpOptions);
}
}
REDIGERA2:
Jag har redigerat denna metod för att göra filtret:
getOperadores(option): Observable<Operador[]> {
if (option == 0) {
return this.http.get<Operador[]>(this.operadoresUrl)
} else if (option == 1) {
return this.http.get<Operador[]>(this.operadoresUrl).pipe(
map((reports: Operador[]) => reports.filter(p => p.habilitado === "S"))
);
} else {
return this.http.get<Operador[]>(this.operadoresUrl).pipe(
map((reports: Operador[]) => reports.filter(p => p.habilitado === "N"))
);
}
}
och skapade dessa två metoder att anropa i konstruktorn:
checkedOperadores() {
return this.operadorService.getOperadores(1)
.subscribe( ob => {
console.log(ob);
this.checkedOperadors = ob;
});
}
uncheckedOperadores() {
return this.operadorService.getOperadores(2)
.subscribe( ob => {
console.log(ob);
this.uncheckedOperadors = ob;
});
}
Men prestandaproblemet fortsätter...
Svar #1
Från dokumentationen kan du använda lat inläsning för att förbättra initialiseringsfasen:
https://material.angular.io/components/tabs/overview#lazy-loading
Lat Laddning
Som standard laddas flikinnehållet ivrigt. Ivrigt laddade flikar kommer att initialisera barnkomponenterna men inte infoga dem i DOM:en förrän fliken aktiveras.Om fliken innehåller flera komplexa underkomponenter eller flikens innehåll är beroende av DOM-beräkningar under initialisering, rekommenderas det att ladda flikens innehåll på ett fördröjt sätt.
Flikinnehåll kan laddas late genom att deklarera kroppen i en ng-template med matTabContent-attributet.
Om du fortfarande har prestandaproblemet måste du lista ut hur du använder virtuell scroll på dina for-loopar.
UPPDATERING:
Jag vet inte hur din filterpipe är implementerad, men du måste vara uppmärksam på om det är en ren eller oren sådan. Relaterat till https://angular.io/guide/pipes#appendix-no-filterpipe-or-orderbypipe kan det orsaka prestandaproblem.
Du kan förbättra din kod också :
1 - Skapa tre get-metoder, var och en för en typ av habilitado som:
get habilitados() {
return tboperadores.filter(op => op.habilitado === 'S')
}
då använder du det i ngFor och blir av med ngIf.
2 - Kanske skapa en komponent för koden nedan för att minska antalet kodrader :
<mat-list-item>
<a matLine [routerLink]="['/operadores', op.id_operador]">
<span class="badge badge-primary"> {{op.id_operador}}</span>
Nome: {{ op.nome }} CPF: {{ op.identificacao }}
</a>
</mat-list-item>
