Angular Master-Detail Grid
igxGrid
コンポーネントは、コンテンツを展開/縮小することで特定の行の追加の詳細を表示する detail テンプレートの指定をサポートします。指定した場合、各レコードは master として機能し、展開すると、現在のレコードのコンテキスト データを含むカスタマイズ可能な詳細テンプレートが表示されます。
このモードは、master-detail スタイル データを階層構造で表示する必要がある場合に役立ちます。
Angular Grid Master-Detail の例
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 { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive";
import { GridMasterDetailSampleComponent } from "./grid/grid-master-detail/grid-master-detail.component";
import {
IgxGridModule,
IgxAvatarModule,
IgxTabsModule,
IgxIconModule,
IgxDividerModule
} from "igniteui-angular";
import {
IgxCategoryChartModule,
IgxPieChartModule,
IgxLegendModule
} from "igniteui-angular-charts";
@NgModule({
bootstrap: [AppComponent],
declarations: [
AppComponent,
GridMasterDetailSampleComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxGridModule,
IgxCategoryChartModule,
IgxPieChartModule,
IgxLegendModule,
IgxAvatarModule,
IgxTabsModule,
IgxIconModule,
IgxDividerModule
],
providers: [],
entryComponents: [],
schemas: []
})
export class AppModule {}
ts
import { Component, ViewChild } from '@angular/core';
import { IgxColumnComponent } from 'igniteui-angular';
import { IgxLegendComponent } from 'igniteui-angular-charts';
import { employeesData } from '../../data/employeesData';
@Component({
selector: 'app-grid-master-detail',
styleUrls: ['./grid-master-detail.component.scss'],
templateUrl: 'grid-master-detail.component.html'
})
export class GridMasterDetailSampleComponent {
@ViewChild('legend', { static: true })
public legend: IgxLegendComponent;
public data = [];
public include = ['date', 'estimated', 'actual'];
constructor() {
this.data = employeesData;
}
public getHeight(selectedIndex) {
switch (selectedIndex) {
case 0: return 250;
case 1: return 320;
case 2: return 400;
default: return 250;
}
}
public formatPieLabel = (args) => args.item.Value + ' ' + args.item.Label;
public formatDateLabel(item: any): string {
return item.date.toLocaleDateString(undefined, { month: 'short' });
}
public formatValue(val: any): string {
return val.toLocaleString('en-us', { maximumFractionDigits: 2 });
}
public getPieData(dataItem) {
return [
{ Label: 'Won', Value: dataItem.deals_won },
{ Label: 'Lost', Value: dataItem.deals_lost },
{ Label: 'Pending', Value: dataItem.deals_pending }];
}
public getChartData(dataItem) {
const year: number = new Date().getFullYear();
const sales: any[] = [];
for (let i = 0; i < 12; i++) {
const value = this.getRandomNumber(2000, 10000);
sales.push({
estimated: value + this.getRandomNumber(-2000, 1000),
actual: value, date: new Date(year, i, 1)
});
}
dataItem.chartData = sales;
return dataItem.chartData;
}
public gridData(dataItem) {
const detailsData = [];
let won = dataItem.deals_won;
let lost = dataItem.deals_lost;
let pending = dataItem.deals_pending;
for (let j = 0; j < 3; j++) {
detailsData.push({
Q: 'Q' + (j + 1),
Won: this.getRandomNumber(0, won),
Lost: this.getRandomNumber(0, lost),
Pending: this.getRandomNumber(0, pending)
});
won -= detailsData[j].Won;
lost -= detailsData[j].Lost;
pending -= detailsData[j].Pending;
}
detailsData.push({
Q: 'Q4',
Won: won,
Lost: lost,
Pending: pending
});
dataItem.gridData = detailsData;
return dataItem.gridData;
}
public columnInit(event: IgxColumnComponent) {
if (event.field === 'Q') {
event.width = '50px';
event.header = ' ';
}
}
public getRandomNumber(min: number, max: number): number {
return Math.round(min + Math.random() * (max - min));
}
}
ts
<div class="grid__wrapper">
<igx-grid [igxPreventDocumentScroll]="true" displayDensity="cosy" [data]="data" [autoGenerate]="false" height="592px" width="100%">
<igx-column field="name" header="Name" width="250px"></igx-column>
<igx-column field="position" header="Position"></igx-column>
<igx-column field="company" header="Company"></igx-column>
<igx-column field="email" header="Email"></igx-column>
<igx-column field="referred_by" header="Referrer"></igx-column>
<ng-template igxGridDetail let-dataItem>
<div style="width:100%;" (keydown)='$event.stopPropagation()' [style.height.px]='getHeight(tabs.selectedIndex)'>
<igx-tabs #tabs [selectedIndex]="0">
<igx-tab-item>
<igx-tab-header>
<span igxTabHeaderLabel>Details</span>
</igx-tab-header>
<igx-tab-content>
<div class="tabContent">
<div class="avatarContainer">
<igx-avatar src="{{dataItem.avatar}}"
[roundShape]="false" size="large"></igx-avatar>
<h6>{{dataItem.name}}</h6>
</div>
<igx-divider [vertical]="true"></igx-divider>
<div class="tabInnerContent">
<div class="breathingcontent">
<div><span
class="categoryStyle">Country: </span><span>{{dataItem.country}}</span>
</div>
<div><span class="categoryStyle">City: </span><span>{{dataItem.city}}</span>
</div>
<div><span
class="categoryStyle">Street: </span><span>{{dataItem.street}}</span>
</div>
<div><span class="categoryStyle">Work
Phone: </span><span>{{dataItem.work_phone}}</span></div>
<div><span class="categoryStyle">Mobile
Phone: </span><span>{{dataItem.mobile_phone}}</span></div>
</div>
</div>
</div>
</igx-tab-content>
</igx-tab-item>
<igx-tab-item>
<igx-tab-header>
<span igxTabHeaderLabel>Deals</span>
</igx-tab-header>
<igx-tab-content>
<div class="tabContent">
<igx-pie-chart [dataSource]="getPieData(dataItem)" [formatLabel]="formatPieLabel"
[outlines]="['transparent']"
[brushes]="['rgb(171, 223, 29)', 'rgb(228, 19, 16)', 'rgb(0, 111, 138)']"
class="details-chart" labelsPosition="insideEnd" leaderLineVisibility="collapsed"
labelMemberPath="Label" valueMemberPath="Value">
</igx-pie-chart>
<igx-divider [vertical]="true"></igx-divider>
<igx-grid [data]="dataItem.gridData ? dataItem.gridData: gridData(dataItem)"
[autoGenerate]="true" class="details-grid" columnWidth="70px" displayDensity="cosy"
width="260px" height="206px" (columnInit)="columnInit($event)">
</igx-grid>
</div>
</igx-tab-content>
</igx-tab-item>
<igx-tab-item>
<igx-tab-header>
<span igxTabHeaderLabel>Sales</span>
</igx-tab-header>
<igx-tab-content>
<div class="tabContent" style="flex-direction: column;">
<igx-legend #legend orientation="horizontal"></igx-legend>
<igx-category-chart height="250px" [legend]="legend"
[dataSource]="dataItem.chartData ? dataItem.chartData : getChartData(dataItem)"
chartType="Line" chartTitle="Sales" subtitle="(Estimated, Actual)" xAxisInterval="1"
[brushes]="['rgb(0, 111, 138)', 'rgb(171, 223, 29)']"
[xAxisFormatLabel]="formatDateLabel" [includedProperties]="include"
[crosshairsSnapToData]="false"
[crosshairsDisplayMode]="'Both'" [crosshairsAnnotationEnabled]="true"
isHorizontalZoomEnabled="false" isVerticalZoomEnabled="false">
</igx-category-chart>
</div>
</igx-tab-content>
</igx-tab-item>
</igx-tabs>
</div>
</ng-template>
</igx-grid>
</div>
html
@use '../../../variables' as *;
.categoryStyle{
font-weight: 600;
}
.tabContent {
padding: rem(24px) rem(8px);
display: flex;
justify-content: flex-start;
margin: rem(10px);
}
.avatarContainer {
display: flex;
align-items: center;
flex-direction: column;
}
igx-divider {
margin: 0 rem(24px) !important;
}
h6 {
margin-top: 1em;
}
.details-chart {
width: rem(200px);
background: contrast-color($color: 'gray', $variant: 900);
background: contrast-color($color: 'gray', $variant: 900);
padding: rem(16px);
border-radius: rem(4px);
border: rem(1px) solid contrast-color($color: 'gray', $variant: 900);
}
.tabContent igx-grid {
box-shadow: none;
border: rem(1px) solid contrast-color($color: 'gray', $variant: 900);
}
.grid__wrapper {
margin: rem(4px) rem(16px);
}
scss
このサンプルが気に入りましたか? 完全な Ignite UI for Angularツールキットにアクセスして、すばやく独自のアプリの作成を開始します。無料でダウンロードできます。
構成
Master-detail モードで表示するように igxGrid
を設定するには、igxGridDetail
ディレクティブでマークされたグリッド内のテンプレートを指定する必要があります。
<igx-grid ... >
<ng-template igxGridDetail let-dataItem>
</ng-template>
</igx-grid>
html
テンプレートのコンテキストはマスター レコード データであるため、マスター レコードの値を詳細テンプレートに表示できます。例:
<igx-grid ... >
<ng-template igxGridDetail let-dataItem>
<div *ngIf="dataItem.Category">
<header>{{dataItem.Category.CategoryName}}</header>
<span>{{dataItem.Category.Description}}</span>
</div>
</ng-template>
</igx-grid>
html
API
展開状態は、igxGrid
の expansionStates
入力で制御できます。状態はキーと値のペア [行識別子、展開状態] に保存されます。このプロパティは、展開状態を取得/設定し、双方向バインディングをサポートします。
<igx-grid [(expansionStates)]='expansionState' >
...
</igx-grid>
html
展開状態を制御するための追加の API メソッドも公開されています。
キーボード ナビゲーション
詳細行にフォーカスがある場合:
上矢印
- 前の行のセルにフォーカスし、1 つ上の行へ移動します。
下矢印
- 次の行のセルにフォーカスし、1 つ下の行へ移動します。
Tab
- フォーカス可能な要素がある場合、テンプレート内の次のフォーカス可能な要素にフォーカスを移動します。そうでない場合は、次のグリッド行に移動します。
Shift + Tab
- 前の行にフォーカスします。
エキスパンダーのデータ行にフォーカスがある場合:
Alt + 右矢印/下矢印
- 行を展開します。
Alt + 左矢印/下矢印
- 行を縮小します。
既知の問題と制限
既知の制限 |
説明 |
カスタム詳細テンプレート内のタブ ナビゲーションは、次のフォーカスされた要素が表示ビュー ポート以外にある場合、マスター グリッドのスクロール位置を更新しない場合があります。 |
カスタム詳細テンプレート内のタブ ナビゲーションは、ブラウザーに残されています。 |
カスタム詳細テンプレート内のタブ ナビゲーションは、次のフォーカスされた要素が表示ビュー ポート以外にある場合、マスター グリッドのスクロール位置を更新しない場合があります。カスタム詳細テンプレート内のタブ ナビゲーションは、ブラウザーに残されています。 |
これは、ネストされたグリッドで autoGenerate=true を使用して回避できます。これらの列の要素を変更する必要がある場合、columnInit イベントを使用できます。 |
詳細テンプレートは Excel にエクスポートされません。 |
詳細テンプレートにはあらゆる種類のコンテンツが含まれているため、Excel にエクスポートすることはできません。 |
検索機能は、詳細テンプレートの要素を強調表示しません。 |
|
API リファレンス