Angular 그리드 셀 편집
Ignite UI for Angular 뛰어난 데이터 조작 기능과 Angular CRUD 작업을 위한 강력한 API를 제공합니다. 기본적으로 Grid는 셀 편집에 사용되며 기본 셀 편집 템플릿 덕분에 열 데이터 유형에 따라 다른 편집기가 표시됩니다. 또한 update-data 작업에 대한 사용자 정의 템플릿을 정의하고 변경 사항을 커밋하고 삭제하기 위한 기본 동작을 재정의할 수 있습니다.
Angular Grid 셀 편집 및 편집 템플릿 예제
import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxDialogComponent, IgxGridComponent, IgxSummaryResult, IgxNumberSummaryOperand, IgxToastComponent, VerticalAlignment, IgxPaginatorComponent, IgxGridToolbarComponent, IgxButtonDirective, IgxIconComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxCellEditorTemplateDirective, IgxComboComponent, IgxFocusDirective, IgxIconButtonDirective, IgxInputGroupComponent, IgxLabelDirective, IgxInputDirective, IgxDatePickerComponent, IgxCheckboxComponent } from 'igniteui-angular' ;
import { DATA, LOCATIONS } from './data' ;
import { Product } from './product' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
import { FormsModule } from '@angular/forms' ;
import { DatePipe } from '@angular/common' ;
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' ,
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxPaginatorComponent, IgxGridToolbarComponent, IgxButtonDirective, IgxIconComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxCellEditorTemplateDirective, FormsModule, IgxComboComponent, IgxFocusDirective, IgxIconButtonDirective, IgxToastComponent, IgxDialogComponent, IgxInputGroupComponent, IgxLabelDirective, IgxInputDirective, IgxDatePickerComponent, IgxCheckboxComponent, DatePipe]
})
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" 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 igxIconButton ="flat" (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 {
--ig-size: var(--ig-size-medium);
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--contained {
background-color : lightgrey;
color : black;
&:hover {
background-color : rgba(0 , 0 , 0 , 0.26 )
}
}
}
scss コピー
이 샘플이 마음에 드시나요? 전체 Ignite UI for Angular 툴킷에 액세스하고 몇 분 안에 나만의 앱을 구축해 보세요. 무료로 다운로드하세요.
사용하여 igxCellEditor
모든 유형의 편집기 구성 요소를 사용하면 키보드 탐색 흐름이 중단됩니다. 편집 모드로 들어가는 사용자 정의 셀을 직접 편집하는 경우에도 마찬가지입니다. 이는 focus
에 남아있을 것이다 cell element
, 우리가 추가한 편집기 구성요소에는 없습니다. igxSelect
, igxCombo
등. 이것이 바로 우리가 다음을 활용해야 하는 이유입니다. igxFocus
지시문은 셀 내 구성 요소에서 직접 포커스를 이동하고 보존합니다. a fluent editing flow
셀/행의
셀 편집
UI를 통한 편집
다음 방법 중 하나로 편집 가능한 셀에 초점이 맞춰지면 특정 셀에 대한 편집 모드로 들어갈 수 있습니다.
두 번 클릭하면;
한 번 클릭 시 - 이전에 선택한 셀이 편집 모드이고 현재 선택한 셀이 편집 가능한 경우에만 한 번 클릭하면 편집 모드로 들어갑니다. 이전에 선택한 셀이 편집 모드가 아닌 경우 한 번 클릭하면 편집 모드로 들어가지 않고 셀이 선택됩니다.
키를 누르면 Enter
;
키를 누르면 F2
;
다음 방법 중 하나로 변경 사항을 커밋하지 않고 편집 모드를 종료할 수 있습니다.
키를 누를 때 Escape
;
정렬 , 필터링 , 검색 및 숨기기 작업을 수행할 때
다음 방법 중 하나로 편집 모드를 종료하고 변경 사항을 커밋 할 수 있습니다.
키를 누르면 Enter
;
키를 누르면 F2
;
키를 누를 때 Tab
;
다른 셀을 한 번 클릭하면 - 그리드의 다른 셀을 클릭하면 변경 사항이 제출됩니다.
페이징, 크기 조정, 고정 또는 이동과 같은 작업을 수행하면 편집 모드가 종료되고 변경 사항이 제출됩니다.
세로 또는 가로로 스크롤하거나 그리드 외부를 클릭하면 셀은 편집 모드로 유지됩니다. 이는 셀 편집과 행 편집 모두에 유효합니다.
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
이 코드는 아래 샘플에서 사용됩니다. IgxSelectComponent
세포에서 Race
, Class
그리고 Alignment
열.
import { Character } from './characters' ;
import { Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxGridComponent, IgxColumnComponent, IgxCellEditorTemplateDirective, IgxSelectComponent, IgxFocusDirective, IgxSelectItemComponent } from 'igniteui-angular' ;
import { DATA, ALIGNMENTS, RACES, CLASSES } from './data' ;
import { FormsModule } from '@angular/forms' ;
@Component ({
selector : 'app-grid-select-sample' ,
styleUrls : ['./grid-select-sample.component.scss' ],
templateUrl : './grid-select-sample.component.html' ,
imports : [IgxGridComponent, IgxColumnComponent, IgxCellEditorTemplateDirective, IgxSelectComponent, FormsModule, IgxFocusDirective, IgxSelectItemComponent]
})
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" >
@for (race of races; track race) {
<igx-select-item [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" >
@for (class of classes; track class) {
<igx-select-item [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" >
@for (alignment of alignments; track alignment) {
<igx-select-item [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
모든 유형의 편집기 구성 요소를 사용하면 키보드 탐색 흐름이 중단됩니다. 편집 모드로 들어가는 사용자 정의 셀을 직접 편집하는 경우에도 마찬가지입니다. 이는 focus
에 남아있을 것이다 cell element
, 우리가 추가한 편집기 구성요소에는 없습니다. igxSelect
, igxCombo
등. 이것이 바로 우리가 다음을 활용해야 하는 이유입니다. igxFocus
지시문은 셀 내 구성 요소에서 직접 포커스를 이동하고 보존합니다. a fluent editing flow
셀/행의
열과 해당 템플릿을 구성하는 방법에 대한 자세한 내용은 그리드 열 구성 설명서를 참조하세요.
그리드 엑셀 스타일 편집
Excel 스타일 편집을 사용하면 사용자는 Excel을 사용하는 것처럼 셀을 탐색하고 신속하게 편집할 수 있습니다.
이 사용자 정의 기능을 구현하려면 그리드의 이벤트를 활용하면 됩니다. 먼저 그리드의 keydown 이벤트에 연결하고 거기에서 두 가지 기능을 구현할 수 있습니다.
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
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 { ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxDialogComponent, IgxGridComponent, Transaction, IgxColumnComponent } from 'igniteui-angular' ;
import { DATA } from '../../data/nwindData' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
@Component ({
selector : 'app-grid-excel-style-editing-sample' ,
styleUrls : [`grid-editing-excel-style.component.scss` ],
templateUrl : 'grid-editing-excel-style.component.html' ,
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent]
})
export class GridExcelStyleEditingComponent implements OnInit {
@ViewChild ('grid' , { read : IgxGridComponent, static : true })
public grid: IgxGridComponent;
public data: any [];
public shouldAppendValue = false ;
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 && !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 ;
}
}
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 작업을 수행하면 필터링 , 정렬 및 그룹화 와 같은 적용된 모든 파이프가 다시 적용되고 보기가 자동으로 업데이트된다는 점을 명심하세요.
IgxGridComponent
는 기본 CRUD 작업을 위한 간단한 API를 제공합니다.
새 레코드 추가
Grid 구성 요소는 제공된 데이터를 데이터 소스 자체에 추가하는 addRow
메서드를 노출합니다.
const record = this .getNewRecord();
this .grid.addRow(record);
typescript
그리드에서 데이터 업데이트
그리드의 데이터 업데이트는 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
그리드에서 데이터 삭제
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 { Component, OnInit, ViewChild } from '@angular/core' ;
import { NgModel } from '@angular/forms' ;
import { IGridEditEventArgs, IgxGridComponent, IgxToastComponent, VerticalAlignment, IgxColumnComponent } from 'igniteui-angular' ;
import { DATA } from '../../data/nwindData' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
@Component ({
selector : 'app-grid-editing-event' ,
templateUrl : 'grid-editing-events.component.html' ,
styleUrls : ['grid-editing-events.component.scss' ],
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxToastComponent]
})
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 Theme Library
. 그리드는 grid-theme
사용자가 그리드의 다양한 측면을 스타일링할 수 있도록 하는 광범위한 속성을 노출합니다.
아래 단계에서는 편집 모드에서 그리드 셀의 스타일을 지정하는 방법과 해당 스타일의 범위를 지정하는 방법을 살펴보겠습니다.
를 Ignite UI Theming Library
사용하려면 먼저 전역 스타일로 테마 index
파일을 가져와야 합니다.
스타일 라이브러리 가져오기
@use "igniteui-angular/theming" as *;
scss
이제 Ignite UI for Angular에서 제공하는 모든 기능을 활용할 수 있습니다.
팔레트 정의
인덱스 파일을 제대로 가져온 후 사용할 수 있는 사용자 지정 팔레트를 만듭니다. 우리가 좋아하는 세 가지 색상을 정의하고 이를 사용하여 팔레트를 만들어 보겠습니다. 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 { Component, OnInit, ViewChild } from '@angular/core' ;
import { IgxGridComponent, IgxPaginatorComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxCellEditorTemplateDirective } from 'igniteui-angular' ;
import { DATA } from '../../data/nwindData' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
import { FormsModule } from '@angular/forms' ;
import { DatePipe } from '@angular/common' ;
@Component ({
selector : 'app-grid-editing-style-sample' ,
styleUrls : ['./grid-editing-style-sample.component.scss' ],
templateUrl : './grid-editing-style-sample.component.html' ,
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxPaginatorComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxCellEditorTemplateDirective, FormsModule, DatePipe]
})
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 "layout.scss" ;
@use "igniteui-angular/theming" as *;
$white : #fff ;
$blue : #4567bb ;
$gray : #efefef ;
$color-palette : palette(
$primary : $white ,
$secondary : $blue ,
$surface : $gray
);
$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-foreground : $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
);
@include css-vars($grid-theme );
:host {
::ng-deep {
.igx-grid__tbody {
@include css-vars($input-theme );
}
@include css-vars($checkbox-theme );
@include css-vars($datepicker-theme );
}
}
.igx-grid {
@include palette($color-palette );
}
scss コピー
샘플은 Change Theme
에서 선택한 전역 테마의 영향을 받지 않습니다.
API 참조
추가 리소스