Angular Grid の選択ベースのデータ集計
以下のサンプルでは、グリッドのフッターで選択した値に基づいて、カスタム集計関数と共に集計を表示する際の複数選択の動作を確認できます。
トピックの概要
選択に基づいた集計機能を実現するには、グリッド選択
機能とグリッド集計
を使用できます。
集計では、列のデータ タイプとニーズに応じて、IgxSummaryOperand
、IgxNumberSummaryOperand
、IgxDateSummaryOperand
のいずれかの基本クラスを拡張することにより、基本的な集計機能をカスタマイズできます。
選択
選択したグリッド範囲のデータの操作を開始するには、グリッド選択の変更を通知するイベントにサブスクライブする必要があります。これは、selected
と rangeSelected
イベントにサブスクライブすることで実行できます。選択機能では、単一のセル選択とセル範囲の選択が区別されるため、両方にバインドする必要があります。
イベント サブスクリプション ロジックでは、グリッドの getSelectedData
関数を使用して選択したデータを抽出し、選択したデータをカスタム集計オペランドに渡すことができます。
まとめ
カスタム集計クラス内では、グリッドのデータ タイプを差別化する必要があります。たとえば、以下のシナリオでは、4 つの異なる列があり、それぞれのデータ タイプがカスタム集計に適しています。それらは、Unit Price、Units in Stock、Discontinued status、Order Date です。
IgxSummaryOperand
の派生クラスの operate
メソッドでデータを処理します。データ タイプに基づいて、さまざまなカテゴリにデータを入れていきます。
const numberData = data.filter(rec => typeof rec === "number");
const boolData = data.filter(rec => typeof rec === "boolean");
const dates = data.filter(rec => isDate(rec));
typescript
isDate
はカスタム関数であることに注意してください。
データ タイプをグループ化した後、集計を開始できます。そのため、IgxNumberSummaryOperand
および IgxDateSummaryOperand
の既に公開されているメソッドを使用できます。
その後、集計データを同じ配列に配置する必要があり、テンプレートに返されます。
データを可視化には、<igx-grid-footer>
を使用することができ、custom-summaries
クラスと組み合わせて集計を表示します。
デモ
選択を変更して、現在選択されている範囲の概要を表示します。
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser";
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { AppComponent } from "./app.component";
import { GridCustomSummariesSelectionComponent } from "./grid/grid-custom-summaries-selection/grid-custom-summaries-selection.component";
import { IgxGridModule } from "igniteui-angular";
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive";
@NgModule({
bootstrap: [AppComponent],
declarations: [
AppComponent,
GridCustomSummariesSelectionComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxGridModule
],
providers: [],
entryComponents: [],
schemas: []
})
export class AppModule {}
ts
import { formatDate } from '@angular/common';
import { AfterViewInit, Component, ViewChild, OnInit, ChangeDetectorRef} from '@angular/core';
import { IgxDateSummaryOperand, IgxGridComponent, IgxNumberSummaryOperand,
IgxSummaryOperand, IgxSummaryResult } from 'igniteui-angular';
import { DATA } from '../../data/nwindData';
class MySummary {
public operate(data: any[] = []): IgxSummaryResult[] {
const result = new IgxSummaryOperand().operate(data);
if (data.length < 1) { return result; }
const numberData = data.filter(rec => typeof rec === 'number');
const boolData = data.filter(rec => typeof rec === 'boolean');
const dates = data.filter(rec => isDate(rec));
if (numberData.length) {
result.push({ key: 'min', label: 'Min', summaryResult: IgxNumberSummaryOperand.min(numberData)});
result.push({ key: 'max', label: 'Max', summaryResult: IgxNumberSummaryOperand.max(numberData)});
result.push({ key: 'avg', label: 'Avg', summaryResult: IgxNumberSummaryOperand.average(numberData)});
result.push({ key: 'sum', label: 'Sum', summaryResult: IgxNumberSummaryOperand.sum(numberData)});
}
if (boolData.length) {
result.push({
key: 'test', label: 'Discounted',
summaryResult: boolData.filter(rec => rec).length + ' of ' + boolData.length });
}
if (dates.length) {
result.push({ key: 'earliest', label: 'Earliest', summaryResult: IgxDateSummaryOperand.earliest(dates)});
result.push({ key: 'latest', label: 'Latest', summaryResult: IgxDateSummaryOperand.latest(dates)});
}
return result;
}
}
@Component({
selector: 'app-grid-sample',
styleUrls: ['./grid-custom-summaries-selection.component.scss'],
templateUrl: 'grid-custom-summaries-selection.component.html'
})
export class GridCustomSummariesSelectionComponent implements AfterViewInit, OnInit {
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;
public data: any[];
public selectionSummaries = [];
private customSummary = new MySummary();
constructor(private cdr: ChangeDetectorRef) { }
public ngOnInit(): void {
this.data = DATA;
}
public ngAfterViewInit(): void {
this.grid1.setSelection({
rowStart: 2, rowEnd: 4,
columnStart: 1, columnEnd: 4
});
this.calculateSummary();
this.cdr.detectChanges();
}
public format(value: any) {
if (typeof value === 'number') {
return value.toFixed(2);
} else if (isDate(value)) {
return formatDate(value, 'mediumDate', 'en');
}
return value;
}
public formatCurrency(value: number) {
if (!value) { return; }
return '$' + value.toFixed(2);
}
public calculateSummary() {
this.selectionSummaries = this.customSummary.operate(this.toArray(this.grid1.getSelectedData()));
}
public toArray(data) {
let result = [];
data.forEach(rec => result = result.concat(Object.values(rec)));
return result;
}
}
function isDate(value: any) {
return Object.prototype.toString.call(value) === '[object Date]';
}
ts
<div class="grid__wrapper">
<igx-grid [igxPreventDocumentScroll]="true" #grid1 [data]="data" [height]="'530px'" [width]="'100%'"
(selected)='calculateSummary()'
(rangeSelected)='calculateSummary()'>
<igx-column [field]="'ProductID'"></igx-column>
<igx-column [field]="'ProductName'"></igx-column>
<igx-column [field]="'UnitPrice'" [dataType]="'number'" [formatter]="formatCurrency"></igx-column>
<igx-column [field]="'UnitsInStock'" [dataType]="'number'"></igx-column>
<igx-column [field]="'Discontinued'" [dataType]="'boolean'">
<ng-template igxCell let-cell="cell" let-val>
<img *ngIf="val" src="https://www.infragistics.com/angular-demos-lob/assets/images/grid/active.png" title="Continued" alt="Continued" />
<img *ngIf="!val" src="https://www.infragistics.com/angular-demos-lob/assets/images/grid/expired.png" title="Discontinued" alt="Discontinued" />
</ng-template>
</igx-column>
<igx-column [field]="'OrderDate'" [dataType]="'date'"></igx-column>
<igx-grid-footer>
<div class="custom-summaries">
<div *ngFor="let summary of selectionSummaries" class="summaries-data-wrapper" [ngClass]="grid1.displayDensity">
<span class="igx-grid-summary__label">{{ summary.label }}</span>
<span class="igx-grid-summary__result">{{ format(summary.summaryResult) }}</span>
</div>
</div>
</igx-grid-footer>
</igx-grid>
</div>
html
.cellAlignSyle {
text-align: right;
float:right;
}
.cellAlignSyle > span {
float:right;
}
.up {
color: green;
}
.down {
color: red;
}
.headerAlignSyle {
text-align: right !important;
}
.sample-container {
width: 20%;
display: flex;
margin: 0% 0% 20px 10px
}
.grid-controls {
display: flex;
justify-content: space-between;
margin: 0 16px 24px;
flex-flow: column;
align-items: flex-start;
}
.grid__wrapper {
margin: 0 16px;
padding-top: 16px;;
}
.currency-badge-container {
width: 80px;
float: right;
}
.badge-left {
float: left;
}
div.igx-grid__tfoot {
z-index: 1;
}
.custom-summaries {
margin-left: auto;
width: 100%;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.summaries-data-wrapper { display: inline-block; }
.summaries-data-wrapper span:first-child { margin-right: 16px }
.cosy {
padding-right: 16px;
}
.compact {
padding-right: 12px;
}
.comfortable {
padding-right: 24px;
}
scss
API リファレンス
その他のリソース
コミュニティに参加して新しいアイデアをご提案ください。