Angular Grid 원격 데이터 작업
Ignite UI for Angular 원격 가상화, 원격 정렬, 원격 필터링 등과 같은 원격 데이터 작업을 지원합니다. 이를 통해 개발자는 서버에서 이러한 작업을 수행하고 생성된 데이터를 검색하여 Grid에 표시할 수 있습니다.
Angular Grid Remote Data Operations Overview Example
기본적으로 Grid는 데이터 작업을 수행하기 위해 자체 논리를 사용합니다. 이러한 작업을 원격으로 수행하고 그리드에 의해 노출되는 특정 입력 및 이벤트를 활용하여 결과 데이터를 그리드에 공급할 수 있습니다.
Remote Virtualization
IgxGrid는 데이터 청크가 원격 서비스에 요청되는 시나리오를 지원하며, 내부적으로 사용하는 지시문에igxForOf 구현된 동작을 노출시킵니다.
이 기능을 사용하려면 출력에dataPreLoad 구독하여 받은 인수에 따라 적절한 요청을 해야 하고, 서비스에서 나오는 해당 정보를 포함하는 공개 IgxGrid 속성을totalItemCount 설정해야 합니다.
<igx-grid #grid [data]="remoteData | async" [autoGenerate]="false"
(dataPreLoad)="processData(false)"
(sortingDone)="processData(true)">
<igx-column [field]="'ProductID'" [sortable]="true"></igx-column>
<igx-column [field]="'ProductName'" [sortable]="true"></igx-column>
<igx-column [field]="'UnitPrice'" [dataType]="'number'" [formatter]="formatCurrency" [sortable]="true"></igx-column>
</igx-grid>
public ngAfterViewInit() {
this.grid.isLoading = true;
this._remoteService.getData(this.grid.virtualizationState, this.grid.sortingExpressions[0], true, (data) => {
this.grid.totalItemCount = data['@odata.count'];
this.grid.isLoading = false;
});
}
public processData(reset) {
if (this.prevRequest) {
this.prevRequest.unsubscribe();
}
this._prevRequest = this._remoteService.getData(this.grid.virtualizationState,
this.grid.sortingExpressions[0], reset, () => {
...
this.cdr.detectChanges();
});
}
데이터를 요청할 때는 와IForOfState 속성을 제공하는startIndex 인터페이스를 사용해야chunkSize 합니다.
Note
첫 번째chunkSize 숫자는 항상 0이며, 구체적인 지원 상황에 따라 본인이 결정해야 합니다.
Remote Virtualization Demo
Infinite Scroll
엔드포인트에서 청크별로 데이터를 가져오는 시나리오에서 인기 있는 설계 중 하나는 이른바 무한 스크롤입니다. 데이터 그리드의 경우, 최종 사용자가 맨 아래까지 스크롤하면서 로드된 데이터가 지속적으로 증가하는 것이 특징입니다. 다음 단락에서는 제공되는 API를 활용해 무한 스크롤IgxGrid을 쉽게 구현하는 방법을 설명합니다.
무한 스크롤을 구현하려면 데이터를 청크로 가져와야 합니다. 이미 가져온 데이터는 로컬에 저장되어야 하며, 청크의 길이와 청크의 수를 결정해야 합니다. 또한 그리드에서 마지막으로 보이는 데이터 행 인덱스를 추적해야 합니다. 이렇게 하여 andstartIndex 속성을 사용하여chunkSize 사용자가 위로 스크롤해서 이미 가져온 데이터를 보여줘야 하는지, 아니면 아래로 스크롤해서 끝에서 더 많은 데이터를 가져와야 하는지 판단할 수 있습니다.
가장 먼저 해야 할 일은 라이프사이클 훅을ngAfterViewInit 사용해 데이터의 첫 번째 청크를 가져오는 것입니다. 속성 설정totalItemCount은 그리드가 스크롤바 크기를 정확히 조절할 수 있게 해주기 때문에 중요합니다.
public ngAfterViewInit() {
this._remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
if (request.data) {
this.grid.totalItemCount = this.page * this.pageSize;
this.grid.data = this._remoteService.getCachedData({startIndex: 0, chunkSize: 10});
this.totalItems = request.data['@odata.count'];
this.totalPageCount = Math.ceil(this.totalItems / this.pageSize);
this.grid.isLoading = false;
}
});
}
또한, 출력에dataPreLoad 구독해야 하므로, 그리드가 현재 로드된 청크가 아닌 다른 청크를 표시하려고 할 때 필요한 데이터를 제공할 수 있습니다. 이벤트 핸들러에서는 이미 로컬에 캐시된 데이터를 가져오거나 반환할지 결정해야 합니다.
public handlePreLoad() {
const isLastChunk = this.grid.totalItemCount ===
this.grid.virtualizationState.startIndex + this.grid.virtualizationState.chunkSize;
// when last chunk reached load another page of data
if (isLastChunk) {
if (this.totalPageCount === this.page) {
this.grid.data = this._remoteService.getCachedData(this.grid.virtualizationState);
return;
}
this.page++;
this.grid.isLoading = true;
this._remoteService.loadDataForPage(this.page, this.pageSize, (request) => {
if (request.data) {
this.grid.totalItemCount = Math.min(this.page * this.pageSize, this.totalItems);
this.grid.data = this._remoteService.getCachedData(this.grid.virtualizationState);
this.grid.isLoading = false;
}
});
} else {
this.grid.data = this._remoteService.getCachedData(this.grid.virtualizationState);
}
}
Infinite Scroll Demo
Remote Sorting/Filtering
원격 정렬과 필터링을 제공하려면 thedataPreLoad,sortingExpressionsChange andfilteringExpressionsTreeChange outputs에 구독하여 받은 인수에 따라 적절한 요청을 하고, 서비스에서 나오는 해당 정보를 포함하는 공개 IgxGrid 속성을totalItemCount 설정해야 합니다.
또한 rxjs debounceTime 함수를 활용할 것입니다. 이 함수는 특정 시간 동안 다른 소스 방출이 없을 때만 소스 Observable에서 값을 방출합니다. 이렇게 하면 사용자가 중단하지 않고 지정된 시간이 지나도 원격 조작이 활성화됩니다.
const DEBOUNCE_TIME = 300;
...
public ngAfterViewInit() {
...
this.grid.dataPreLoad.pipe(
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$)
).subscribe(() => {
this.processData();
});
this.grid.filteringExpressionsTreeChange.pipe(
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$)
).subscribe(() => {
this.processData(true);
});
this.grid.sortingExpressionsChange.pipe(
debounceTime(DEBOUNCE_TIME),
takeUntil(this.destroy$)
).subscribe(() => {
this.processData();
});
}
원격 정렬과 필터링이 제공될 때는 보통 그리드의 내장된 정렬과 필터링이 필요하지 않습니다. 우리는 다음 설정을 통해 이를 비활성화할 수 있습니다.sortStrategy 그리고filterStrategy 그리드의 입력을NoopSortingStrategy 그리고NoopFilteringStrategy 각각의 사례들.
<igx-grid #grid [data]="remoteData | async" [height]="'500px'" [width]="'100%'" [autoGenerate]='false'
[filterStrategy]="noopFilterStrategy"
[sortStrategy]="noopSortStrategy"
[allowFiltering]="true">
...
</igx-grid>
public noopFilterStrategy = NoopFilteringStrategy.instance();
public noopSortStrategy = NoopSortingStrategy.instance();
Note
원격 데이터가 요청되면 필터링 작업은 대소문자를 구분합니다.
Remote Sorting/Filtering Demo
데모 섹션의 이 문서 시작 부분에서 위의 코드 결과를 볼 수 있습니다.
Unique Column Values Strategy
엑셀 스타일 필터링 대화상자 내의 목록 항목들은 해당 열의 고유 값을 나타냅니다. 그리드는 기본적으로 데이터 소스를 기반으로 이 값을 생성합니다. 원격 필터링의 경우, 그리드 데이터에 서버의 모든 데이터가 포함되지 않습니다. 고유 값을 수동으로 제공하고 필요할 때 로드하기 위해 그리드의uniqueColumnValuesStrategy 입력을 활용할 수 있습니다. 이 입력은 실제로 세 가지 인수를 제공하는 메서드입니다:
- 열- 해당 열 인스턴스입니다.
- filteringExpressionsTree- 해당 열을 기준으로 축소된 필터링 표현식 트리입니다.
- done- 서버에서 검색될 때 새로 생성된 열 값으로 호출되어야 하는 콜백입니다.
개발자는 열과 filteringExpressionsTree 인수에서 제공되는 정보를 기반으로 필요한 고유 열 값을 수동으로 생성한 다음 완료 콜백을 호출할 수 있습니다.
Note
입력이uniqueColumnValuesStrategy 제공되면, 엑셀 스타일 필터링의 기본 고유 값 생성 프로세스는 사용되지 않습니다.
<igx-grid #grid1 [data]="data" [filterMode]="'excelStyleFilter'" [uniqueColumnValuesStrategy]="columnValuesStrategy">
...
</igx-grid>
public columnValuesStrategy = (column: ColumnType,
columnExprTree: IFilteringExpressionsTree,
done: (uniqueValues: any[]) => void) => {
// Get specific column data.
this.remoteValuesService.getColumnData(column, columnExprTree, uniqueValues => done(uniqueValues));
}
Unique Column Values Strategy Demo
엑셀 스타일 필터링을 위한 맞춤 로딩 템플릿을 제공하기 위해 다음igxExcelStyleLoading 지시를 사용할 수 있습니다:
<igx-grid [data]="data" [filterMode]="'excelStyleFilter'" [uniqueColumnValuesStrategy]="columnValuesStrategy">
...
<ng-template igxExcelStyleLoading>
Loading ...
</ng-template>
</igx-grid>
Remote Paging
페이징 기능은 원격 데이터로 작동할 수 있습니다. 이를 시연하기 위해 먼저 데이터 가져오기를 담당할 서비스를 선언하겠습니다. 페이지 수를 계산하려면 모든 데이터 항목의 수가 필요합니다. 이 로직은 우리 서비스에 추가될 예정입니다.
@Injectable()
export class RemotePagingService {
public remoteData: BehaviorSubject<any[]>;
public dataLenght: BehaviorSubject<number> = new BehaviorSubject(0);
public url = 'https://www.igniteui.com/api/products';
constructor(private http: HttpClient) {
this.remoteData = new BehaviorSubject([]) as any;
}
public getData(index?: number, perPage?: number): any {
let qS = '';
if (perPage) {
qS = `?$skip=${index}&$top=${perPage}&$count=true`;
}
this.http
.get(`${this.url + qS}`).pipe(
map((data: any) => data)
).subscribe((data) => this.remoteData.next(data));
}
public getDataLength(): any {
return this.http.get(this.url).pipe(
map((data: any) => data.length)
);
}
}
서비스를 선언한 후에는 그리드 구성 및 데이터 구독을 담당할 구성 요소를 생성해야 합니다.
export class RemotePagingGridSample implements OnInit, AfterViewInit, OnDestroy {
public data: Observable<any[]>;
private _dataLengthSubscriber;
constructor(private remoteService: RemoteService) {}
public ngOnInit() {
this.data = this.remoteService.remoteData.asObservable();
this._dataLengthSubscriber = this.remoteService.getDataLength().subscribe((data) => {
this.totalCount = data;
this.grid1.isLoading = false;
});
}
public ngOnDestroy() {
if (this._dataLengthSubscriber) {
this._dataLengthSubscriber.unsubscribe();
}
}
}
이제 저희가 직접 맞춤 페이징 템플릿을 설정할지, 아니면 기본igx-paginator 템플릿을 사용할 수 있겠죠. 먼저 기본 페이징 템플릿을 사용해 원격 페이징을 설정하는 데 필요한 사항을 살펴보겠습니다.
Remote paging with default template
기본 페이징 템플릿을 사용하려면 Paginator의totalRecords 속성을 설정해야 하며, 그래야 그리드가 전체 원격 레코드를 기반으로 전체 페이지 수를 계산할 수 있습니다. 원격 페이지네이션을 수행할 때 페이지네이터는 현재 페이지의 데이터만 그리드에 전달하므로, 그리드는 제공된 데이터 소스를 페이지네이션하려 하지 않습니다. 그래서 Grid의pagingMode 속성을 GridPagingMode.remote로 설정해야 합니다. 또한 원격 서비스에서 데이터를 가져오려면 이벤트에 구독pagingDoneperPageChange 해야 하며, 어떤 이벤트를 사용할지는 사용 사례에 따라 다릅니다.
<igx-grid #grid1 [data]="data | async" [isLoading]="isLoading" [pagingMode]="mode">
<igx-column field="ID"></igx-column>
...
<igx-paginator [(page)]="page" [(perPage)]="perPage" [totalRecords]="totalCount"
(pagingDone)="paginate($event.current)">
</igx-paginator>
</igx-grid>
public totalCount = 0;
public data: Observable<any[]>;
public mode = GridPagingMode.remote;
public isLoading = true;
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
private _dataLengthSubscriber;
public set perPage(val: number) {
this._perPage = val;
this.paginate(0);
}
public ngOnInit() {
this.data = this.remoteService.remoteData.asObservable();
this._dataLengthSubscriber = this.remoteService.getDataLength().subscribe((data: any) => {
this.totalCount = data;
this.grid1.isLoading = false;
});
}
public ngAfterViewInit() {
const skip = this.page * this.perPage;
this.remoteService.getData(skip, this.perPage);
}
public paginate(page: number) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
}
Remote Paging with custom igx-paginator-content
커스텀 페이지네이터 콘텐츠를 정의할 때, 요청된 페이지에만 데이터를 얻고 올바른 데이터를 전달할 수 있도록 콘텐츠를 정의해야 합니다 거르다 그리고 맨 위로 선택한 페이지와 항목에 따라 원격 서비스에 대한 매개변수perPage. 우리는<igx-paginator> 예제 구성을 쉽게 하기 위해,IgxPageSizeSelectorComponent 그리고IgxPageNavigationComponent 도입된 사람들 -igx-page-size페이지별 드롭다운과 라벨을 추가합니다igx-page-nav 내비게이션 액션 버튼과 라벨을 추가할 예정입니다.
<igx-paginator #paginator
[totalRecords]="totalCount"
[(page)]="page"
[(perPage)]="perPage"
[selectOptions]="selectOptions"
(pageChange)="paginate($event)"
(perPageChange)="perPageChange($event)">
<igx-paginator-content>
<igx-page-size></igx-page-size>
[This is my custom content]
<igx-page-nav></igx-page-nav>
</igx-paginator-content>
</igx-paginator>
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
private _perPage = 15;
private _dataLengthSubscriber: { unsubscribe: () => void; } | undefined;
constructor(private remoteService: RemotePagingService) { }
public ngAfterViewInit() {
this.grid1.isLoading = true;
this.remoteService.getData(0, this.perPage);
}
public paginate(page: number) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
}
public perPageChange(perPage: number) {
const skip = this.page * perPage;
const top = perPage;
this.remoteService.getData(skip, top);
}
Note
원격 페이징을 올바르게 구성하려면 다음을GridPagingMode.Remote 설정해야 합니다:
<igx-grid #grid1 [data]="data | async" width="100%" height="580px" [pagingMode]="mode"></igx-grid>
...
public mode = GridPagingMode.Remote;
마지막 단계는 요구 사항에 따라 페이지네이터 콘텐츠를 선언하는 것입니다.
<igx-paginator-content>
<igx-page-size></igx-page-size>
[This is my custom content]
<igx-page-nav></igx-page-nav>
</igx-paginator-content>
위의 모든 변경 후에는 다음과 같은 결과가 달성됩니다.
Remote Paging with custom paginator
경우에 따라 고유한 페이징 동작을 정의하고 싶을 수 있으며 이때 페이징 템플릿을 활용하고 사용자 지정 논리를 함께 추가할 수 있습니다. 이를 보여주기 위해 원격 페이징 예제를 확장하겠습니다.
아래에는 저희nextprevious가 자체 및 페이지 액션을 구현하기 위해 정의한 방법들을 확인할 수 있습니다.
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
public ngAfterViewInit() {
this.grid1.isLoading = true;
this.remoteService.getData(0, this.perPage);
}
public nextPage() {
this.firstPage = false;
this.page++;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
if (this.page + 1 >= this.totalPages) {
this.lastPage = true;
}
this.setNumberOfPagingItems(this.page, this.totalPages);
}
public previousPage() {
this.lastPage = false;
this.page--;
const skip = this.page * this.perPage;
const top = this.perPage;
this.remoteService.getData(skip, top);
if (this.page <= 0) {
this.firstPage = true;
}
this.setNumberOfPagingItems(this.page, this.totalPages);
}
public paginate(page: number, recalculate = false) {
this.page = page;
const skip = this.page * this.perPage;
const top = this.perPage;
if (recalculate) {
this.totalPages = Math.ceil(this.totalCount / this.perPage);
}
this.setNumberOfPagingItems(this.page, this.totalPages);
this.remoteService.getData(skip, top);
this.buttonDeselection(this.page, this.totalPages);
}
Remote Paging with Batch editing
지금까지의 예제를 통해 원격 데이터로 IgxGrid를 설정하는 방법을 명확히 했습니다. 이제 일괄 편집 항목/가이드에 따라 그리드에 대한 일괄 편집을 활성화하는 데 중점을 두겠습니다.
샘플을 계속하기 전에 현재 사용 사례를 명확히 하는 것이 좋습니다. 서버에서 페이지 매김이 수행되면 그리드에는 현재 페이지에 대한 데이터만 포함되며 새 행을 추가하면 새로 추가된 행(일괄 편집 사용)이 그리드에 포함된 현재 데이터와 연결됩니다. 따라서 서버가 특정 페이지에 대해 데이터를 반환하지 않으면 그리드의 데이터 소스는 새로 추가된 행으로만 구성되며 그리드는 정의된 페이지 매김 설정(페이지, 페이지당)에 따라 페이지를 매깁니다.
public ngOnInit() {
this._dataLengthSubscriber = this.remoteService.getDataLength().subscribe((data) => {
this.totalCount = data;
this._recordOnServer = data;
this._totalPagesOnServer = Math.floor(this.totalCount / this.perPage);
this.grid1.isLoading = false;
});
}
이 사용 사례를 제대로 처리하려면 맞춤형 로직을 구현해야 합니다. 먼저, 서버에 저장된 레코드의 총 수를 알아야 합니다. 이를 고려하면, 서버에 저장된 총 데이터 페이지 수를 계산하고(참조this._totalPagesOnServer), 그 값을 바탕으로 맞춤형 페이지네이션 로직을 구현할 것입니다.
public paginate(page: number) {
this.grid1.endEdit(true);
if (page > this._totalPagesOnServer) {
if (this.page !== this._totalPagesOnServer) {
const skipEl = this._totalPagesOnServer * this.perPage;
this.remoteService.getData(skipEl, this.perPage);
}
this.page = page - this._totalPagesOnServer;
this.page = page;
return;
} else {
this.page = 0;
}
this.page = page;
const skip = this.page * this.perPage;
this.remoteService.getData(skip, this.perPage);
}
페이지네이트 메서드에서 보시다시피, 값에_totalPagesOnServer 따라 맞춤형 페이지네이션 로직이 수행됩니다.
일괄 편집 데모를 통한 원격 페이징
Known Issues and Limitations
- 그리드에 세트가 없
primaryKey고 원격 데이터 시나리오가 활성화되어 있을 때(페이징, 정렬, 필터링, 스크롤 시 원격 서버에 표시할 데이터를 가져오기 요청이 트리거될 때), 데이터 요청이 완료된 후 다음 상태가 줄로 사라집니다:- 행 선택
- 행 확장/축소
- 행 편집
- 행 고정
- 원격 데이터 시나리오에서는 격자
primaryKey에 set,eventrowSelectionChanging.oldSelection인자가 현재 데이터 뷰 밖에 있는 행의 전체 행 데이터 객체를 포함하지 않습니다. 이 경우 객체는rowSelectionChanging.oldSelection필드 속성 중 하나primaryKey만 포함합니다. 나머지 행들은 현재 데이터 뷰에 위치해 있으며,rowSelectionChanging.oldSelection전체 행 데이터를 포함하게 됩니다.