Angular 그리드 그룹화
Ignite UI for Angular의 Group By 동작은 열 값을 기반으로 그룹화된 데이터 행을 만듭니다. igxGrid
의 Group By를 사용하면 계층 구조로 그룹을 시각화할 수 있습니다. 그룹화된 데이터 행은 확장하거나 축소할 수 있으며 그룹화 순서는 UI 또는 API를 통해 변경할 수 있습니다. 행 선택이 활성화된 경우 Group By 행 선택기가 그룹 행의 가장 왼쪽 영역에 렌더링됩니다. rowSelection
속성이 single로 설정된 경우 체크박스는 비활성화되고 선택이 배치된 그룹에 대한 표시로만 사용됩니다. rowSelection
속성이 multiple로 설정된 경우 Group By 행 선택기를 클릭하면 이 그룹에 속하는 모든 레코드가 선택됩니다.
예제별 Angular 그리드 그룹
이 예에서는 대량의 데이터를 그룹화하는 기능을 보여줍니다. 열 헤더를 상단(그룹화 영역)으로 드래그하면 사용자는 선택한 열에 대한 데이터를 계층 구조로 볼 수 있습니다. 더 많은 열 헤더를 맨 위로 드래그하여 여러 필드에서 그룹화할 수 있습니다. 이러한 그룹화 옵션은 사용자가 훨씬 빠르고 시각적으로 허용되는 방식으로 데이터를 표시하려는 수많은 행과 열이 있는 테이블이 있는 경우 유용합니다.
import { Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core' ;
import { DefaultSortingStrategy, GridSelectionMode, IgxGridComponent, ISortingExpression, SortingDirection, IgxColumnComponent, IgxCellTemplateDirective, IgxGroupByRowTemplateDirective, IgxIconComponent, IgxBadgeComponent } from 'igniteui-angular' ;
import { INVOICE_DATA } from '../../data/invoiceData' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
import { NgIf } from '@angular/common' ;
@Component ({
encapsulation : ViewEncapsulation.None,
selector : 'app-grid-groupby-sample' ,
styleUrls : ['./grid-groupby-sample.component.scss' ],
templateUrl : './grid-groupby-sample.component.html' ,
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxCellTemplateDirective, NgIf, IgxGroupByRowTemplateDirective, IgxIconComponent, IgxBadgeComponent]
})
export class GridGroupBySampleComponent {
@ViewChild ('grid1' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
public data;
public expr: ISortingExpression[];
public selectionMode: GridSelectionMode = 'multiple' ;
constructor ( ) {
this .data = INVOICE_DATA;
this .expr = [
{ dir : SortingDirection.Asc, fieldName : 'ShipCountry' , ignoreCase : false ,
strategy : DefaultSortingStrategy.instance() },
{ dir : SortingDirection.Asc, fieldName : 'ShipCity' , ignoreCase : false ,
strategy : DefaultSortingStrategy.instance() }
];
}
public formatDate (val: Date ) {
return new Intl .DateTimeFormat('en-US' ).format(val);
}
public formatCurrency (value: number ) {
return '$' + value.toFixed(2 );
}
public isDate (value: any ) {
if (value instanceof Date ) {
return true ;
} else {
return false ;
}
}
public calc2017 (values: any [] ) {
const startDate = new Date ('1/1/2017' );
const endDate = new Date ('12/31/2017' );
return values.filter((x ) => x.OrderDate >= startDate && x.OrderDate <= endDate).length;
}
}
ts コピー <div class ="grid__wrapper" >
<igx-grid [igxPreventDocumentScroll ]="true" #grid1 [data ]="data" [width ]="'100%'" [height ]="'570px'" [rowSelection ]="selectionMode" [groupingExpressions ]="expr" >
<igx-column field ="OrderID" header ="Order ID" [hidden ]="true" >
</igx-column >
<igx-column field ="ShipCountry" header ="Ship Country" width ="200px" [groupable ]="true" >
</igx-column >
<igx-column field ="OrderDate" header ="Order Date" width ="200px" [formatter ]="formatDate" [groupable ]="true" >
</igx-column >
<igx-column field ="PostalCode" header ="Postal Code" width ="200px" [groupable ]="true" >
</igx-column >
<igx-column field ="Discontinued" header ="Discontinued" width ="200px" [groupable ]="true" >
<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 ="ShipName" header ="Ship Name" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="ShipCity" header ="Ship City" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="ShipperName" header ="Shipper Name" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="Salesperson" header ="Salesperson" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="UnitPrice" header ="Unit Price" width ="150px" [formatter ]="formatCurrency" dataType ="number" [groupable ]="true" >
</igx-column >
<igx-column field ="Quantity" header ="Quantity" width ="150px" dataType ="number" [groupable ]="true" >
</igx-column >
<ng-template igxGroupByRow let-groupRow >
<div class ="igx-group-label" >
<igx-icon family ="material" class ="igx-group-label__icon" > group_work</igx-icon >
<span class ="igx-group-label__column-name" >
{{ groupRow.expression.fieldName }}:
</span >
<span class ="igx-group-label__text" > {{ isDate(groupRow.value) ? formatDate(groupRow.value) : groupRow.value }}</span >
<igx-badge [value ]="groupRow.records.length" class ='igx-group-label__count-badge' > </igx-badge >
<span style ="color:#09f;" > Ordered in 2017:</span > <span class ="igx-badge__circle igx-badge__circle--default" > {{ calc2017(groupRow.records)}}</span >
</div >
</ng-template >
</igx-grid >
</div >
html コピー .grid-controls {
display : flex;
flex-flow : column nowrap;
justify-content : space-between;
margin : 0 16px 24px ;
igx-switch {
margin-top : 24px ;
}
}
.grid__wrapper {
padding-top : 16px ;
margin : 0 16px ;
}
.header-icon {
font-size : 1.4em ;
width : 1.1em ;
height : 1.1em ;
float : right;
cursor : pointer;
}
.header {
height : 100% ;
}
.igx-grid__th .title {
width : 100% ;
cursor : auto;
}
scss コピー
이 샘플이 마음에 드시나요? 전체 Ignite UI for Angular 툴킷에 액세스하고 몇 분 안에 나만의 앱을 구축해 보세요. 무료로 다운로드하세요.
초기 그룹화 상태
그리드의 groupingExpressions
속성에 표현식 배열을 할당하여 그리드의 초기 그룹화를 정의할 수 있습니다.
public ngOnInit ( ) {
grid.groupingExpressions = [
{ fieldName : 'ProductName' , dir : SortingDirection.Desc },
{ fieldName : 'Released' , dir : SortingDirection.Desc }
];
}
typescript
그룹화 표현식은 ISortingExpression
인터페이스를 구현합니다.
그룹화 API
그룹화 API
그룹화는 UI와 그리드 구성 요소에서 제공하는 강력한 API를 통해 사용할 수 있습니다. 개발자는 각 열의 groupable
속성을 true
로 설정하여 최종 사용자가 특정 열을 기준으로 그리드 데이터를 그룹화하도록 허용할 수 있습니다.
<igx-grid [data ]="data" >
<igx-column *ngFor ="let c of columns" [field ]="c.field" [groupable ]="true" >
</igx-column >
</igx-grid >
html
public ngOnInit ( ) {
grid.columns.forEach((column ) => {
column.groupable = true ;
});
}
typescript
런타임 동안 표현식은 groupingExpressions
속성에서 가져오고 설정할 수 있습니다. 기존 표현식을 추가하거나 변경해야 하는 경우 단일 또는 ISortingExpression
배열과 함께 groupBy
메소드를 사용할 수도 있습니다.
grid.groupBy({ fieldName : 'ProductName' , dir : SortingDirection.Desc, ignoreCase : true });
typescript
지금까지는 그룹화/정렬이 서로 함께 작동했습니다. 13.2 버전에서는 정렬에서 그룹화를 분리하는 새로운 동작이 도입되었습니다. 예를 들어 그룹화를 지우면 그리드의 정렬 표현식이 지워지지 않으며 그 반대의 경우도 마찬가지입니다. 그러나 열이 정렬되고 그룹화된 경우 그룹화된 식이 우선합니다.
확장/축소 API
표현식을 그룹화하는 것 외에도 그룹 행의 확장 상태를 제어할 수도 있습니다. 이는 igxGrid
구성요소 groupingExpansionState
의 별도 속성에 저장됩니다. 그룹 행은 생성된 필드 이름과 각 그룹화 수준에 대해 나타내는 값을 기반으로 고유하게 식별됩니다. 이는 확장 상태 인터페이스의 서명이 다음과 같음을 의미합니다.
export interface IGroupByKey {
fieldName : string ;
value: any ;
}
export interface IGroupByExpandState {
hierarchy : Array <IGroupByKey>;
expanded: boolean ;
}
typescript
groupingExpressions
와 마찬가지로 IGroupByExpandState
목록을 groupingExpansionState
에 직접 설정하면 이에 따라 확장이 변경됩니다. 또한 igxGrid
그룹 레코드 인스턴스로 그룹을 전환하는 메서드를 노출합니다.
const groupRow = this .grid.groupsRecords.find(r => r.value === "France" );
const groupRow = this .grid.getRowByIndex(0 ).groupRow;
grid.toggleGroup(groupRow);
groupRow.expanded = false ;
typescript
그룹은 확장(기본값 ) 또는 축소로 생성될 수 있으며 일반적으로 확장 상태에는 기본 동작과 반대되는 상태만 포함됩니다. groupsExpanded
속성을 통해 그룹을 확장하여 생성해야 하는지 여부를 제어할 수 있습니다.
그룹 API의 모든 행 선택/선택 취소
그룹의 모든 행을 선택/선택 취소하는 것은 selectRowsInGroup
및 deselectRowsInGroup
API 메소드를 통해 가능합니다.
아래 코드 조각은 그룹 레코드 인스턴스 selectRowsInGroup
메서드를 사용하여 그룹 내의 모든 행을 선택하는 데 사용할 수 있습니다. 또한 이 메서드의 두 번째 매개 변수는 이전 행 선택을 지울지 여부를 선택할 수 있는 부울 속성입니다. 이전 선택 사항은 기본적으로 유지됩니다.
const groupRow = this .grid.groupsRecords.find(r => r.value === "France" );
const groupRow = this .grid.getRowByIndex(0 ).groupRow;
grid.selectRowsInGroup(groupRow);
typescript
프로그래밍 방식으로 그룹 내의 모든 행을 선택 취소해야 하는 경우 deselectRowsInGroup
메서드를 사용할 수 있습니다.
const groupRow = this .grid.groupsRecords.find(r => r.value === "France" );
const groupRow = this .grid.getRowByIndex(0 ).groupRow;
grid.deselectRowsInGroup(groupRow);
typescript
템플릿
그룹 행 템플릿
확장/축소 UI를 제외한 그룹 행은 완전히 템플릿화 가능합니다. 기본적으로 그룹화 아이콘을 렌더링하고 해당 아이콘이 나타내는 필드 이름과 값을 표시합니다. 렌더링되는 그룹화 레코드 템플릿에는 다음과 같은 서명이 있습니다.
export interface IGroupByRecord {
expression : ISortingExpression;
level: number ;
records: GroupedRecords;
value: any ;
groupParent: IGroupByRecord;
groups?: IGroupByRecord[];
}
typescript
예를 들어, 다음 템플릿은 그룹 행 요약을 더욱 자세하게 만듭니다.
<ng-template igxGroupByRow let-groupRow >
<span > Total items with value: {{ groupRow.value }} are {{ groupRow.records.length }}</span >
</ng-template >
html
그룹 행 선택기 템플릿
위에서 언급한 것처럼 확장/축소 UI를 제외한 그룹 행은 완전히 템플릿화 가능합니다. 그리드 내에서 사용자 정의 Group By 행 선택기 템플릿을 생성하려면 igxGroupByRowSelector
지시문을 사용하여 <ng-template>
선언하세요. 템플릿에서 Group By 행의 상태에 대한 정보를 제공하는 속성을 사용하여 암시적으로 제공된 컨텍스트 변수에 액세스할 수 있습니다.
selectedCount
속성은 현재 선택된 그룹 레코드 수를 표시하고 totalCount
그룹에 속한 레코드 수를 표시합니다.
<ng-template igxGroupByRowSelector let-groupByRowContext >
{{ groupByRowContext.selectedCount }} / {{ groupByRowContext.totalCount }}
</ng-template >
html
groupRow
속성은 그룹 행에 대한 참조를 반환합니다.
<ng-template igxGroupByRowSelector let-groupByRowContext >
<div (click )="handleGroupByRowSelectorClick($event, groupByRowContext.groupRow)" > Handle groupRow</div >
</ng-template >
html
selectedCount
및 totalCount
속성을 사용하여 그룹화 기준 행 선택기를 선택해야 하는지 또는 불확정(부분 선택)해야 하는지 결정할 수 있습니다.
<igx-grid #grid [data ]="gridData" primaryKey ="ProductID" rowSelection ="multiple" >
<ng-template igxGroupByRowSelector let-context >
<igx-checkbox
[checked ]=" context.selectedCount > 0 && context.selectedCount === context.totalCount"
[indeterminate ]="context.selectedCount > 0 && context.selectedCount !== context.totalCount" >
</igx-checkbox >
</ng-template >
</igx-grid >
html
페이징을 사용한 Angular Grid 그룹화
그룹 행은 데이터 행과 함께 페이징 프로세스에 참여합니다. 각 페이지의 페이지 크기에 포함됩니다. 축소된 행은 페이징 프로세스에 포함되지 않습니다. 확장 또는 축소 작업을 수행하면 Paging이 페이지 수를 다시 계산하고 필요한 경우 페이지 인덱스를 조정합니다. 여러 페이지에 걸쳐 있는 그룹은 페이지 간에 분할됩니다. 그룹 행은 시작하는 페이지에만 표시되며 후속 페이지에서는 반복되지 않습니다. 그룹 행의 요약 정보는 전체 그룹을 기준으로 계산되며 Paging의 영향을 받지 않습니다.
페이징 예제를 사용한 Angular 그룹
import { Component, ViewChild } from '@angular/core' ;
import { DefaultSortingStrategy, GridSelectionMode, IgxGridComponent, ISortingExpression, SortingDirection, IgxPaginatorComponent, IgxColumnComponent, IgxGroupByRowTemplateDirective, IgxIconComponent, IgxBadgeComponent } from 'igniteui-angular' ;
import { INVOICE_DATA } from '../../data/invoiceData' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
@Component ({
selector : 'app-grid-group-by-paging-sample' ,
templateUrl : './grid-group-by-paging-sample.component.html' ,
styleUrls : ['./grid-group-by-paging-sample.component.scss' ],
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxPaginatorComponent, IgxColumnComponent, IgxGroupByRowTemplateDirective, IgxIconComponent, IgxBadgeComponent]
})
export class GridGroupByPagingSampleComponent {
@ViewChild ('grid1' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
public data;
public expr: ISortingExpression[];
public selectionMode: GridSelectionMode = 'multiple' ;
constructor ( ) {
this .data = INVOICE_DATA;
this .expr = [
{ dir : SortingDirection.Asc, fieldName : 'ShipCountry' , ignoreCase : false ,
strategy : DefaultSortingStrategy.instance() }
];
}
public formatDate (val: Date ) {
return new Intl .DateTimeFormat('en-US' ).format(val);
}
public formatCurrency (value: number ) {
return '$' + value.toFixed(2 );
}
public isDate (value: any ) {
if (value instanceof Date ) {
return true ;
} else {
return false ;
}
}
public calc2017 (values: any [] ) {
const startDate = new Date ('1/1/2017' );
const endDate = new Date ('12/31/2017' );
return values.filter((x ) => x.OrderDate >= startDate && x.OrderDate <= endDate).length;
}
}
ts コピー <div class ="grid__wrapper" >
<igx-grid [igxPreventDocumentScroll ]="true" #grid1 [data ]="data" [width ]="'100%'" [height ]="'570px'" [rowSelection ]="selectionMode" [groupingExpressions ]="expr" >
<igx-paginator [perPage ]="10" > </igx-paginator >
<igx-column field ="ShipCountry" header ="Ship Country" width ="200px" [groupable ]="true" >
</igx-column >
<igx-column field ="ShipCity" header ="Ship City" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="UnitPrice" header ="Unit Price" width ="150px" [formatter ]="formatCurrency" dataType ="number" [groupable ]="true" >
</igx-column >
<igx-column field ="Quantity" header ="Quantity" width ="150px" dataType ="number" [groupable ]="true" >
</igx-column >
<ng-template igxGroupByRow let-groupRow >
<div class ="igx-group-label" >
<igx-icon family ="material" class ="igx-group-label__icon" > group_work</igx-icon >
<span class ="igx-group-label__column-name" >
{{ groupRow.expression.fieldName }}:
</span >
<span class ="igx-group-label__text" > {{ isDate(groupRow.value) ? formatDate(groupRow.value) : groupRow.value }}</span >
<igx-badge [value ]="groupRow.records.length" class ='igx-group-label__count-badge' > </igx-badge >
<span style ="color:#09f;" > Ordered in 2017:</span > <span class ="igx-badge__circle igx-badge__circle--default" > {{ calc2017(groupRow.records)}}</span >
</div >
</ng-template >
</igx-grid >
</div >
html コピー .grid-controls {
display : flex;
flex-flow : column nowrap;
justify-content : space-between;
margin : 0 16px 24px ;
igx-switch {
margin-top : 24px ;
}
}
.grid__wrapper {
padding-top : 16px ;
margin : 0 16px ;
}
.header-icon {
font-size : 1.4em ;
width : 1.1em ;
height : 1.1em ;
float : right;
cursor : pointer;
}
.header {
height : 100% ;
}
.igx-grid__th .title {
width : 100% ;
cursor : auto;
}
scss コピー
요약이 포함된 그룹화 기준
Group By와 요약 간의 통합은 요약 항목에 설명되어 있습니다.
키보드 탐색
그룹화 UI는 다음과 같은 키보드 상호 작용을 지원합니다.
Angular 그리드 사용자 정의 그룹화
igxGrid를 사용하면 열별 또는 그룹화 표현식별로 사용자 정의 그룹화를 정의할 수 있으며, 이는 사용자 정의 조건을 기반으로 그룹화를 제공합니다. 이는 복잡한 개체별로 그룹화해야 하거나 기타 애플리케이션별 시나리오에 유용합니다.
아래 샘플은 Date
별 사용자 정의 그룹화를 보여줍니다. 여기서 날짜 값은 사용자가 선택한 그룹화 모드에 따라 일, 주, 월 또는 연도별로 정렬 및 그룹화됩니다.
예제별 Angular 사용자 정의 그룹
import { Component, ViewChild, ViewEncapsulation } from '@angular/core' ;
import { DefaultSortingStrategy, IgxGridComponent, SortingDirection, IgxGridToolbarComponent, IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective, IgxDropDownComponent, IgxDropDownItemComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxGroupByRowTemplateDirective, IgxIconComponent, IgxBadgeComponent } from 'igniteui-angular' ;
import { INVOICE_DATA } from '../../data/invoiceData' ;
import { DatePipe, NgFor, NgIf, CurrencyPipe } from '@angular/common' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
@Component ({
encapsulation : ViewEncapsulation.None,
selector : 'app-grid-groupby-custom-sample' ,
styleUrls : ['./grid-groupby-custom-sample.component.scss' ],
templateUrl : './grid-groupby-custom-sample.component.html' ,
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxGridToolbarComponent, IgxButtonDirective, IgxToggleActionDirective, IgxDropDownItemNavigationDirective, IgxDropDownComponent, NgFor, IgxDropDownItemComponent, IgxColumnComponent, IgxCellTemplateDirective, NgIf, IgxGroupByRowTemplateDirective, IgxIconComponent, IgxBadgeComponent, CurrencyPipe, DatePipe]
})
export class GridGroupByCustomSampleComponent {
@ViewChild ('grid1' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
public data;
public sortingStrategy;
public groupByOptions = [
{ name : 'Day' , ref : DaySortingStrategy.instance() },
{ name : 'Week' , ref : WeekSortingStrategy.instance() },
{ name : 'Month' , ref : BaseSortingStrategy.instance() },
{ name : 'Year' , ref : BaseSortingStrategy.instance() }
];
public groupByMode = this .groupByOptions[0 ].name;
public initialExpr;
public dateFormatter = '' ;
constructor ( ) {
this .data = INVOICE_DATA;
this .sortingStrategy = this .groupByOptions[0 ].ref;
this .dateFormatter = 'MM/dd/yyyy' ;
this .initialExpr = [
{
dir : SortingDirection.Asc,
fieldName : 'OrderDate' ,
ignoreCase : true ,
strategy : this .sortingStrategy,
groupingComparer : (a, b ) => {
const dateA = this .sortingStrategy.getParsedDate(a);
const dateB = this .sortingStrategy.getParsedDate(b);
if (this .groupByMode === 'Month' ) {
return dateA.month === dateB.month ? 0 : -1 ;
} else if (this .groupByMode === 'Year' ) {
return dateA.year === dateB.year ? 0 : -1 ;
} else if (this .groupByMode === 'Week' ) {
return this .sortingStrategy.getWeekOfDate(a) === this .sortingStrategy.getWeekOfDate(b) ? 0 : -1 ;
}
return dateA.day === dateB.day && dateA.month === dateB.month ? 0 : -1 ;
}
}
];
}
public selectionChange (event: any ) {
this .groupByMode = event.newSelection.value.name;
this .sortingStrategy = event.newSelection.value.ref;
this .dateFormatter = this .changeFormatter(this .groupByMode);
const expr = this .grid1.groupingExpressions.find(
(e ) => e.fieldName === 'OrderDate'
);
if (expr) {
expr.strategy = this .sortingStrategy;
const gexpr = this .grid1.groupingExpressions;
this .grid1.groupingExpressions = [];
this .grid1.groupingExpressions = gexpr;
}
}
public changeFormatter (mode: string ) {
if (this .groupByMode === 'Month' ) {
return 'MMMM yyyy' ;
} else if (this .groupByMode === 'Year' ) {
return 'yyyy' ;
} else if (this .groupByMode === 'Week' ){
return 'yyyy \'week\' w' ;
}
return 'MM/dd/yyyy' ;
}
public isDate (value: any ) {
if (value instanceof Date ) {
return true ;
} else {
return false ;
}
}
}
class BaseSortingStrategy extends DefaultSortingStrategy {
public getParsedDate (date: any ) {
return {
day : date.getDay(),
month : date.getMonth() + 1 ,
year : date.getFullYear()
};
}
compareValues (a: any , b: any ) {
const dateA = this .getParsedDate(a);
const dateB = this .getParsedDate(b);
return dateA.year < dateB.year ? -1 : dateA.year > dateB.year ? 1 : dateA.month < dateB.month ? -1 : dateA.month > dateB.month ? 1 : 0 ;
}
}
class DaySortingStrategy extends BaseSortingStrategy {
compareValues (a: any , b: any ) {
const dateA = this .getParsedDate(a);
const dateB = this .getParsedDate(b);
return dateA.year < dateB.year ? -1 : dateA.year > dateB.year ? 1 : dateA.month < dateB.month ? -1 : dateA.month > dateB.month ? 1 :
dateA.day < dateB.day ? -1 : dateA.day > dateB.day ? 1 : 0 ;
}
}
class WeekSortingStrategy extends BaseSortingStrategy {
public getWeekOfDate (a: any ) {
return parseInt (new DatePipe('en-US' ).transform(a, 'w' ), 10 );
}
compareValues (a: any , b: any ) {
const dateA = this .getParsedDate(a);
const dateB = this .getParsedDate(b);
const weekA = this .getWeekOfDate(a);
const weekB = this .getWeekOfDate(b);
return dateA.year < dateB.year ? -1 : dateA.year > dateB.year ? 1 : weekA < weekB ? -1 : weekA > weekB ? 1 : 0 ;
}
}
ts コピー <div class ="grid__wrapper" >
<igx-grid [igxPreventDocumentScroll ]="true" #grid1 [data ]="data" [width ]="'100%'" [height ]="'570px'" [groupingExpressions ]="initialExpr" >
<igx-grid-toolbar >
<button igxButton ="contained" [igxToggleAction ]="dropDown" [igxDropDownItemNavigation ]="dropDown" > Group By {{ groupByMode }}</button >
<igx-drop-down #dropDown (selectionChanging )="selectionChange($event)" >
<igx-drop-down-item *ngFor ="let item of groupByOptions" [value ]="item" >
{{ item.name }}
</igx-drop-down-item >
</igx-drop-down >
</igx-grid-toolbar >
<igx-column field ="OrderID" header ="Order ID" [hidden ]="true" >
</igx-column >
<igx-column field ="ShipCountry" header ="Ship Country" width ="200px" [groupable ]="true" >
</igx-column >
<igx-column field ="OrderDate" header ="Order Date" width ="200px" [groupable ]="true" dataType ="date" >
<ng-template igxCell let-value >
{{ value | date:'shortDate' }}
</ng-template >
</igx-column >
<igx-column field ="PostalCode" header ="Postal Code" width ="200px" [groupable ]="true" >
</igx-column >
<igx-column field ="Discontinued" header ="Discontinued" width ="200px" [groupable ]="true" >
<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 ="ShipName" header ="Ship Name" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="ShipCity" header ="Ship City" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="ShipperName" header ="Shipper Name" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="Salesperson" header ="Salesperson" width ="250px" [groupable ]="true" >
</igx-column >
<igx-column field ="UnitPrice" header ="Unit Price" width ="150px" dataType ="number" [groupable ]="true" >
<ng-template igxCell let-value >
{{ value | currency:'USD':'symbol-narrow'}}
</ng-template >
</igx-column >
<igx-column field ="Quantity" header ="Quantity" width ="150px" dataType ="number" [groupable ]="true" >
</igx-column >
<ng-template igxGroupByRow let-groupRow >
<div class ="igx-group-label" >
<igx-icon family ="material" class ="igx-group-label__icon" > group_work</igx-icon >
<span class ="igx-group-label__column-name" >
{{ groupRow.expression.fieldName }}:
</span >
<span class ="igx-group-label__text" > {{ isDate(groupRow.value) ? (groupRow.value | date: dateFormatter) : groupRow.value }}</span >
<igx-badge [value ]="groupRow.records.length" class ='igx-group-label__count-badge' > </igx-badge >
</div >
</ng-template >
</igx-grid >
</div >
html コピー .grid-controls {
display : flex;
flex-flow : column nowrap;
justify-content : space-between;
margin : 0 16px 24px ;
igx-switch {
margin-top : 24px ;
}
}
.grid__wrapper {
padding-top : 16px ;
margin : 0 16px ;
}
.header {
height : 100% ;
}
.igx-grid__th .title {
width : 100% ;
cursor : auto;
}
scss コピー
샘플은 다양한 날짜 조건에 대한 사용자 정의 정렬 전략을 정의합니다. 각 사용자 정의 전략은 기본 DefaultSortingStrategy
확장하고 값을 정렬할 때 사용되는 사용자 정의 비교 함수인 compareValues
메서드를 정의합니다. 또한 비교에 필요한 날짜에서 값을 추출합니다.
class BaseSortingStrategy extends DefaultSortingStrategy {
public getParsedDate (date: any ) {
return {
day : date.getDay(),
month : date.getMonth() + 1 ,
year : date.getFullYear()
};
}
compareValues (a: any , b: any ) {
const dateA = this .getParsedDate(a);
const dateB = this .getParsedDate(b);
return dateA.year < dateB.year ?
-1 : dateA.year > dateB.year ?
1 : dateA.month < dateB.month ?
-1 : dateA.month > dateB.month ?
1 : 0 ;
}
}
class DaySortingStrategy extends BaseSortingStrategy {
compareValues (a: any , b: any ) {
const dateA = this .getParsedDate(a);
const dateB = this .getParsedDate(b);
return dateA.year < dateB.year ?
-1 : dateA.year > dateB.year ?
1 : dateA.month < dateB.month ?
-1 : dateA.month > dateB.month ?
1 : dateA.day < dateB.day ?
-1 : dateA.day > dateB.day ?
1 : 0 ;
}
}
class WeekSortingStrategy extends BaseSortingStrategy {
public getWeekOfDate (a: any ) {
return parseInt (new DatePipe("en-US" ).transform(a, 'w' ), 10 );
}
compareValues (a: any , b: any ) {
const dateA = this .getParsedDate(a);
const dateB = this .getParsedDate(b);
const weekA = this .getWeekOfDate(a);
const weekB = this .getWeekOfDate(b);
return dateA.year < dateB.year ?
-1 : dateA.year > dateB.year ?
1 : weekA < weekB ?
-1 : weekA > weekB ?
1 : 0 ;
}
}
typescript
groupingComparer
함수는 선택한 그룹화 모드에 따라 동일한 그룹에 속하는 항목을 결정하는 그룹화 표현식에 대해 정의됩니다. 이 함수가 0을 반환하는 정렬된 데이터의 값은 동일한 그룹의 일부로 표시됩니다.
groupingComparer: (a, b ) => {
const dateA = this .sortingStrategy.getParsedDate(a);
const dateB = this .sortingStrategy.getParsedDate(b);
if (this .groupByMode === 'Month' ) {
return dateA.month === dateB.month ? 0 : -1 ;
} else if (this .groupByMode === "Year" ) {
return dateA.year === dateB.year ? 0 : -1 ;
} else if (this .groupByMode === "Week" ) {
return this .sortingStrategy.getWeekOfDate(a) === this .sortingStrategy.getWeekOfDate(b) ? 0 : -1 ;
}
return dateA.day === dateB.day && dateA.month === dateB.month ? 0 : -1 ;
}
typescript
버전 15.1.0부터는 기본 제공 정렬 전략인 GroupMemberCountSortingStrategy
사용하여 구성원 수에 따라 항목을 정렬할 수도 있습니다.
public sortByGroup ( ) {
const expressions = this .grid1.groupingExpressions;
if (expressions.length) {
const fieldName = expressions[0 ].fieldName;
const dir = expressions[0 ].dir === SortingDirection.Asc ? SortingDirection.Desc : SortingDirection.Asc;
this .grid1.groupBy({ fieldName, dir, ignoreCase : false , strategy : GroupMemberCountSortingStrategy.instance() });
}
}
typescript
스타일링
igxGrid를 사용하면 스타일을 지정할 수 있습니다 Ignite UI for Angular Theme Library
. 그리드는 grid-theme
그리드의 모든 기능을 사용자 지정할 수 있는 다양한 속성을 노출합니다.
아래 단계에서는 그리드의 Group By 스타일을 사용자 정의하는 단계를 진행합니다.
글로벌 테마 가져오기
Group By 기능의 사용자 정의를 시작하려면 모든 스타일링 기능과 믹스인이 있는 index
파일을 가져와야 합니다.
@use "igniteui-angular/theming" as *;
scss
맞춤 테마 정의
다음으로, grid-theme
확장하고 원하는 대로 Group By를 사용자 정의하는 데 필요한 매개변수를 허용하는 새 테마를 만듭니다. 또한 Group By 기능에 사용되므로 chip-theme
확장해야 합니다.
$custom-theme : grid-theme(
$group-row-background : #494949 ,
$group-row-selected-background : #383838 ,
$group-label-column-name-text : #f8f8f8 ,
$group-label-icon : #ffcd0f ,
$group-label-text : #f8f8f8 ,
$group-count-background : #ffcd0f ,
$group-count-text-color : #000 ,
$expand-icon-color : #ffcd0f ,
$expand-icon-hover-color : rgb(223 , 181 , 13 ),
$cell-active-border-color : #ffcd0f ,
$row-selected-background : #fff6d3 ,
$row-selected-text-color : #000 ,
$drop-indicator-color : #ffcd0f
);
$custom-chips-theme : chip-theme(
$background : #494949 ,
$text-color : #f8f8f8 ,
$hover-text-color : #e7e7e7
);
scss
사용자 정의 색상 팔레트 정의
위에서 설명한 접근 방식에서는 색상 값이 하드 코딩되었습니다. 또는 and color
함수를 사용하여 palette
더 큰 유연성을 얻을 수 있습니다.
palette
제공된 Primary, Secondary 및 Surface 색상을 기반으로 색상표를 생성합니다.
$black-color : #292826 ;
$yellow-color : #ffcd0f ;
$grey-color : #efefef ;
$custom-palette : palette(
$primary : $black-color ,
$secondary : $yellow-color ,
$surface : $grey-color
);
scss
사용자 정의 팔레트가 생성된 후 이 color
기능을 사용하여 다양한 종류의 기본 및 보조 색상을 얻을 수 있습니다.
$custom-theme : grid-theme(
$group-row-background : color($custom-palette , "primary" , 300 ),
$group-row-selected-background : color($custom-palette , "primary" , 400 ),
$group-label-column-name-text :contrast-color($custom-palette , "primary" , 500 ),
$group-label-icon : color($custom-palette , "secondary" , 600 ),
$group-label-text :contrast-color($custom-palette , "primary" , 500 ),
$group-count-background : color($custom-palette , "secondary" , 600 ),
$group-count-text-color : color($custom-palette , "primary" , 400 ),
$expand-icon-color : color($custom-palette , "secondary" , 600 ),
$expand-icon-hover-color : color($custom-palette , "secondary" , 300 ),
$cell-active-border-color : color($custom-palette , "secondary" , 600 )
);
$custom-chips-theme : chip-theme(
$background : color($custom-palette , "primary" , 300 ),
$text-color :contrast-color($custom-palette , "primary" , 500 ),
$hover-text-color :contrast-color($custom-palette , "primary" , 600 )
);
scss
커스텀 스키마 정의
더 나아가 스키마 의 모든 이점을 갖춘 유연한 구조를 구축할 수 있습니다. 스키마 는 테마의 레시피입니다. 모든 구성 요소에 대해 제공되는 두 개의 미리 정의된 스키마 중 하나를 확장합니다. 우리의 경우에는, 우리는 사용할 light-grid
것입니다.
$custom-grid-schema : extend(
$light-grid ,
(
group-row-background: (color:('secondary' , 100 )),
group-row-selected-background: (color:('primary' , 400 )),
group-label-column-name-text: (color:('primary' , 600 )),
group-label-icon: (color:('primary' , 600 )),
group-label-text: (color:('secondary' , 700 )),
group-count-background: (color:('primary' , 600 )),
group-count-text-color: (color:('secondary' , 400 )),
expand-icon-color: (color:('primary' , 600 )),
expand-icon-hover-color: (color:('primary' , 400 ))
)
);
scss
사용자 지정 스키마를 적용하려면 (light
또는 dark
) 전역을 확장해야 합니다. 전체 프로세스는 실제로 구성 요소에 사용자 정의 스키마를 제공하고 나중에 해당 구성 요소 테마에 추가합니다.
$my-custom-schema : extend(
$light-material-schema ,
(
grid: $custom-grid-schema
)
);
$custom-theme : grid-theme(
$palette : $custom-palette ,
$schema : $my-custom-schema
);
scss
사용자 정의 테마 적용
테마를 적용하는 가장 쉬운 방법은 전역 스타일 파일에 sass
@include
문을 사용하는 것입니다.
@include css-vars($custom-theme );
@include css-vars($custom-chips-theme );
scss
범위가 지정된 구성요소 테마
사용자 정의 테마가 특정 구성 요소에만 영향을 미치도록 하려면 방금 정의한 모든 스타일을 전역 스타일 파일에서 사용자 정의 구성 요소의 스타일 파일로 이동할 수 있습니다(index
파일 가져오기 포함).
이렇게 하면 Angular의 ViewEncapsulation 덕분에 사용자 정의 구성 요소에만 스타일이 적용됩니다.
구성 요소가 ViewEncapsulation을 Emulated
사용하는 경우 그리드 내부에 있는 구성 요소의 스타일을 지정하려면 이 캡슐화를 관::ng-deep
통해야 합니다.
이 예에서는 칩 테마에 사용해야::ng-deep
합니다.
@include css-vars($custom-theme );
:host {
::ng-deep {
@include chip($custom-chips-theme );
}
}
scss
데모
import { Component, ViewChild, ViewEncapsulation } from '@angular/core' ;
import { DefaultSortingStrategy, IgxGridComponent, ISortingExpression, SortingDirection, IgxColumnComponent, IgxCellTemplateDirective } from 'igniteui-angular' ;
import { INVOICE_DATA } from '../../data/invoiceData' ;
import { IgxPreventDocumentScrollDirective } from '../../directives/prevent-scroll.directive' ;
import { NgIf } from '@angular/common' ;
@Component ({
encapsulation : ViewEncapsulation.Emulated,
selector : 'app-grid-groupby-sample' ,
styleUrls : ['./grid-groupby-styling.component.scss' ],
templateUrl : './grid-groupby-styling.component.html' ,
imports : [IgxGridComponent, IgxPreventDocumentScrollDirective, IgxColumnComponent, IgxCellTemplateDirective, NgIf]
})
export class GridGroupByStylingComponent {
@ViewChild ('grid1' , { read : IgxGridComponent, static : true })
public grid1: IgxGridComponent;
public data;
public expr: ISortingExpression[];
constructor ( ) {
this .data = INVOICE_DATA;
this .expr = [
{ dir : SortingDirection.Asc, fieldName : 'ShipCountry' , ignoreCase : false ,
strategy : DefaultSortingStrategy.instance() },
{ dir : SortingDirection.Asc, fieldName : 'ShipCity' , ignoreCase : false ,
strategy : DefaultSortingStrategy.instance() }
];
}
public formatDate (val: Date ) {
return new Intl .DateTimeFormat('en-US' ).format(val);
}
public formatCurrency (value: number ) {
return '$' + value.toFixed(2 );
}
}
ts コピー <div class ="grid-wrapper" >
<igx-grid
[igxPreventDocumentScroll ]="true"
#grid1
[data ]="data"
[width ]="'100%'"
[height ]="'540px'"
[groupingExpressions ]="expr"
>
<igx-column field ="OrderID" header ="Order ID" [hidden ]="true" > </igx-column >
<igx-column
field ="ShipCountry"
header ="Ship Country"
width ="200px"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="OrderDate"
header ="Order Date"
width ="200px"
[formatter ]="formatDate"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="PostalCode"
header ="Postal Code"
width ="200px"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="Discontinued"
header ="Discontinued"
width ="200px"
[groupable ]="true"
>
<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 ="ShipName"
header ="Ship Name"
width ="250px"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="ShipCity"
header ="Ship City"
width ="250px"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="ShipperName"
header ="Shipper Name"
width ="250px"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="Salesperson"
header ="Salesperson"
width ="250px"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="UnitPrice"
header ="Unit Price"
width ="150px"
[formatter ]="formatCurrency"
dataType ="number"
[groupable ]="true"
>
</igx-column >
<igx-column
field ="Quantity"
header ="Quantity"
width ="150px"
dataType ="number"
[groupable ]="true"
>
</igx-column >
</igx-grid >
</div >
html コピー @use "layout.scss" ;
@use "igniteui-angular/theming" as *;
$yellow : #ffcd0f ;
$gray : #494949 ;
$light-gray : #f8f8f8 ;
$black : #222 ;
$custom-theme : grid-theme(
$group-row-background : $gray ,
$group-row-selected-background : #383838 ,
$group-label-column-name-text : $light-gray ,
$group-label-icon : $yellow ,
$group-label-text : $light-gray ,
$group-count-background : $yellow ,
$group-count-text-color : $black ,
$expand-icon-color : $yellow ,
$expand-icon-hover-color : rgb(223 , 181 , 13 ),
$cell-active-border-color : $yellow ,
$row-selected-background : #fff6d3 ,
$row-selected-text-color : $black ,
$drop-indicator-color : $yellow
);
$custom-chips-theme : chip-theme(
$background : $gray ,
$text-color : $light-gray ,
$hover-text-color : #e7e7e7
);
@include css-vars($custom-theme );
:host {
::ng-deep {
@include chip($custom-chips-theme );
}
}
scss コピー
샘플은 Change Theme
에서 선택한 전역 테마의 영향을 받지 않습니다.
알려진 제한 사항
한정
설명
그룹화된 열의 최대 개수는 10개입니다.
10개 이상의 열이 그룹화되면 오류가 발생합니다.
API 참조
추가 리소스
우리 커뮤니티는 활동적이며 항상 새로운 아이디어를 환영합니다.