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
- Componente de cuadro combinado
- Funciones del cuadro combinado
- Plantillas de cuadros combinados
- Integración de formularios basados en plantillas
- Integración de formularios reactivos
- Cuadro combinado de selección única
Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.