Lista suspensa virtual
O componente Drop Down Ignite UI for Angular pode se integrar totalmente àIgxForOf diretiva para exibir uma lista muito grande de itens para sua seleção.
Angular Virtual Drop Down Example
Usage
First Steps
Para configurar o menu suspenso para exibir uma lista de itens virtuais, é necessário cumprir alguns pré-requisitos. Primeiro, precisamos importar oIgxForOfModule no módulo do componente que declarará nosso menu suspenso.
// app.module.ts
import { IgxForOfModule } from 'igniteui-angular/directives';
// import { IgxForOfModule } from '@infragistics/igniteui-angular'; for licensed package
@NgModule({
imports: [
...
IgxForOfModule
]
})
export class AppModule {}
Template Configuration
Em seguida, precisamos criar o template do componente suspenso, percorrendo os dados usando*igxFor em vez de*ngFor. A*igxFor diretiva precisa de alguma configuração adicional para exibir corretamente todos os itens:
<!-- drop-down-virtual.component.html -->
<button igxButton [igxToggleAction]="dropdown"
[igxDropDownItemNavigation]="dropdown">
Item Series
</button>
<igx-drop-down #dropdown>
<div class="drop-down-virtual-wrapper" style="height: {{ itemsMaxHeight }}px;">
<igx-drop-down-item
*igxFor="let item of items; index as index;
scrollOrientation: 'vertical';
containerSize: itemsMaxHeight;
itemSize: itemHeight;"
[value]="item" [isHeader]="item.header"
role="option" [disabled]="item.disabled"
[index]="index">
{{ item.name }}
</igx-drop-down-item>
</div>
</igx-drop-down>
<div>Selected Model: <span>{{ dropdown.selectedItem?.value.name }}</span></div>
Os parâmetros adicionais passados à*igxFor diretiva são:
index- captura o índice do item atual no conjunto de dadosscrollOrientation- deve sempre ser'vertical'containerSize- o tamanho do contêiner virtualizado (inpx). Isso também precisa ser aplicado no envolvimento<div>itemSize- o tamanho dos itens que serão exibidos (empx)
Para garantir a unicidade dos itens, passeitem dentro davalue entrada eindex dentro daindex entrada daigx-drop-down-item. Para preservar a seleção durante a rolagem, o item suspenso precisa ter uma referência aos itens de dados aos quais está vinculado.
Note
Para que o menu suspenso funcione com uma lista virtualizada de itensvalue eindex entradas devem ser passadas para todos os itens.
Note
É fortemente recomendado que cada item tenha um valor único passado para a[value] entrada. Caso contrário, pode levar a resultados inesperados (seleção incorreta).
Note
Quando o menu suspenso usa itens virtualizados, o tipo dedropdown.selectedItem se torna{ value: any, index: number }, ondevalue é uma referência ao item de dados passado dentro da[value] entrada eindex é o índice do item no conjunto de dados
Component Definition
Dentro do construtor do componente, declararemos uma lista moderadamente grande de itens (contendo tanto cabeçalhos quanto itens desativados), que será exibida no menu suspenso. Também precisaremos declararitemHeight eitemsMaxHeight:
// drop-drop-virtual.component.ts
export class DropDownVirtualComponent {
public items: DataItem[];
public itemHeight = 48;
public itemsMaxHeight = 320;
constructor() {
const itemsCollection: DataItem[] = [];
for (let i = 0; i < 50; i++) {
const series = (i * 10).toString();
itemsCollection.push({
id: series,
name: `${series} Series`,
header: true,
disabled: false
});
for (let j = 0; j < 10; j++) {
itemsCollection.push({
id: `${series}_${j}`,
name: `Series ${series}, ${i * 10 + j} Model`,
header: false,
disabled: j % 9 === 0
});
}
}
this.items = itemsCollection;
}
}
Styles
A última parte da configuração é definiroverflow: hidden para o div de envolvimento para evitar o aparecimento de duas barras de rolagem (uma doigxFor próprio recipiente e outra do próprio recipiente):
// drop-drop-virtual.component.scss
.drop-down-virtual-wrapper {
overflow: hidden;
}
Remote Data
Suportaigx-drop-down carregar blocos de dados remotos usando a*igxFor diretiva estrutural. A configuração é semelhante à dos itens locais, sendo a principal diferença como os blocos de dados são carregados.
Template
O template suspenso não precisa mudar muito em comparação com o exemplo anterior – ainda precisamos especificar um div de wrapping, estilizá-lo de acordo e escrever a configuração completa para o*igxFor. Como receberemos nossos dados de uma fonte remota, precisamos especificar que nossos dados serão observáveis e passá-Angular los pelo 'sasync pipe:
<igx-drop-down #remoteDropDown>
<div class="drop-down-virtual-wrapper">
<igx-drop-down-item
*igxFor="let item of rData | async; index as index;
scrollOrientation: 'vertical';
containerSize: itemsMaxHeight;
itemSize: itemHeight;"
[value]="item.ProductName" role="option"
[disabled]="item.disabled" [index]="index">
{{ item.ProductName }}
</igx-drop-down-item>
</div>
</igx-drop-down>
Handling chunk load
Como você pode ver, o template é quase idêntico ao do exemplo anterior. Neste cenário de dados remotos, o código por trás fará a maior parte do trabalho pesado.
Primeiro, precisamos definir um serviço remoto para buscar dados:
// remote.service.ts
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { IForOfState } from 'igniteui-angular/directives';
// import { IForOfState } from '@infragistics/igniteui-angular'; for licensed package
import { BehaviorSubject, Observable } from 'rxjs';
@Injectable()
export class RemoteService {
public remoteData: Observable<any[]>;
private _remoteData: BehaviorSubject<any[]>;
constructor(private http: HttpClient) {
this._remoteData = new BehaviorSubject([]);
this.remoteData = this._remoteData.asObservable();
}
public getData(data?: IForOfState, cb?: (any) => void): any {
// Assuming that the API service is RESTful and can take the following:
// skip: start index of the data that we fecth
// count: number of records we fetch
this.http.get(`https://dummy.db/dummyEndpoint?skip=${data.startIndex}&count=${data.chunkSize}`).subscribe((data) => {
// emit the values through the _remoteData subject
this._remoteData.next(data);
})
}
O serviço expõe umObservable subremoteData. Vamos injetar nosso serviço e vincular a essa propriedade em nosso componente drop-down remoto:
// remote-drop-down.component.ts
@Component({
providers: [RemoteService],
selector: 'app-drop-down-remote',
templateUrl: './drop-down-remote.component.html',
styleUrls: ['./drop-down-remote.component.scss']
})
export class DropDownRemoteComponent implements OnInit, OnDestroy {
@ViewChild(IgxForOfDirective, { read: IgxForOfDirective })
public remoteForDir: IgxForOfDirective<any>;
@ViewChild('remoteDropDown', { read: IgxDropDownComponent })
public remoteDropDown: IgxDropDownComponent;
public itemHeight = 48;
public itemsMaxHeight = 480;
public prevRequest: Subscription;
public rData: any;
private destroy$ = new Subject();
constructor(private remoteService: RemoteService) { }
public ngAfterViewInit() {
const initialState = { startIndex: 0, chunkSize: Math.ceil(this.itemsMaxHeight / this.itemHeight) }
this.remoteService.getData(initialState, (data) => {
this.remoteForDir.totalItemCount = data['@odata.count'];
});
// Subscribe to igxForOf.chunkPreload and load new data from service
this.remoteForDir.chunkPreload.pipe(takeUntil(this.destroy$)).subscribe((data) => {
this.dataLoading(data);
});
}
public dataLoading(evt) {
if (this.prevRequest) {
this.prevRequest.unsubscribe();
}
this.prevRequest = this.remoteService.getData(
evt,
(data) => {
this.remoteForDir.totalItemCount = data['@odata.count'];
});
}
public ngOnInit() {
this.rData = this.remoteService.remoteData;
}
public ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
Dentro dongAfterViewInit gancho, ligamos para obter dados do estado inicial e assinar oigxForOf emissor dachunkPreload diretiva. Essa assinatura será responsável por buscar dados toda vez que o chunk carregado for alterado. Usamospipe(takeUntil(this.destroy$)) para podermos cancelar a inscrição facilmente do emissor ao destruir componentes.
Remote Virtualization - Demo
O resultado da configuração acima é um menu suspenso que carrega dinamicamente os dados que deve exibir, dependendo do estado da barra de rolagem:
Notes and Limitations
Usar o menu suspenso com uma lista virtualizada de itens impõe algumas limitações. Por favor, esteja atento ao seguinte ao tentar configurar uma lista suspensa usando*igxFor:
- Os itens suspensos que estão sendo reproduzidos precisam ser passados em um elemento de encapsulamento (por exemplo
<div>) que tenha o seguinte css:overflow: hiddeneheightigual acontainerSizeempx <igx-drop-down-item-group>não pode ser usado para agrupar itens quando a lista está virtualizada. Use aisHeaderpropriedade em vez disso- O
itemsacessor retornará apenas a lista de itens suspensos que não sejam cabeçalhos e que estão atualmente na visualização virtualizada. dropdown.selectedItemé do tipo{ value: any, index: number }- O objeto emitido por
selectionmudanças emconst emittedEvent: { newSelection: { value: any, index: number }, oldSelection: { value: any, index: number }, cancel: boolean, } dropdown.setSelectedItemdeve ser chamado com o índice do item no conjunto de dados- Definir a entrada do
[selected]item suspenso não marcará o item na seleção suspensa