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
- 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.