콤보박스 원격 바인딩

    Ignite UI for Angular 콤보박스를 원격 서비스에 바인딩하고 요청 시 데이터를 검색할 수 있는 API를 노출합니다.

    Angular ComboBox Remote Binding Example

    아래 샘플은 dataPreLoad 속성을 사용하여 원격 데이터의 새 청크를 로드하는 원격 바인딩을 보여줍니다.

    Usage

    ComboBox 구성 요소를 시작하려면 먼저 IgxComboModule 당신의 app.module.ts 파일. 이 데모에서는 서버 요청에 원격 서비스가 사용되므로 다음도 포함해야 합니다. 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 속성에 서버의 전체 항목에 해당하는 값이 있어야 합니다.

    아래 코드는 콤보박스의 현재 상태 정보를 수신하고 관찰 가능 항목으로 데이터를 반환하는 getData() 메서드가 있는 간단한 서비스를 정의합니다.

    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()"
               [filterable]="true">
    </igx-combo>
    

    다음은 콤보박스 구성 요소가 새 데이터를 요청해야 하는 몇 가지 일반적인 경우입니다. - 콤보 상자가 초기화될 때 - 콤보 상자의 목록을 스크롤할 때 - 새 콤보 상자 virtualizationState와 함께 dataPreLoad 내보내므로 원격 서비스에 새 요청을 할 수 있습니다. - 콤보박스에서 검색할 때 - 원격 결과를 필터링하도록 요청해야 합니다. - 콤보박스가 열리면 이전 필터 작업의 결과를 지워야 합니다.

    다음은 이미 정의된 작업을 수신하고 서버에 대한 요청을 실행하는 핸들러 목록입니다.

    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

    청크로 로드된 원격 데이터에 바인딩된 콤보박스를 사용하고 더 복잡한 데이터 유형(예: 개체)을 처리할 때 valueKey를 정의해야 합니다. 콤보박스 항목에 명시된 대로 valueKey 지정되지 않으면 콤보박스는 equality (===)으로 선택을 처리하려고 시도합니다. 선택됨으로 표시되는 개체는 계속해서 로드되는 개체와 동일하지 않으므로 선택이 실패합니다.

    Note

    콤보박스를 원격 데이터에 바인딩할 때 각 항목에 고유한 속성을 나타내는 valueKey를 지정해야 합니다.

    콤보박스가 원격 데이터에 바인딩되면 API를 통해 값/선택 항목을 설정하면 현재 청크에 로드된 항목만 고려됩니다. 초기값을 설정하려면 선택하기 전에 해당 특정 항목이 로드되었는지 확인하세요.

    API Summary

    Additional Resources

    우리 커뮤니티는 활동적이며 항상 새로운 아이디어를 환영합니다.