Ligação remota do ComboBox

    O componente Ignite UI for Angular ComboBox expõe uma API que permite vincular uma combobox a um serviço remoto e recuperar dados sob demanda.

    Angular ComboBox Remote Binding Example

    O exemplo abaixo demonstra a vinculação remota usando a propriedade dataPreLoad para carregar um novo bloco de dados remotos:

    Usage

    Para começar a usar o componente ComboBox, primeiro você precisa importar o IgxComboModule no seu arquivo app.module.ts. Nesta demonstração, um serviço remoto é usado para solicitações de servidor, portanto, também precisamos incluir o HttpClientModule:

    import { IgxComboModule } from 'igniteui-angular';
    // import { IgxComboModule } from '@infragistics/igniteui-angular'; for licensed package
    
    import { HttpClientModule } from '@angular/common/http';
    
    @NgModule({
        imports: [
            ...
            IgxComboModule,
            HttpClientModule,
            ...
        ]
    })
    export class AppModule {}
    

    Define Remote Service

    Ao vincular um combobox a dados remotos, precisamos ter um serviço disponível que carregará dados sob demanda de um servidor. O componente combobox expõe a propriedade virtualizationState que fornece o estado atual de um combobox - o primeiro índice e o número de itens que precisam ser carregados. Para mostrar corretamente o tamanho do scroll, a propriedade totalItemCount deve ter um valor que corresponda ao total de itens no servidor.

    O código abaixo define um serviço simples que possui um método getData(), que recebe informações do estado atual do combobox e retorna dados como um observável:

    import { HttpClient } from '@angular/common/http';
    import { Injectable } from '@angular/core';
    import { IForOfState } from 'igniteui-angular';
    // 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();
        }
    
        // Use combobox current virtualization state and search text to build URL and request the new data.
        public getData(data?: IForOfState, searchText?: string, cb?: (any) => void): any { }
    }
    

    Binding ComboBox to Remote Service

    Quando os dados são retornados de um serviço como um observável, podemos defini-los no componente combobox usando o pipe assíncrono:

    <igx-combo [data]="rData | async"
               [valueKey]="'ProductID'"
               [displayKey]="'ProductName'"
               (dataPreLoad)="dataLoading($event)"
               (searchInputUpdate)="handleSearchInputUpdate($event)"
               (selectionChanging)="handleSelectionChanging($event)"
               (closing)="onClosing()"
               (opened)="onOpened()"
               (closed)="onClosed()"
               [filterable]="true">
    </igx-combo>
    

    Aqui estão alguns casos comuns quando o componente combobox precisa solicitar novos dados: - quando o combobox é inicializado - quando rolamos a lista do combobox - ele emitirá dataPreLoad junto com o novo combobox virtualizationState, o que permite fazer uma nova solicitação ao serviço remoto. - ao pesquisar em um combobox - precisamos fazer uma solicitação para filtrar resultados remotos. - quando o combobox é aberto - precisamos limpar os resultados de quaisquer operações de filtro anteriores.

    Abaixo estão listados os manipuladores que escutam as ações já definidas e executam requisições ao servidor:

    import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
    import { IgxComboComponent } from 'igniteui-angular';
    // import { IgxComboComponent } from '@infragistics/igniteui-angular'; for licensed package
    
    import { RemoteService } from '../../grid/services/remote.service';
    
    @Component({
        providers: [RemoteService],
        selector: 'app-combo-remote',
        styleUrls: ['./combo-remote.component.scss'],
        templateUrl: './combo-remote.component.html'
    })
    export class ComboRemoteComponent implements OnInit {
        @ViewChild('remoteCombo', { read: IgxComboComponent }) public remoteCombo: IgxComboComponent;
    
        public prevRequest: any;
        public rData: any;
    
        private searchText: string = null;
        private defaultVirtState: IForOfState = { chunkSize: 6, startIndex: 0 };
    
        private currentVirtState: IForOfState = { chunkSize: 6, startIndex: 0 };
        private itemID: number = 1;
        private itemCount: number = 0;
        private hasSelection: boolean;
        private additionalScroll: number = 0;
    
        constructor(private remoteService: RemoteService, public cdr: ChangeDetectorRef) { }
    
        public ngOnInit() {
            this.rData = this.remoteService.remoteData;
        }
    
        public ngAfterViewInit() {
            const initSize = {
                startIndex: 0,
                chunkSize: Math.ceil(250 / this.remoteCombo.itemHeight)
            };
            this.remoteService.getData(initSize, null, (data) => {
                this.remoteCombo.totalItemCount = data['@odata.count'];
                this.itemCount = this.remoteCombo.totalItemCount;
            });
        }
    
        public dataLoading(evt) {
            if (this.prevRequest) {
                this.prevRequest.unsubscribe();
            }
            this.prevRequest = this.remoteService.getData(
                this.remoteCombo.virtualizationState,
                this.searchText,
                (data) => {
                    this.remoteCombo.totalItemCount = data['@odata.count'];
                    this.cdr.detectChanges();
            });
        }
    
        public handleSearchInputUpdate(searchData: IComboSearchInputEventArgs) {
            this.currentVirtState.startIndex = 0;
            this.currentVirtState.chunkSize = Math.ceil(this.remoteCombo.itemsMaxHeight / this.remoteCombo.itemHeight);
            this.searchText = searchData?.searchText || '';
            this.remoteService.getData(
                this.searchText ? this.currentVirtState : this.defaultVirtState,
                this.searchText,
                (data) => {
                    this.remoteCombo.totalItemCount = data['@odata.count'];
                }
            );
        }
    
        public onOpened() {
            const scroll: number = this.remoteCombo.virtualScrollContainer.getScrollForIndex(this.itemID - 1);
            this.remoteCombo.virtualScrollContainer.scrollPosition = scroll + this.additionalScroll;
            this.cdr.detectChanges();
        }
    
        public onClosing() {
            this.searchText = '';
        }
    
        public onClosed() {
            this.currentVirtState.startIndex = (this.itemID || 1) - 1;
            this.remoteService.getData(
                this.currentVirtState,
                this.searchText,
                (data) => {
                    this.remoteCombo.totalItemCount = data['@odata.count'];
                    this.cdr.detectChanges();
                }
            );
        }
    
        public handleSelectionChanging(evt: IComboSelectionChangingEventArgs) {
            this.hasSelection = !!evt?.newSelection.length;
    
            if (!this.hasSelection) {
                this.itemID = 1;
                this.currentVirtState = this.defaultVirtState;
                return;
            }
    
            const currentSelection = evt.newSelection[evt.newSelection.length - 1]
            this.currentVirtState.chunkSize = Math.ceil(this.remoteCombo.itemsMaxHeight / this.remoteCombo.itemHeight);
    
            this.itemCount === currentSelection ?
                this.additionalScroll = this.remoteCombo.itemHeight :
                this.additionalScroll = 0;
    
            if (this.itemCount - currentSelection >= this.currentVirtState.chunkSize - 1) {
                this.itemID = this.currentVirtState.startIndex = currentSelection;
            } else {
                this.itemID = this.currentVirtState.startIndex = this.itemCount - (this.currentVirtState.chunkSize - 1);
            }
        }
    }
    
    Note

    Anytime new data is loaded, we update the totalItemCount property, in order to have proper size of the list's scroll bar. In that case, the service returns total size using the property @odata.count.

    Note

    Um serviço precisa ser incluído como provedor.

    Handling Selection

    Ao usar um combobox vinculado a dados remotos carregados em blocos e lidar com um tipo de dado mais complexo (por exemplo, objetos), é necessário definir um valueKey. Conforme declarado no tópico combobox, quando nenhum valueKey é especificado, o combobox tentará manipular a seleção por equality (===). Como os objetos que serão marcados como selecionados não serão os mesmos que os objetos que são carregados continuamente, a seleção falhará.

    Note

    Ao vincular uma caixa de combinação a dados remotos, certifique-se de especificar uma valueKey, representando uma propriedade exclusiva de cada item.

    Quando o combobox estiver vinculado a dados remotos, definir valor/itens selecionados por meio da API levará em conta apenas os itens que são carregados no bloco atual. Se você quiser definir um valor inicial, certifique-se de que esses itens específicos sejam carregados antes de selecionar.

    API Summary

    Additional Resources

    Nossa comunidade é ativa e sempre acolhedora para novas ideias.