콤보박스 원격 바인딩
Ignite UI for Angular 콤보 상자를 원격 서비스에 바인딩하고 필요에 따라 데이터를 검색할 수 있는 API를 제공합니다.
Angular ComboBox Remote Binding Example
아래 샘플은 dataPreLoad 속성을 사용하여 원격 데이터의 새 청크를 로드하는 원격 바인딩을 보여줍니다.
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
콤보박스를 원격 데이터에 바인딩할 때 서버에서 요청 시 데이터를 로드할 수 있는 서비스가 필요합니다. 콤보박스 구성 요소는 콤보박스의 현재 상태(첫 번째 인덱스 및 로드해야 하는 항목 수)를 제공하는 virtualizationState 속성을 노출합니다. 스크롤 크기를 제대로 표시하려면 totalItemCount 속성에 서버의 전체 항목에 해당하는 값이 있어야 합니다.
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
서비스에서 데이터가 관찰 가능 항목으로 반환되면 비동기 파이프를 사용하여 이를 콤보박스 구성 요소로 설정할 수 있습니다.
<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.
다음은 이미 정의된 작업을 수신하고 서버에 대한 요청을 실행하는 핸들러 목록입니다.
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
서비스가 공급자로 포함되어야 합니다.
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.
콤보박스가 원격 데이터에 바인딩되면 API를 통해 값/선택 항목을 설정하면 현재 청크에 로드된 항목만 고려됩니다. 초기값을 설정하려면 선택하기 전에 해당 특정 항목이 로드되었는지 확인하세요.
API Summary
Additional Resources
우리 커뮤니티는 활동적이며 항상 새로운 아이디어를 환영합니다.