Angular Grid のセル編集
Ignite UI for Angular Grid コンポーネントは、Angular CRUD 操作のための優れたデータ操作機能と強力な API を提供します。デフォルトで Grid はセル編集 を使用し、デフォルトのセル編集テンプレート によって、列のデータ型に基づいてさまざまなエディターが表示されます。さらに、データ更新アクション用の独自のカスタム テンプレートを定義したり、変更をコミット/破棄したりするためのデフォルトの動作をオーバーライドすることもできます。
Angular Grid セル編集とセル テンプレートの例
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 {
IgxButtonModule,
IgxCheckboxModule,
IgxDatePickerModule,
IgxDialogModule,
IgxGridModule,
IgxInputGroupModule,
IgxIconModule,
IgxComboModule,
IgxToastModule,
IgxRippleModule
} from "igniteui-angular" ;
import { GridEditingSampleComponent } from "./grid/grid-editing-sample/grid-editing-sample.component" ;
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
GridEditingSampleComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxButtonModule,
IgxCheckboxModule,
IgxDatePickerModule,
IgxDialogModule,
IgxGridModule,
IgxInputGroupModule,
IgxIconModule,
IgxRippleModule,
IgxToastModule,
IgxComboModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxDialogComponent, IgxGridComponent, IgxSummaryResult, IgxNumberSummaryOperand, IgxToastComponent, VerticalAlignment } from 'igniteui-angular' ;
import { DATA, LOCATIONS } from './data' ;
import { Product } from './product' ;
class NumberSummary {
public operate(data: any []): IgxSummaryResult[] {
const result = [];
result.push({
key : 'max' ,
label : 'Max' ,
summaryResult : IgxNumberSummaryOperand.max(data)
});
result.push({
key : 'sum' ,
label : 'Sum' ,
summaryResult : IgxNumberSummaryOperand.sum(data)
});
result.push({
key : 'avg' ,
label : 'Avg' ,
summaryResult : IgxNumberSummaryOperand.average(data)
});
return result;
}
}
@Component ({
selector : 'app-grid-editing-sample' ,
styleUrls : ['./grid-editing-sample.component.scss' ],
templateUrl : './grid-editing-sample.component.html'
})
export class GridEditingSampleComponent implements OnInit , AfterViewInit {
@ViewChild ('grid1' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
@ViewChild ('dialogAdd' , { read : IgxDialogComponent, static : true })
public dialog: IgxDialogComponent;
@ViewChild ('toast' , { read : IgxToastComponent, static : false })
public toast: IgxToastComponent;
public data;
public locations;
public product;
public customOverlaySettings;
public id;
public numSummary = NumberSummary;
public ngOnInit ( ) {
this .data = DATA.map((e ) => {
const index = Math .floor(Math .random() * LOCATIONS.length);
const count = Math .floor(Math .random() * 3 ) + 1 ;
e.Locations = [...LOCATIONS].splice(index, count);
return e;
});
this .id = this .data.length;
this .product = new Product(this .id);
this .locations = LOCATIONS;
}
public ngAfterViewInit ( ) {
this .customOverlaySettings = {
outlet : this .grid1.outlet
};
}
public removeRow (rowIndex ) {
const row = this .grid1.getRowByIndex(rowIndex);
row.delete();
}
public addRow ( ) {
const id = this .product.ProductID;
this .grid1.addRow(this .product);
this .grid1.cdr.detectChanges();
this .cancel();
this .grid1.paginator.page = this .grid1.paginator.totalPages - 1 ;
this .grid1.cdr.detectChanges();
let row;
requestAnimationFrame(() => {
const index = this .grid1.filteredSortedData ? this .grid1.filteredSortedData.map(rec => rec['ProductID' ]).indexOf(id) :
(row = this .grid1.getRowByKey(id) ? row.index : undefined );
this .grid1.navigateTo(index, -1 );
});
}
public cancel ( ) {
this .dialog.close();
this .id++;
this .product = new Product(this .id);
}
public parseArray(arr: { shop : string , lastInventory : string }[]): string {
return (arr || []).map((e ) => e.shop).join(', ' );
}
public show (args ) {
const message = `The product: {name: ${args.data.ProductName} , ID ${args.data.ProductID} } has been removed!` ;
this .toast.positionSettings.verticalDirection = VerticalAlignment.Middle;
this .toast.open(message);
}
}
ts コピー <div class ="grid__wrapper" >
<div class ="sample__header" >
<igx-grid [igxPreventDocumentScroll ]="true" #grid1 [data ]="data" [autoGenerate ]="false" displayDensity ="cosy" width ="100%" height ="600px" [primaryKey ]="'ProductID'" [allowFiltering ]="true" (rowDeleted )="show($event)" >
<igx-paginator [perPage ]="10" > </igx-paginator >
<igx-grid-toolbar >
<button igxButton ="flat" (click )="dialogAdd.open()" class ="addProdBtn" > <igx-icon > add</igx-icon > Add Product</button >
</igx-grid-toolbar >
<igx-column field ="ProductName" header ="Product Name" [dataType ]="'string'" [sortable ]="true" [hasSummary ]="true" [editable ]="true" [resizable ]="true" >
</igx-column >
<igx-column field ="UnitsInStock" header ="Units In Stock" dataType ="number" [sortable ]="true" [hasSummary ]="true" [summaries ]="numSummary" [editable ]="true" [resizable ]="true" >
</igx-column >
<igx-column field ="OrderDate" header ="Order Date" [dataType ]="'date'" [sortable ]="true" [hasSummary ]="true" [editable ]="true" [resizable ]="true" >
<ng-template igxCell let-cell ="cell" let-val >
{{val | date:'dd/MM/yyyy'}}
</ng-template >
</igx-column >
<igx-column field ="Discontinued" header ="Discontinued" [dataType ]="'boolean'" [sortable ]="true" [hasSummary ]="true" [editable ]="true" >
</igx-column >
<igx-column field ="ReorderLevel" header ="Reorder Level" dataType ="number" [summaries ]="numSummary" [sortable ]="true" [hasSummary ]="true" [editable ]="true" [filterable ]="false" >
<ng-template igxCellEditor let-cell ="cell" >
<input type ="number" [(ngModel )]="cell.editValue" class ="reorderLevelInput" />
</ng-template >
</igx-column >
<igx-column field ="Locations" header ="Available At" [editable ]="true" [filterable ]="false" width ="220px" >
<ng-template igxCell let-cell ="cell" >
{{ parseArray(cell.value) }}
</ng-template >
<ng-template igxCellEditor let-cell ="cell" let-value >
<igx-combo type ="line" [(ngModel )]="cell.editValue" [displayKey ]="'shop'" [data ]="locations" width ="220px" [igxFocus ]="true" [overlaySettings ]="customOverlaySettings" > </igx-combo >
</ng-template >
</igx-column >
<igx-column width ="100px" [filterable ]="false" >
<ng-template igxCell let-cell ="cell" >
<button igxButton ="icon" (click )="removeRow(cell.id.rowIndex)" >
<igx-icon > delete</igx-icon >
</button >
</ng-template >
</igx-column >
</igx-grid >
<igx-toast #toast [autoHide ]="true" > </igx-toast >
<igx-dialog #dialogAdd title ="New Product" [rightButtonLabel ]="'Add'" [leftButtonLabel ]="'Cancel'" (leftButtonSelect )="cancel()" (rightButtonSelect )="addRow()" >
<div class ="dialogNewRecord" >
<igx-input-group >
<label igxLabel for ="productName" > Product Name</label >
<input igxInput id ="productName" type ="text" [(ngModel )]="product.ProductName" />
</igx-input-group >
<igx-input-group >
<label igxLabel for ="unitsInStock" > Units In Stock</label >
<input igxInput id ="unitsInStock" type ="number" [(ngModel )]="product.UnitsInStock" />
</igx-input-group >
<igx-combo id ="availableAt" [displayKey ]="'shop'" [placeholder ]="'Available @'" [data ]="locations" [(ngModel )]="product.Locations" [itemsMaxHeight ]="200" > </igx-combo >
<igx-date-picker id ="orderDate" [(ngModel )]="product.OrderDate" mode ="dialog" >
<label igxLabel > Order Date</label > </igx-date-picker >
<igx-checkbox id ="discontinued" [(ngModel )]="product.Discontinued" > Discontinued</igx-checkbox >
<igx-input-group >
<label igxLabel for ="reorderLevel" > Reorder Level</label >
<input igxInput id ="reorderLevel" [(ngModel )]="product.ReorderLevel" />
</igx-input-group >
</div >
</igx-dialog >
</div >
</div >
html コピー .grid__wrapper {
padding : 16px ;
}
.dialogNewRecord {
> * {
margin-bottom : 8px ;
&:last-child {
margin-bottom : 0 ;
}
}
#discontinued {
margin-top : 15px ;
}
}
:host {
::ng-deep{
.igx-grid {
margin-top: 10px ;
}
.igx-checkbox {
margin-top : 5px ;
margin-bottom : 5px ;
padding-top : 8px ;
padding-bottom : 5px ;
}
.reorderLevelInput {
color : black;
width : 100% ;
}
@media screen and (max-width : 934px ) {
.igx-grid {
overflow-x : none;
}
}
}
}
.default-theme {
.addProdBtn .igx-button--raised {
background-color : lightgrey;
color : black;
&:hover {
background-color : rgba(0 , 0 , 0 , 0.26 )
}
}
}
scss コピー
このサンプルが気に入りましたか? 完全な Ignite UI for Angularツールキットにアクセスして、すばやく独自のアプリの作成を開始します。無料でダウンロードできます。
任意のタイプのエディター コンポーネントで igxCellEditor
を使用すると、キーボード ナビゲーション フローが中断されます。同じことが、編集モードに入るカスタム セルの直接編集にも当てはまります。これは、追加したエディター コンポーネント (igxSelect
、igxCombo
など) ではなく、セル要素にフォーカスが残るためです。これが、igxFocus
ディレクティブを利用する必要がある理由です。これにより、フォーカスがセル内コンポーネントに直接移動し、セル/行の流暢な編集フロー
が維持されます。
セルの編集
UI を介した編集
編集可能なセルがフォーカスされたときに以下のいずれかの方法で特定のセルを編集モードにすることができます。
ダブルクリック;
シングル クリック - 以前選択したセルが編集モードで現在選択したセルが編集可能な場合のみ、シングル クリックで編集モードに入ります。以前選択したセルが編集モードではない場合、編集モードに入らずにシングル クリックでセルを選択します。
Enter
キーの押下;
F2
キーの押下;
変更をコミットしない場合 も以下の方法で編集モードを終了できます。
Escape
キーの押下;
ソート 、フィルターリング 、検索 、非表示 操作の実行時。
変更をコミット しない場合も以下の方法で編集モードを終了できます。
Enter
キーの押下;
F2
キーの押下;
Tab
キーの押下;
他のセルをシングル クリック - Grid で他のセルをクリックしたときに変更がサブミットされます。
その他の操作 (ページング、サイズ変更、ピン固定、移動など) は、編集モードを終了して変更を送信します。
セルは、垂直/水平方向へのスクロールや Grid 以外をクリックした場合も編集モードのままです。セル編集と行編集両方で有効です。
API を介した編集
プライマリキーが定義されている場合のみ IgxGrid API でもセル値を変更することができます。
public updateCell ( ) {
this .grid1.updateCell(newValue, rowID, 'ReorderLevel' );
}
typescript
セルを更新するその他の方法として IgxGridCell
の update
メソッドで直接更新する方法があります。
public updateCell ( ) {
const cell = this .grid1.getCellByColumn(rowIndex, 'ReorderLevel' );
cell.update(70 );
}
typescript
セル編集テンプレート
デフォルトのセル編集テンプレートの詳細については、編集トピック を参照してください。
セルが編集モードのときに適用されるカスタム テンプレートを提供する場合は、igxCellEditor
ディレクティブ を使用できます。これを行うには、igxCellEditor
ディレクティブでマークされた ng-template
を渡し、カスタム コントロールを cell.editValue
に適切にバインドする必要があります:
<igx-column field ="class" header ="Class" [editable ]="true" >
<ng-template igxCellEditor let-cell ="cell" let-value >
<igx-select class ="cell-select" [(ngModel )]="cell.editValue" [igxFocus ]="true" >
<igx-select-item *ngFor ="let class of classes" [value ]="class" >
{{ class }}
</igx-select-item >
</igx-select >
</ng-template >
</igx-column >
html
このコードは、Race
、Class
、および Alignment
列のセルに IgxSelectComponent
を実装する以下のサンプルで使用されています。
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 {
IgxGridModule,
IgxSelectModule
} from "igniteui-angular" ;
import { GridSelectComponent } from "./grid/grid-select/grid-select-sample.component" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
GridSelectComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxGridModule,
IgxSelectModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { Character } from './characters' ;
import { Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxGridComponent } from 'igniteui-angular' ;
import { DATA, ALIGNMENTS, RACES, CLASSES } from './data' ;
@Component ({
selector : 'app-grid-select-sample' ,
styleUrls : ['./grid-select-sample.component.scss' ],
templateUrl : './grid-select-sample.component.html'
})
export class GridSelectComponent implements OnInit {
@ViewChild ('grid1' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
public data;
public alignments;
public races;
public classes;
public character;
public generateRandomData (data ) {
return data.map((e ) => {
const indexAlignments = Math .floor(Math .random() * ALIGNMENTS.length);
e.alignment = ALIGNMENTS[indexAlignments];
const indexRaces = Math .floor(Math .random() * RACES.length);
e.race = RACES[indexRaces];
const indexClasses = Math .floor(Math .random() * CLASSES.length);
e.class = CLASSES[indexClasses];
return e;
});
}
public ngOnInit ( ) {
this .data = this .generateRandomData(DATA);
this .character = new Character();
this .alignments = ALIGNMENTS;
this .races = RACES;
this .classes = CLASSES;
}
}
ts コピー <igx-grid #grid1 [data ]="data" [primaryKey ]="'name'" height ="600px" >
<igx-column field ="name" header ="Character name" [editable ]="true" >
</igx-column >
<igx-column field ="race" header ="Race" [editable ]="true" >
<ng-template igxCellEditor let-cell ="cell" let-value >
<igx-select class ="cell-select" [(ngModel )]="cell.editValue" [igxFocus ]="true" >
<igx-select-item *ngFor ="let race of races" [value ]="race" >
{{ race }}
</igx-select-item >
</igx-select >
</ng-template >
</igx-column >
<igx-column field ="class" header ="Class" [editable ]="true" >
<ng-template igxCellEditor let-cell ="cell" let-value >
<igx-select class ="cell-select" [(ngModel )]="cell.editValue" [igxFocus ]="true" >
<igx-select-item *ngFor ="let class of classes" [value ]="class" >
{{ class }}
</igx-select-item >
</igx-select >
</ng-template >
</igx-column >
<igx-column field ="age" header ="Age" [dataType ]="'number'" [editable ]="true" width ="10%" >
</igx-column >
<igx-column field ="alignment" header ="Alignment" [editable ]="true" >
<ng-template igxCellEditor let-cell ="cell" let-value >
<igx-select class ="cell-select" [(ngModel )]="cell.editValue" [igxFocus ]="true" >
<igx-select-item *ngFor ="let alignment of alignments" [value ]="alignment" >
{{ alignment }}
</igx-select-item >
</igx-select >
</ng-template >
</igx-column >
</igx-grid >
html コピー :host {
display : block;
padding : 16px ;
}
.cell-select {
width : 100% ;
height : 100% ;
}
scss コピー
セルテンプレート igxCell
は、編集モード外での列のセルの表示方法を制御します。
igxCellEditor
セル編集テンプレート ディレクティブは、編集モードでの列のセルの表示方法を処理し、編集されたセルの編集値を制御します。
任意のタイプのエディター コンポーネントで igxCellEditor
を使用すると、キーボード ナビゲーション フローが中断されます。同じことが、編集モードに入るカスタム セルの直接編集にも当てはまります。これは、追加したエディター コンポーネント (igxSelect
、igxCombo
など) ではなく、セル要素にフォーカスが残るためです。これが、igxFocus
ディレクティブを利用する必要がある理由です。これにより、フォーカスがセル内コンポーネントに直接移動し、セル/行の 流暢な編集フロー
が維持されます。
列とそのテンプレートの構成方法の詳細については、グリッド列構成 のドキュメントを参照してください。
Grid Excel スタイル編集
Excel スタイル編集を使用すると、Excel を使用する場合と同じようにセルをナビゲートし、すばやく編集できます。
このカスタム機能を実装するには、グリッドのイベントを使用します。最初にグリッドの keydown イベントにフックし、そこから 2 つの機能を実装できます。
public keydownHandler (event ) {
const key = event.keyCode;
const grid = this .grid;
const activeElem = grid.navigation.activeNode;
if (
(key >= 48 && key <= 57 ) ||
(key >= 65 && key <= 90 ) ||
(key >= 97 && key <= 122 )){
const columnName = grid.getColumnByVisibleIndex(activeElem.column).field;
const cell = grid.getCellByColumn(activeElem.row, columnName);
if (cell && !cell.editMode) {
cell.editMode = true ;
cell.editValue = event.key;
this .shouldAppendValue = true ;
} else if (cell && cell.editMode && this .shouldAppendValue) {
event.preventDefault();
cell.editValue = cell.editValue + event.key;
this .shouldAppendValue = false ;
}
}
}
typescript
Enter
/Shift + Enter
ナビゲーション
if (key == 13 ) {
let thisRow = activeElem.row;
const column = activeElem.column;
const rowInfo = grid.dataView;
let nextRow = this .getNextEditableRowIndex(thisRow, rowInfo, event.shiftKey);
this .grid.navigateTo(nextRow, column, (obj ) => {
obj.target.activate();
this .grid.clearCellSelection();
this .cdr.detectChanges();
});
}
typescript
次の適格なインデックスを見つけるための重要な部分は以下のようになります。
if (currentRowIndex < 0 || (currentRowIndex === 0 && previous) || (currentRowIndex >= dataView.length - 1 && !previous)) {
return currentRowIndex;
}
if (previous){
return dataView.findLastIndex((rec, index ) => index < currentRowIndex && this .isEditableDataRecordAtIndex(index, dataView));
}
return dataView.findIndex((rec, index ) => index > currentRowIndex && this .isEditableDataRecordAtIndex(index, dataView));
typescript
詳細については、サンプルを参照してください。
Angular Grid Excel スタイル編集のサンプル
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 { GridExcelStyleEditingComponent } from "./grid/grid-editing-excel-style/grid-editing-excel-style.component" ;
import { IgxGridModule } from "igniteui-angular" ;
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
GridExcelStyleEditingComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxGridModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core' ;
import {
IgxDialogComponent,
IgxGridComponent,
Transaction
} from 'igniteui-angular' ;
import { DATA } from './../../data/nwindData' ;
@Component ({
selector : 'app-grid-excel-style-editing-sample' ,
styleUrls : [`grid-editing-excel-style.component.scss` ],
templateUrl : 'grid-editing-excel-style.component.html'
})
export class GridExcelStyleEditingComponent implements OnInit {
@ViewChild ('grid' , { read : IgxGridComponent, static : true })
public grid: IgxGridComponent;
public data: any [];
public ngOnInit(): void {
this .data = DATA;
}
constructor (private cdr:ChangeDetectorRef ) {}
public keydownHandler (event ) {
const key = event.keyCode;
const grid = this .grid;
const activeElem = grid.navigation.activeNode;
if (
(key >= 48 && key <= 57 ) ||
(key >= 65 && key <= 90 ) ||
(key >= 97 && key <= 122 )
) {
const columnName = grid.getColumnByVisibleIndex(activeElem.column).field;
const cell = grid.getCellByColumn(activeElem.row, columnName);
if (cell && !grid.crudService.cellInEditMode) {
grid.crudService.enterEditMode(cell);
cell.editValue = event.key;
}
}
if (key == 13 ) {
let thisRow = activeElem.row;
const column = activeElem.column;
const rowInfo = grid.dataView;
let nextRow = this .getNextEditableRowIndex(thisRow, rowInfo, event.shiftKey);
this .grid.navigateTo(nextRow, column, (obj ) => {
obj.target.activate();
this .grid.clearCellSelection();
this .cdr.detectChanges();
});
}
}
public activeNodeChange ( ) {
this .grid.clearCellSelection();
this .grid.endEdit();
}
public getNextEditableRowIndex (currentRowIndex, dataView, previous ) {
if (currentRowIndex < 0 || (currentRowIndex === 0 && previous) || (currentRowIndex >= dataView.length - 1 && !previous)) {
return currentRowIndex;
}
if (previous){
return dataView.findLastIndex((rec, index ) => index < currentRowIndex && this .isEditableDataRecordAtIndex(index, dataView));
}
return dataView.findIndex((rec, index ) => index > currentRowIndex && this .isEditableDataRecordAtIndex(index, dataView));
}
private isEditableDataRecordAtIndex (dataViewIndex, dataView ) {
const rec = dataView[dataViewIndex];
return !rec.expression && !rec.summaries && !rec.childGridsData && !rec.detailsData
}
}
ts コピー <div class ="grid__wrapper" >
<igx-grid
[igxPreventDocumentScroll ]="true"
#grid
[data ]="data"
[primaryKey ]="'ProductID'"
width ="100%"
height ="500px"
(keydown )="keydownHandler($event)"
(activeNodeChange )="activeNodeChange()"
>
<igx-column
field ="ProductID"
header ="Product ID"
[editable ]="true"
[groupable ]="true"
[hidden ]="true"
> </igx-column >
<igx-column
field ="ProductName"
header ="Product Name"
[groupable ]="true"
[dataType ]="'string'"
[editable ]="true"
> </igx-column >
<igx-column
field ="UnitPrice"
header ="Unit Price"
[groupable ]="true"
[dataType ]="'string'"
[editable ]="true"
> </igx-column >
<igx-column
field ="QuantityPerUnit"
header ="Quantity Per Unit"
[groupable ]="true"
[dataType ]="'string'"
[editable ]="true"
> </igx-column >
<igx-column
field ="ReorderLevel"
header ="Reorder Level"
dataType ="number"
[groupable ]="true"
[editable ]="true"
> </igx-column >
</igx-grid >
</div >
html コピー .grid__wrapper {
padding : 16px ;
}
h4 {
text-align : center;
padding-top : 2% ;
padding-bottom : 2% ;
}
.buttons-row {
display : flex;
flex-direction : row;
justify-content : space-between;
padding : 5px ;
}
.buttons-wrapper {
display : flex;
flex-direction : row;
justify-content : center;
padding : 10px 0 ;
}
.transaction--update , .transaction--delete , .transaction--add {
font-weight : 600 ;
}
.transaction--add {
color : #6b3 ;
}
.transaction--update {
color : #4a71b9 ;
}
.transaction--delete {
color : #ee4920 ;
}
.transaction-log {
word-wrap : none;
}
scss コピー
上記のアプローチの主な利点は次のとおりです:
常時編集モード: セルが選択されているときに入力すると、編集モードに入り、入力された値が既存の値を置き換えます。
Enter
/Shift + Enter
で移動する場合、データ以外の行はスキップされます。これにより、ユーザーは値をすばやく切り替えることができます。
CRUD 操作
CRUD 操作 を実行した場合、filtering 、sorting 、grouping などのパイプが再適用されるため、ビューが自動的に更新されることに注意してください。
IgxGridComponent
は基本的な CRUD 操作のための簡易な API を提供します。
新しいレコードの追加
Grid コンポーネントは、提供したデータをデータ ソースに追加する addRow
メソッドを公開します。
const record = this .getNewRecord();
this .grid.addRow(record);
typescript
データを Grid で更新
Grid のデータ更新は、グリッドでプライマリキーが定義されている場合のみ updateRow
と updateCell
メソッドで行うことができます。セルと行の値またはそのいずれかを各 update
メソッドで直接更新できます。
this .grid.updateRow(newData, this .selectedCell.cellID.rowID);
this .grid.updateCell(newData, this .selectedCell.cellID.rowID, this .selectedCell.column.field);
this .selectedCell.update(newData);
const row = this .grid.getRowByKey(rowID);
row.update(newData);
typescript
Grid からデータを削除
deleteRow()
メソッドは、プライマリキーが定義されている場合に指定した行のみを削除することに注意してください。
this .grid.deleteRow(this .selectedCell.cellID.rowID);
const row = this .grid.getRowByIndex(rowIndex);
row.delete();
typescript
igx-grid に関係なく、ボタンのクリックなどのユーザー インタラクションに関連付けできます。
<button igxButton igxRipple (click )="deleteRow($event)" > Delete Row</button >
html
編集イベントでのセル検証
グリッドの編集イベントを使用して、ユーザーがグリッドを操作する方法を変更できます。
この例では、cellEdit
イベントにバインドすることにより、入力されたデータに基づいてセルを検証します。セルの新しい値が事前定義された基準を満たしていない場合、イベントをキャンセルすることでデータソースに到達しないようにします (event.cancel = true
)。また、IgxToast
を使用してカスタム エラーメッセージを表示します。
最初に必要なことは、グリッドのイベントにバインドすることです。
<igx-grid (cellEdit )="handleCellEdit($event)"
... >
...
</igx-grid >
html
cellEdit
は、セルの値がコミットされる直前に発生します。handleCellEdit
の定義では、アクションを実行する前に特定の列を確認する必要があります。
export class MyGridEventsComponent {
public handleCellEdit(event: IGridEditEventArgs): void {
const column = event.column;
if (column.field === 'Ordered' ) {
const rowData = event.rowData;
if (!rowData) {
return ;
}
if (event.newValue > rowData.UnitsInStock) {
event.cancel = true ;
this .toast.open();
}
}
}
}
typescript
注文済み 列の下のセルに入力された値が使用可能量 (在庫数 の値) よりも大きい場合、編集はキャンセルされ、エラー メッセージ付きのトーストが表示されます。
以下は、上記の検証が igx-grid
に適用された結果のデモです。
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 {
IgxGridModule,
IgxToastModule
} from "igniteui-angular" ;
import { GridEditingEventsComponent } from "./grid/grid-editing-events/grid-editing-events.component" ;
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
GridEditingEventsComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxGridModule,
IgxToastModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { Component, OnInit, ViewChild } from '@angular/core' ;
import { NgModel } from '@angular/forms' ;
import { IGridEditEventArgs, IgxGridComponent, IgxToastComponent, VerticalAlignment } from 'igniteui-angular' ;
import { DATA } from '../../data/nwindData' ;
@Component ({
selector : 'app-grid-editing-event' ,
templateUrl : 'grid-editing-events.component.html' ,
styleUrls : ['grid-editing-events.component.scss' ]
})
export class GridEditingEventsComponent implements OnInit {
@ViewChild (IgxToastComponent, { read : IgxToastComponent, static : true })
public toast: IgxToastComponent;
@ViewChild ('myTemplate' , { read : NgModel })
public myTemplate: NgModel;
public products: any [];
public balance = 7800 ;
public orderBalance: number ;
public ngOnInit ( ) {
this .products = DATA.map(e => {
if (!e.UnitPrice) {
e.UnitPrice = 1 ;
}
e.Ordered = Math .floor(Math .random() * e.UnitsInStock);
return e;
});
this .toast.positionSettings.verticalDirection = VerticalAlignment.Middle;
}
public handleCellEdit (event: IGridEditEventArgs ) {
const column = event.column;
if (column.field === 'Ordered' ) {
const rowData = event.rowData;
if (!rowData) {
return ;
}
if (event.newValue > rowData.UnitsInStock) {
event.cancel = true ;
this .toast.open();
}
}
}
}
ts コピー <h4 > Shipping Orders</h4 >
<igx-grid [igxPreventDocumentScroll ]="true" [data ]="products" height ="500px" primaryKey ="ProductID" (cellEdit )="handleCellEdit($event)" >
<igx-column field ="ProductName" header ="Product Name" dataType ="string" > </igx-column >
<igx-column field ="UnitPrice" header ="Price" dataType ="number" [editable ]="true" > </igx-column >
<igx-column field ="UnitsInStock" header ="Units In Stock" dataType ="number" [editable ]="true" > </igx-column >
<igx-column field ="Ordered" header ="Ordered" dataType ="number" [editable ]="true" > </igx-column >
</igx-grid >
<igx-toast > You cannot order more than the units in stock!</igx-toast >
html コピー :host {
display : block;
padding : 16px ;
}
h4 {
margin-bottom : 20px ;
}
scss コピー
スタイル設定
IgxGrid で Ignite UI for Angular テーマ ライブラリ
を使用してセルのスタイルを設定できます。グリッドの grid-theme
は、ユーザーがグリッドのさまざまな側面をスタイル設定できる広範なプロパティを公開します。
以下の手順では、編集モードでグリッドのセルのスタイルを設定する方法と、それらのスタイルの範囲を設定する方法について説明します。
Ignite UI テーマ ライブラリ
を使用するには、まずグローバル スタイルでテーマ index
ファイルをインポートする必要があります。
スタイル ライブラリのインポート
@use "igniteui-angular/theming" as *;
scss
以上で Ignite UI for Angular テーマ エンジンによって公開されているすべての機能を使用できます。
パレットの定義
インデックス ファイルをインポート後、カスタム パレットを作成します。好きな 3 つの色を定義し、それらを使用して palette
でパレットを作成しましょう。
$white : #fff ;
$blue : #4567bb ;
$gray : #efefef ;
$color-palette : palette(
$primary : $white ,
$secondary : $blue ,
$surface : $gray
);
scss
テーマの定義
これで、パレットを使用してテーマを定義できます。セルは grid-theme
によってスタイル設定されているため、それを使用して IgxGrid のテーマを生成できます。
$custom-grid-theme : grid-theme(
$cell-editing-background : $blue ,
$cell-edited-value-color : $white ,
$cell-active-border-color : $white ,
$edit-mode-color : color($color-palette , "secondary" , 200 )
);
scss
テーマを適用
テーマを適用する最も簡単な方法は、グローバル スタイル ファイルに sass
@include
ステートメントを使用することです。
@include grid ($custom-grid-theme );
scss
デモ
上記の手順に加えて、セルの編集テンプレートに使用されるコントロールのスタイルを設定することもできます (input-group
、datepicker
および checkbox
)。
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 { GridEditingStyleSampleComponent } from "./grid/grid-editing-style-sample/grid-editing-style-sample.component" ;
import {
IgxGridModule,
IgxDatePickerModule
} from "igniteui-angular" ;
import { IgxPreventDocumentScrollModule } from "./directives/prevent-scroll.directive" ;
@NgModule ({
bootstrap : [AppComponent],
declarations : [
AppComponent,
GridEditingStyleSampleComponent
],
imports : [
BrowserModule,
BrowserAnimationsModule,
FormsModule,
IgxPreventDocumentScrollModule,
IgxGridModule,
IgxDatePickerModule
],
providers : [],
entryComponents : [],
schemas : []
})
export class AppModule {}
ts コピー import { Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxGridComponent } from 'igniteui-angular' ;
import { DATA } from '../../data/nwindData' ;
@Component ({
selector : 'app-grid-editing-style-sample' ,
styleUrls : ['./grid-editing-style-sample.component.scss' ],
templateUrl : './grid-editing-style-sample.component.html'
})
export class GridEditingStyleSampleComponent implements OnInit {
@ViewChild ('grid' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
public data;
constructor ( ) { }
public ngOnInit ( ) {
this .data = DATA;
}
}
ts コピー <div class ="grid__wrapper" >
<igx-grid [igxPreventDocumentScroll ]="true" #grid [data ]="data" [autoGenerate ]="false" width ="100%" height ="600px" [allowFiltering ]="true" >
<igx-paginator [perPage ]="10" > </igx-paginator >
<igx-column field ="ProductName" header ="Product Name" width ="15%" [dataType ]="'string'" [sortable ]="true"
[hasSummary ]="true" [editable ]="true" [resizable ]="true" >
</igx-column >
<igx-column field ="UnitsInStock" header ="Units In Stock" width ="13%" dataType ="number" [sortable ]="true"
[hasSummary ]="true" [editable ]="true" [resizable ]="true" >
</igx-column >
<igx-column field ="OrderDate" header ="Order Date" width ="15%" [dataType ]="'date'" [sortable ]="true"
[hasSummary ]="true" [editable ]="true" [resizable ]="true" >
<ng-template igxCell let-cell ="cell" let-val >
{{val | date:'dd/MM/yyyy'}}
</ng-template >
</igx-column >
<igx-column field ="Discontinued" header ="Discontinued" width ="13%" [dataType ]="'boolean'" [sortable ]="true"
[hasSummary ]="true" [editable ]="true" >
</igx-column >
<igx-column field ="ReorderLevel" header ="Reorder Level" dataType ="number" width ="13%" [sortable ]="true"
[hasSummary ]="true" [editable ]="true" [filterable ]="false" >
<ng-template igxCellEditor let-cell ="cell" >
<input type ="number" [(ngModel )]="cell.editValue" class ="reorderLevelInput" />
</ng-template >
</igx-column >
</igx-grid >
</div >
html コピー @use '../../../variables' as *;
$white : #fff ;
$blue : #4567bb ;
$color-palette : palette($primary : $white , $secondary : $blue , $surface : #fff );
$grid-theme : grid-theme(
$cell-editing-background : $blue ,
$cell-active-border-color : $blue ,
$cell-edited-value-color : $white ,
$edit-mode-color : color($color-palette , "secondary" , 200 )
);
$checkbox-theme : checkbox-theme(
$empty-color : color($color-palette , "secondary" , 200 ),
$fill-color : $white ,
$tick-color : $blue
);
$datepicker-theme : calendar-theme(
$date-selected-text-color : $white ,
$date-selected-background : $blue
);
$input-theme : input-group-theme(
$filled-text-color : $white ,
$focused-text-color : $white ,
$idle-text-color : $white ,
$idle-bottom-line-color : $white ,
$focused-bottom-line-color : $white ,
$interim-bottom-line-color : $white ,
$hover-bottom-line-color : $white ,
$box-background : $blue
);
:host {
@include palette($color-palette );
::ng-deep {
.igx-grid__tbody{
@include css-vars($input-theme );
}
@include css-vars($checkbox-theme );
@include css-vars($datepicker-theme );
@include css-vars($grid-theme );
}
}
.grid__wrapper {
padding : 16px ;
}
.igx-grid {
margin-top : 10px ;
}
.reorderLevelInput {
color : black;
width : 100% ;
}
scss コピー
このサンプルは、Change Theme
(テーマの変更) から選択したグローバル テーマに影響を受けません。
API リファレンス
その他のリソース