Enlace remoto de ComboBox

    El componente ComboBox Ignite UI for Angular expone una API que permite vincular un cuadro combinado a un servicio remoto y recuperar datos a petición.

    Angular ComboBox Remote Binding Example

    El siguiente ejemplo demuestra el enlace remoto utilizando la propiedad dataPreLoad para cargar una nueva porción de datos remotos:

    Usage

    To get started with the ComboBox component, first you need to import the IgxComboModule in your app.module.ts file. In this demo, a remote service is used for server requests, therefore, we also need to include the 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

    Al vincular un cuadro combinado a datos remotos, necesitamos tener un servicio disponible que cargue datos a pedido desde un servidor. El componente del cuadro combinado expone la propiedad virtualizationState que proporciona el estado actual de un cuadro combinado: el primer índice y la cantidad de elementos que deben cargarse. Para mostrar correctamente el tamaño de desplazamiento, la propiedad totalItemCount debe tener un valor que corresponda al total de elementos en el servidor.

    The code below defines a simple service that has a getData() method, which receives combobox's current state information and returns data as an observable:

    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

    Cuando los datos se devuelven desde un servicio como observables, podemos configurarlos en el componente del cuadro combinado usando la canalización asíncrona:

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

    Here are some common cases when the combobox component needs to request new data: - when the combobox is initialized - when we scroll combobox's list - it will emit dataPreLoad along with the new combobox virtualizationState, which allows making a new request to the remote service. - when searching in a combobox - we need to make request to filter remote results. - when combobox is opened - we need to clear the results from any previous filter operations.

    A continuación se enumeran los controladores que escuchan las acciones ya definidas y ejecutan solicitudes al 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

    Es necesario incluir un servicio como proveedor.

    Handling Selection

    When using a combobox bound to remote data loaded in chunks and dealing with a more complex data type (e.g. objects), it is necessary to define a valueKey. As stated in the combobox topic, when no valueKey is specified, the combobox will try to handle selection by equality (===). Since the objects that will be marked as selected will not be the same as the object that are continuously loaded, the selection will fail.

    Note

    When binding a combobox to remote data, make sure to specify a valueKey, representing a property that is unique to each item.

    Cuando el cuadro combinado está vinculado a datos remotos, la configuración del valor/elementos seleccionados a través de la API solo tendrá en cuenta los elementos que están cargados en el fragmento actual. Si desea establecer un valor inicial, asegúrese de que esos elementos específicos estén cargados antes de seleccionarlos.

    API Summary

    Additional Resources

    Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.