Angular 그리드 그룹화
Ignite UI for Angular 테이블이나 UI 그리드에서의 그룹 바이 동작은 열 값을 기반으로 그룹화된 데이터 행을 생성합니다. 그룹 By in 는igxGrid 계층적 구조로 그룹을 시각화할 수 있게 해줍니다. 그룹화된 데이터 행은 확장하거나 접힐 수 있으며, UI나 API를 통해 그룹화 순서를 변경할 수 있습니다. Row Select가 활성화되면 그룹 행의 가장 왼쪽 영역에 'Group By row' 셀렉터가 렌더링됩니다. 속성이rowSelection 단일로 설정되어 있을 경우, 체크박스는 비활성화되어 선택이 이루어진 그룹에 대한 표시로만 사용됩니다. 속성이rowSelection 멀티플로 설정되어 있다면, '그룹 별(Group By row)' 선택기를 클릭해 해당 그룹에 속하는 모든 레코드를 선택합니다.
Angular Grid Group By Example
이 예에서는 대량의 데이터를 그룹화하는 기능을 보여줍니다. 열 헤더를 상단(그룹화 영역)으로 드래그하면 사용자는 선택한 열에 대한 데이터를 계층 구조로 볼 수 있습니다. 더 많은 열 헤더를 맨 위로 드래그하여 여러 필드에서 그룹화할 수 있습니다. 이러한 그룹화 옵션은 사용자가 훨씬 빠르고 시각적으로 허용되는 방식으로 데이터를 표시하려는 수많은 행과 열이 있는 테이블이 있는 경우 유용합니다.
Initial Grouping State
격자의 속성에groupingExpressions 여러 식을 할당함으로써 격자의 초기 그룹화를 정의할 수 있습니다.
public ngOnInit() {
grid.groupingExpressions = [
{ fieldName: 'ProductName', dir: SortingDirection.Desc },
{ fieldName: 'Released', dir: SortingDirection.Desc }
];
}
그룹화식은 인터페이스를 구현ISortingExpression 합니다.
Group By API
Grouping 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>
public ngOnInit() {
grid.columns.forEach((column) => {
column.groupable = true;
});
}
런타임 동안 표현식은 속성에서groupingExpressions getable과 settable을 모두 사용할 수 있습니다. 기존 식을 추가하거나 변경해야 할 경우, 단일 또는 배groupBy 열과 함께 메서드를 사용할ISortingExpression 수도 있습니다.
grid.groupBy({ fieldName: 'ProductName', dir: SortingDirection.Desc, ignoreCase: true });
Note
지금까지는 그룹화/정렬이 서로 함께 작동했습니다. 13.2 버전에서는 정렬에서 그룹화를 분리하는 새로운 동작이 도입되었습니다. 예를 들어 그룹화를 지우면 그리드의 정렬 표현식이 지워지지 않으며 그 반대의 경우도 마찬가지입니다. 그러나 열이 정렬되고 그룹화된 경우 그룹화된 식이 우선합니다.
Expand/Collapse API
그룹화식 외에도, 그룹 행의 확장 상태를 제어할 수도 있습니다. 이들은 컴포넌igxGrid 트groupingExpansionState의 별도의 속성에 저장됩니다. 그룹 행은 생성되는 필드 이름과 각 그룹화 수준에서 나타내는 값을 바탕으로 고유하게 식별됩니다. 이는 확장 상태 인터페이스의 서명이 다음과 같다는 의미입니다:
export interface IGroupByKey {
fieldName: string;
value: any;
}
export interface IGroupByExpandState {
hierarchy: Array<IGroupByKey>;
expanded: boolean;
}
마찬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;
그룹은 생성, 확장(기본값) 또는 붕괴될 수 있으며, 확장 상태는 일반적으로 기본 동작과 반대되는 상태만 포함합니다. 이 속성을 통해groupsExpanded 그룹을 생성하거나 확장할지 여부를 제어할 수 있습니다.
Select/Deselect all rows in a group API
그룹 내 모든 행을 선택하고 선택 해제하는 기능은 andselectRowsInGroup API 메서드를 통해deselectRowsInGroup 가능합니다.
아래 코드 스니펫은 그룹 레코드 인스턴스selectRowsInGroup 메서드를 사용하여 그룹 내 모든 행을 선택하는 데 사용할 수 있습니다. 또한, 이 방법의 두 번째 매개변수는 불리언 속성으로, 이전 행 선택이 삭제될지 여부를 결정할 수 있습니다. 이전 선택은 기본적으로 유지됩니다.
const groupRow = this.grid.groupsRecords.find(r => r.value === "France");
const groupRow = this.grid.getRowByIndex(0).groupRow;
grid.selectRowsInGroup(groupRow);
프로그래밍적으로 그룹 내 모든 행을 선택 해제해야 한다면 이deselectRowsInGroup 방법을 사용할 수 있습니다.
const groupRow = this.grid.groupsRecords.find(r => r.value === "France");
const groupRow = this.grid.getRowByIndex(0).groupRow;
grid.deselectRowsInGroup(groupRow);
Templating
Group Row Templates
확장/축소 UI를 제외한 그룹 행은 완전히 템플릿화 가능합니다. 기본적으로 그룹화 아이콘을 렌더링하고 해당 아이콘이 나타내는 필드 이름과 값을 표시합니다. 렌더링되는 그룹화 레코드 템플릿에는 다음과 같은 서명이 있습니다.
export interface IGroupByRecord {
expression: ISortingExpression;
level: number;
records: GroupedRecords;
value: any;
groupParent: IGroupByRecord;
groups?: IGroupByRecord[];
}
예를 들어, 다음 템플릿은 그룹 행 요약을 더욱 자세하게 만듭니다.
<ng-template igxGroupByRow let-groupRow>
<span>Total items with value: {{ groupRow.value }} are {{ groupRow.records.length }}</span>
</ng-template>
Group Row Selector Templates
앞서 언급했듯이, 확장/접힘 UI를 제외한 그룹 행은 완전히 템플릿 가능해요. 그리드 내에서 사용자 정의 그룹 By 행 선택 템플릿을 만들려면 with<ng-template> 지시문을 선언igxGroupByRowSelector 하세요. 템플릿에서 암묵적으로 제공된 컨텍스트 변수에 접근할 수 있으며, Group By 행의 상태에 대한 정보를 제공하는 속성을 제공합니다.
이 속성은selectedCount 현재 선택된 그룹 레코드 수를 보여주고,totalCount 그룹에 속한 레코드 수를 보여줍니다.
<ng-template igxGroupByRowSelector let-groupByRowContext>
{{ groupByRowContext.selectedCount }} / {{ groupByRowContext.totalCount }}
</ng-template>
속성은groupRow 그룹 행에 대한 참조를 반환합니다.
<ng-template igxGroupByRowSelector let-groupByRowContext>
<div (click)="handleGroupByRowSelectorClick($event, groupByRowContext.groupRow)">Handle groupRow</div>
</ng-template>
그리고selectedCount 속성은totalCount 그룹 By 행 선택기를 검사할지 불확정(부분적으로 선택)해야 하는지 결정하는 데 사용할 수 있습니다.
<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>
Angular Grid Group By with Paging
그룹 행은 데이터 행과 함께 페이징 프로세스에 참여합니다. 각 페이지의 페이지 크기에 포함됩니다. 축소된 행은 페이징 프로세스에 포함되지 않습니다. 확장 또는 축소 작업을 수행하면 Paging이 페이지 수를 다시 계산하고 필요한 경우 페이지 인덱스를 조정합니다. 여러 페이지에 걸쳐 있는 그룹은 페이지 간에 분할됩니다. 그룹 행은 시작하는 페이지에만 표시되며 후속 페이지에서는 반복되지 않습니다. 그룹 행의 요약 정보는 전체 그룹을 기준으로 계산되며 Paging의 영향을 받지 않습니다.
Angular group by with paging example
Group By with Summaries
Group By와 요약 간의 통합은 요약 항목에 설명되어 있습니다.
Keyboard Navigation
그룹화 UI는 다음과 같은 키보드 상호 작용을 지원합니다.
그룹 행의 경우(포커스는 행 또는 확장/축소 셀에 있어야 함)
- ALT + RIGHT- 그룹 확장
- ALT + LEFT- 그룹 축소
- SPACE-rowSelection 속성이 다중으로 설정된 경우 그룹의 모든 행을 선택합니다.
그룹별 영역별 그룹 구성 요소는
igxChip칩에 집중해야 합니다- SHIFT + LEFT- 가능한 경우 그룹화 순서를 변경하여 초점을 맞춘 칩을 왼쪽으로 이동합니다.
- SHIFT + 오른쪽- 가능한 경우 그룹화 순서를 변경하여 초점을 맞춘 칩을 오른쪽으로 이동합니다.
- SPACE- 정렬 방향을 변경합니다.
- DELETE- 필드 그룹을 해제합니다.
- 칩의 개별 요소도 초점을 맞출 수 있으며 키를 사용하여 상호 작용할 수 있습니다 ENTER.
Angular Grid Custom Group By
igxGrid를 사용하면 열별 또는 그룹화 표현식별로 사용자 정의 그룹화를 정의할 수 있으며, 이는 사용자 정의 조건을 기반으로 그룹화를 제공합니다. 이는 복잡한 개체별로 그룹화해야 하거나 기타 애플리케이션별 시나리오에 유용합니다.
Note
사용자 지정 그룹화를 구현하려면 먼저 데이터를 적절히 정렬해야 합니다. 이 때문에 베이스DefaultSortingStrategy를 확장하는 맞춤형 정렬 전략을 적용해야 할 수도 있습니다. 데이터가 정렬된 후, 열이나 특정 그룹화식에 대해 agroupingComparer를 지정하여 사용자 정의 그룹을 결정할 수 있습니다.
아래 샘플은 사용자가 선택한 그룹화 모드를 기반으로 날짜 값이 일, 주, 월 또는 연도로 정렬되고 그룹화되는 맞춤형 그룹화 방식을Date 보여줍니다.
Angular custom group by example
이 샘플은 서로 다른 날짜 조건에 대한 맞춤형 정렬 전략을 정의합니다. 각 맞춤형 전략은 기본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;
}
}
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;
}
버전 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() });
}
}
스타일링
igxGrid는 스타일링Ignite UI for Angular Theme Library을 통해 가능합니다. 그리드는grid-theme 다양한 특성을 노출시켜 모든 기능을 맞춤화할 수 있게 합니다.
아래 단계에서는 그리드의 Group By 스타일을 사용자 정의하는 단계를 진행합니다.
Importing global theme
Group By 기능의 커스터마이징을 시작하려면, 모든 스타일링 기능과 믹싱이 있는 파일을 가져와index야 합니다.
@use "igniteui-angular/theming" as *;
// IMPORTANT: Prior to Ignite UI for Angular version 13 use:
// @import '~igniteui-angular/lib/core/styles/themes/index';
Defining custom theme
다음으로, Group By를 원하는 대로 커스터마이징하는 데 필요한 매개변수를 확장grid-theme 하고 수용하는 새로운 테마를 생성합니다. 또한 그룹 별 기능에서 사용되기 때문에 확장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
);
/* Chip theme will style the chips in the Group By area */
$custom-chips-theme: chip-theme(
$background: #494949,
$text-color: #f8f8f8,
$hover-text-color: #e7e7e7
);
Defining a custom color palette
위에서 설명한 방식에서는 색상 값이 하드코딩되었습니다. 또는 와palette 함수를 활용color 해 더 큰 유연성을 달성할 수도 있습니다.palette 제공된 기본 색상, 보조 색상, 표면색을 기반으로 색상 팔레트를 생성합니다.
$black-color: #292826;
$yellow-color: #ffcd0f;
$grey-color: #efefef;
$custom-palette: palette(
$primary: $black-color,
$secondary: $yellow-color,
$surface: $grey-color
);
커스텀 팔레트가 생성된 후, 이 함수는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)
);
Defining custom schemas
더 나아가 스키마의 모든 장점을 가진 유연한 구조를 구축할 수도 있습니다. 스키마는 주제의 레시피입니다. 각 컴포넌트에 제공되는 두 개의 미리 정의된 스키마 중 하나를 확장하세요. 우리의 경우에는light-grid
$custom-grid-schema: extend(
map.get('grid', $light-material-schema),
(
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))
)
);
커스텀 스키마를 적용하려면 전역(globalslight) 중 하나를dark 확장해야 합니다. 전체 과정은 실제로 컴포넌트에 커스텀 스키마를 제공하고, 그 후에 해당 컴포넌트 테마에 추가하는 것입니다.
$my-custom-schema: extend(
$light-material-schema,
(
grid: $custom-grid-schema
)
);
$custom-theme: grid-theme(
$palette: $custom-palette,
$schema: $my-custom-schema
);
Applying the custom theme
테마를 적용하는 가장 쉬운 방법은 글로벌 스타일 파일에 있는 문장을 사용하는sass @include 것입니다:
@include css-vars($custom-theme);
@include css-vars($custom-chips-theme);
Scoped component theme
커스텀 테마가 특정 컴포넌트에만 영향을 미치려면, 방금 정의한 모든 스타일을 전역 스타일 파일에서 커스텀 컴포넌트의 스타일 파일로 옮길 수 있습니다(파일 가져오기index도 포함해서요).
이렇게 하면 Angular의 ViewEncapsulation 덕분에 사용자 정의 구성 요소에만 스타일이 적용됩니다.
Note
만약 컴포넌트가 뷰 캡슐화를 사용Emulated 한다면, 그리드 내부에 있는 컴포넌트를 스타일링하기 위해 이 캡슐화::ng-deep를 뚫어야 합니다.
예시에서 칩 테마는 다음과 같이 사용::ng-deep 해야 합니다:
@include css-vars($custom-theme);
:host {
::ng-deep {
@include chip($custom-chips-theme);
}
}
Demo
Note
샘플은 선택된 글로벌 테마Change Theme의 영향을 받지 않습니다.
Known Limitations
| 한정 | 설명 |
|---|---|
| 그룹화된 열의 최대 개수는 10개입니다. | 10개 이상의 열이 그룹화되면 오류가 발생합니다. |
API References
- IgxGrid구성 요소
- Igx그룹별행
- IgxGrid구성 요소 스타일
- Isorting표현
- IgxColumnComponent
- IGroupByExpandState
- IgxChip구성 요소
- IgxChipComponent 스타일