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

    Para empezar con el componente ComboBox, primero tienes que importarloIgxComboModule en tu archivo app.module.ts. En esta demostración, se utiliza un servicio remoto para las solicitudes del servidor, por lo que también debemos incluir elHttpClientModule:

    import { IgxComboModule } from 'igniteui-angular/combo';
    // 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 código siguiente define un servicio sencillo que tiene ungetData() método, que recibe la información de estado actual de combobox y devuelve datos como observable:

    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();
        }
    
        // 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>
    

    Aquí hay algunos casos comunes en los que el componente combobox necesita solicitar nuevos datos: - cuando se inicializa el combobox - al desplazar la lista de combobox - emitirádataPreLoad junto con el nuevo comboboxvirtualizationState, lo que permite hacer una nueva solicitud al servicio remoto. - al buscar en un combobox - necesitamos solicitar el filtro de resultados remotos. - cuando se abre el combobox - necesitamos borrar los resultados de cualquier operación de filtro previa.

    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/combo';
    // 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

    Cada vez que se carga un nuevo dato, actualizamos latotalItemCount propiedad para que la barra de desplazamiento de la lista tenga el tamaño adecuado. En ese caso, el servicio devuelve el tamaño total usando la propiedad@odata.count.

    Note

    Es necesario incluir un servicio como proveedor.

    Handling Selection

    Al usar una combobox vinculada a datos remotos cargados en bloques y tratar con un tipo de dato más complejo (por ejemplo, objetos), es necesario definir un.valueKey Como se indica en el tema de combobox, cuando se especifica novalueKey, el combobox intentará manejar la selección porequality (===). 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 asignar un combobox a datos remotos, asegúrate de especificar avalueKey, que representa una propiedad ú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.