Enlace remoto de ComboBox

    La Ignite UI for Angular ComboBox expone una API que permite vincular un cuadro combinado a un servicio remoto y recuperar datos a pedido.

    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

    Para comenzar con el componente ComboBox, primero debe importar IgxComboModule en su archivo app.module.ts. En esta demostración, se utiliza un servicio remoto para las solicitudes del servidor; por lo tanto, también debemos incluir 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.

    El siguiente código define un servicio simple que tiene un método getData(), que recibe la información del estado actual del cuadro combinado y devuelve datos como un 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()"
               [filterable]="true">
    </igx-combo>
    

    Estos son algunos casos comunes en los que el componente del cuadro combinado necesita solicitar nuevos datos: - cuando se inicializa el cuadro combinado - cuando nos desplazamos por la lista del cuadro combinado - emitirá dataPreLoad junto con el nuevo cuadro combinado virtualizationState, que permite realizar una nueva solicitud al servicio remoto. - cuando buscamos en un cuadro combinado, debemos realizar una solicitud para filtrar resultados remotos. - cuando se abre el cuadro combinado, debemos borrar los resultados de cualquier operación de filtro anterior.

    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

    Cuando se utiliza un cuadro combinado vinculado a datos remotos cargados en fragmentos y se trata de un tipo de datos más complejo (por ejemplo, objetos), es necesario definir una valueKey. Como se indica en el tema del cuadro combinado, cuando no se especifica ninguna valueKey, el cuadro combinado intentará manejar la selección por equality (===). Dado que los objetos que se marcarán como seleccionados no serán los mismos que los objetos que se cargan continuamente, la selección fallará.

    Note

    Al vincular un cuadro combinado a datos remotos, asegúrese de especificar una valueKey, que represente una propiedad que sea única para cada elemento.

    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.