Skip to content

Commit 14ec463

Browse files
authored
feat(grids): add empty and loading declarative template directives (#15895)
1 parent 66bb654 commit 14ec463

File tree

10 files changed

+115
-17
lines changed

10 files changed

+115
-17
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,25 @@ All notable changes for each version of this project will be documented in this
1111
- `IgxChip`
1212
- **Behavioral Change** The `variant` is now strictly typed with the union of supported options and no longer accepts invalid values for the default state, provide no value (nullish) instead is needed.
1313

14+
### New Features
15+
- `IgxGrid`, `IgxTreeGrid`, `IgxHierarchicalGrid`, `IgxPivotGrid`
16+
- Added a new `igxGridEmpty` template directive that allows assigning the `emptyGridTemplate` declaratively, without the need to get and assign reference, like other grid templates like:
17+
```html
18+
<igx-grid>
19+
<ng-template igxGridEmpty>
20+
<!-- content to show when the grid is empty -->
21+
</ng-template>
22+
</igx-grid>
23+
```
24+
- Added a new `igxGridLoading` template directive that allows assigning the `loadingGridTemplate` declaratively, without the need to get and assign reference, like other grid templates like:
25+
```html
26+
<igx-grid>
27+
<ng-template igxGridLoading>
28+
<!-- content to show when the grid is loading -->
29+
</ng-template>
30+
</igx-grid>
31+
```
32+
1433
## 19.2.0
1534

1635
### General

projects/igniteui-angular/src/lib/grids/grid-base.directive.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ import { FilteringStrategy, IFilteringStrategy } from '../data-operations/filter
8080
import {
8181
IgxRowExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective,
8282
IgxHeaderCollapsedIndicatorDirective, IgxExcelStyleHeaderIconDirective, IgxSortAscendingHeaderIconDirective,
83-
IgxSortDescendingHeaderIconDirective, IgxSortHeaderIconDirective
83+
IgxSortDescendingHeaderIconDirective, IgxSortHeaderIconDirective,
84+
IgxGridLoadingTemplateDirective, IgxGridEmptyTemplateDirective,
8485
} from './grid.directives';
8586
import {
8687
GridKeydownTargetType,
@@ -260,11 +261,22 @@ export abstract class IgxGridBaseDirective implements GridType,
260261
*
261262
* @example
262263
* ```html
264+
* <ng-template igxGridEmpty>
265+
* <!-- content to show when the grid is empty -->
266+
* </ng-template>
267+
* ```
268+
* Or
269+
* ```html
263270
* <igx-grid [id]="'igx-grid-1'" [data]="Data" [emptyGridTemplate]="myTemplate" [autoGenerate]="true"></igx-grid>
264271
* ```
265272
*/
266273
@Input()
267-
public emptyGridTemplate: TemplateRef<IgxGridTemplateContext>;
274+
public get emptyGridTemplate(): TemplateRef<IgxGridTemplateContext> {
275+
return this._emptyGridTemplate || this.emptyDirectiveTemplate;
276+
}
277+
public set emptyGridTemplate(template: TemplateRef<IgxGridTemplateContext>) {
278+
this._emptyGridTemplate = template;
279+
}
268280

269281
/**
270282
* Gets/Sets a custom template for adding row UI when grid is empty.
@@ -282,11 +294,22 @@ export abstract class IgxGridBaseDirective implements GridType,
282294
*
283295
* @example
284296
* ```html
297+
* <ng-template igxGridLoading>
298+
* <!-- content to show when the grid is loading -->
299+
* </ng-template>
300+
* ```
301+
* Or
302+
* ```html
285303
* <igx-grid [id]="'igx-grid-1'" [data]="Data" [loadingGridTemplate]="myTemplate" [autoGenerate]="true"></igx-grid>
286304
* ```
287305
*/
288306
@Input()
289-
public loadingGridTemplate: TemplateRef<IgxGridTemplateContext>;
307+
public get loadingGridTemplate(): TemplateRef<IgxGridTemplateContext> {
308+
return this._loadingGridTemplate || this.loadingDirectiveTemplate;
309+
}
310+
public set loadingGridTemplate(template: TemplateRef<IgxGridTemplateContext>) {
311+
this._loadingGridTemplate = template;
312+
}
290313

291314
/**
292315
* Get/Set IgxSummaryRow height
@@ -1709,6 +1732,13 @@ export abstract class IgxGridBaseDirective implements GridType,
17091732
@ContentChildren(IgxDragIndicatorIconDirective, { read: TemplateRef, descendants: false })
17101733
public dragIndicatorIconTemplates: QueryList<TemplateRef<IgxGridEmptyTemplateContext>>;
17111734

1735+
1736+
@ContentChild(IgxGridLoadingTemplateDirective, { read: TemplateRef })
1737+
protected loadingDirectiveTemplate: TemplateRef<IgxGridTemplateContext>;
1738+
1739+
@ContentChild(IgxGridEmptyTemplateDirective, { read: TemplateRef })
1740+
protected emptyDirectiveTemplate: TemplateRef<IgxGridTemplateContext>;
1741+
17121742
/**
17131743
* @hidden @internal
17141744
*/
@@ -3186,6 +3216,8 @@ export abstract class IgxGridBaseDirective implements GridType,
31863216
private _rowCollapsedIndicatorTemplate: TemplateRef<IgxGridRowTemplateContext>;
31873217
private _headerExpandIndicatorTemplate: TemplateRef<IgxGridTemplateContext>;
31883218
private _headerCollapseIndicatorTemplate: TemplateRef<IgxGridTemplateContext>;
3219+
private _emptyGridTemplate: TemplateRef<IgxGridTemplateContext>;
3220+
private _loadingGridTemplate: TemplateRef<IgxGridTemplateContext>;
31893221

31903222
private _cdrRequests = false;
31913223
private _resourceStrings = getCurrentResourceStrings(GridResourceStringsEN);

projects/igniteui-angular/src/lib/grids/grid.directives.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,30 @@ export class IgxSortDescendingHeaderIconDirective {
155155
}
156156
}
157157

158+
/** @hidden */
159+
@Directive({
160+
selector: '[igxGridLoading]',
161+
standalone: true
162+
})
163+
export class IgxGridLoadingTemplateDirective {
164+
public static ngTemplateContextGuard(_directive: IgxGridLoadingTemplateDirective,
165+
context: unknown): context is IgxGridTemplateContext {
166+
return true
167+
}
168+
}
169+
170+
/** @hidden */
171+
@Directive({
172+
selector: '[igxGridEmpty]',
173+
standalone: true
174+
})
175+
export class IgxGridEmptyTemplateDirective {
176+
public static ngTemplateContextGuard(_directive: IgxGridEmptyTemplateDirective,
177+
context: unknown): context is IgxGridTemplateContext {
178+
return true
179+
}
180+
}
181+
158182
/**
159183
* @hidden
160184
*/

projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { ISortingExpression, SortingDirection } from '../../data-operations/sort
2424
import { GRID_SCROLL_CLASS } from '../../test-utils/grid-functions.spec';
2525
import { AsyncPipe } from '@angular/common';
2626
import { IgxPaginatorComponent, IgxPaginatorContentDirective } from '../../paginator/paginator.component';
27-
import { IGridRowEventArgs, IgxColumnGroupComponent, IgxGridFooterComponent, IgxGridRow, IgxGroupByRow, IgxSummaryRow } from '../public_api';
27+
import { IGridRowEventArgs, IgxColumnGroupComponent, IgxGridEmptyTemplateDirective, IgxGridFooterComponent, IgxGridLoadingTemplateDirective, IgxGridRow, IgxGroupByRow, IgxSummaryRow } from '../public_api';
2828
import { getComponentSize } from '../../core/utils';
2929
import { setElementSize, ymd } from '../../test-utils/helper-utils.spec';
3030

@@ -580,16 +580,28 @@ describe('IgxGrid Component Tests #grid', () => {
580580
expect(gridBody.nativeElement.textContent).not.toEqual(grid.emptyFilteredGridMessage);
581581
}));
582582

583-
it('should allow applying custom loading indicator', fakeAsync(() => {
583+
it('should allow applying custom empty and loading indicator', fakeAsync(() => {
584584
const fixture = TestBed.createComponent(IgxGridRemoteOnDemandComponent);
585-
fixture.componentInstance.instance.loadingGridTemplate = fixture.componentInstance.customTemplate;
585+
fixture.componentInstance.customLoading = true;
586586
fixture.detectChanges();
587587
tick(16);
588588

589589
const grid = fixture.componentInstance.instance;
590590
const gridBody = fixture.debugElement.query(By.css(TBODY_CLASS));
591591
const gridHead = fixture.debugElement.query(By.css(THEAD_CLASS));
592592

593+
grid.isLoading = false;
594+
tick();
595+
fixture.detectChanges();
596+
expect(gridBody.nativeElement.textContent).toEqual('No Data 😢');
597+
grid.isLoading = true;
598+
tick();
599+
fixture.detectChanges();
600+
expect(gridBody.nativeElement.textContent).toEqual('Loading 🔃');
601+
602+
grid.loadingGridTemplate = fixture.componentInstance.customTemplate;
603+
grid.markForCheck();
604+
fixture.detectChanges();
593605
expect(gridBody.nativeElement.textContent).toEqual('Loading...');
594606
expect(gridBody.nativeElement.textContent).not.toEqual(grid.emptyFilteredGridMessage);
595607

@@ -3612,21 +3624,26 @@ export class IgxGridRemoteVirtualizationComponent implements OnInit, AfterViewIn
36123624
@Component({
36133625
template: `
36143626
<igx-grid [data]="data | async" (dataPreLoad)="dataLoading($event)" [isLoading]="true" [autoGenerate]="true" [height]="'600px'">
3627+
<span *igxGridEmpty>No Data 😢</span>
3628+
@if (customLoading) {
3629+
<ng-template igxGridLoading>Loading 🔃</ng-template>
3630+
}
36153631
</igx-grid>
36163632
36173633
<ng-template #customTemplate>
36183634
<span>Loading...</span>
36193635
</ng-template>
36203636
`,
36213637
providers: [LocalService],
3622-
imports: [IgxGridComponent, AsyncPipe]
3638+
imports: [IgxGridComponent, IgxGridEmptyTemplateDirective, IgxGridLoadingTemplateDirective, AsyncPipe]
36233639
})
36243640
export class IgxGridRemoteOnDemandComponent {
36253641
@ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true })
36263642
public instance: IgxGridComponent;
36273643
@ViewChild('customTemplate', { read: TemplateRef, static: true })
36283644
public customTemplate: TemplateRef<any>;
36293645
public data;
3646+
public customLoading = false;
36303647
constructor(private localService: LocalService, public cdr: ChangeDetectorRef) { }
36313648

36323649
public bind() {

projects/igniteui-angular/src/lib/grids/grid/public_api.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { IgxGridDetailTemplateDirective, IgxGroupByRowTemplateDirective } from '
55
/* Imports that cannot be resolved from IGX_GRID_COMMON_DIRECTIVES spread
66
NOTE: Do not remove! Issue: https://github.com/IgniteUI/igniteui-angular/issues/13310
77
*/
8-
8+
99
import {
1010
IgxRowDirective,
1111
IgxGridFooterComponent,
@@ -17,6 +17,8 @@ import {
1717
IgxSortAscendingHeaderIconDirective,
1818
IgxSortDescendingHeaderIconDirective,
1919
IgxSortHeaderIconDirective,
20+
IgxGridEmptyTemplateDirective,
21+
IgxGridLoadingTemplateDirective,
2022
IgxExcelStyleHeaderIconDirective,
2123
IgxDragIndicatorIconDirective,
2224
IgxRowDragGhostDirective,
@@ -103,6 +105,8 @@ export const IGX_GRID_DIRECTIVES = [
103105
IgxSortAscendingHeaderIconDirective,
104106
IgxSortDescendingHeaderIconDirective,
105107
IgxSortHeaderIconDirective,
108+
IgxGridEmptyTemplateDirective,
109+
IgxGridLoadingTemplateDirective,
106110
IgxDragIndicatorIconDirective,
107111
IgxRowDragGhostDirective,
108112
IgxGridStateDirective,

projects/igniteui-angular/src/lib/grids/public_api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import {
3333
IgxExcelStyleLoadingValuesTemplateDirective
3434
} from './filtering/excel-style/public_api';
3535
import { IgxGridFooterComponent } from './grid-footer/grid-footer.component';
36-
import { IgxExcelStyleHeaderIconDirective, IgxHeaderCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxRowExpandedIndicatorDirective, IgxSortAscendingHeaderIconDirective, IgxSortDescendingHeaderIconDirective, IgxSortHeaderIconDirective } from './grid.directives';
36+
import { IgxExcelStyleHeaderIconDirective, IgxHeaderCollapsedIndicatorDirective, IgxHeaderExpandedIndicatorDirective, IgxRowCollapsedIndicatorDirective, IgxRowExpandedIndicatorDirective, IgxSortAscendingHeaderIconDirective, IgxSortDescendingHeaderIconDirective, IgxSortHeaderIconDirective, IgxGridEmptyTemplateDirective, IgxGridLoadingTemplateDirective } from './grid.directives';
3737
import {
3838
IgxGridHeaderComponent,
3939
IgxGridHeaderGroupComponent,
@@ -126,6 +126,8 @@ export const IGX_GRID_COMMON_DIRECTIVES = [
126126
IgxSortAscendingHeaderIconDirective,
127127
IgxSortDescendingHeaderIconDirective,
128128
IgxSortHeaderIconDirective,
129+
IgxGridEmptyTemplateDirective,
130+
IgxGridLoadingTemplateDirective,
129131
IgxDragIndicatorIconDirective,
130132
IgxRowDragGhostDirective,
131133
IgxGridStateDirective,

src/app/grid-remote-paging/grid-remote-paging.sample.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
[(perPage)]="perPage" (pageChange)="paginate($event)" (perPageChange)="perPageChange($event)">
1313
</igx-paginator>
1414
}
15+
<span *igxGridLoading> Loading 🔃 </span>
1516
</igx-grid>
1617

1718
<igx-card style="width: 360px; margin-top: 12px">

src/app/grid-remote-paging/grid-remote-paging.sample.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ import { FormsModule } from '@angular/forms';
44

55
import { Observable } from 'rxjs';
66
import { RemoteService } from '../shared/remote.service';
7-
import { GridPagingMode, IgxButtonDirective, IgxCardComponent, IgxCardContentDirective, IgxCardHeaderComponent, IgxCardHeaderTitleDirective, IgxColumnComponent, IgxGridComponent, IgxPaginatorComponent, IgxSelectComponent, IgxSelectItemComponent } from 'igniteui-angular';
7+
import { GridPagingMode, IgxButtonDirective, IgxCardComponent, IgxCardContentDirective, IgxCardHeaderComponent, IgxCardHeaderTitleDirective, IGX_GRID_DIRECTIVES, IgxGridComponent, IgxPaginatorComponent, IgxSelectComponent, IgxSelectItemComponent } from 'igniteui-angular';
88

99
@Component({
1010
selector: 'app-grid-remote-paging-sample',
1111
templateUrl: 'grid-remote-paging.sample.html',
1212
providers: [RemoteService],
13-
imports: [IgxGridComponent, IgxColumnComponent, IgxPaginatorComponent, IgxCardComponent, IgxCardHeaderComponent, IgxCardHeaderTitleDirective, IgxCardContentDirective, IgxButtonDirective, IgxSelectComponent, FormsModule, IgxSelectItemComponent, AsyncPipe]
13+
imports: [IGX_GRID_DIRECTIVES, IgxPaginatorComponent, IgxCardComponent, IgxCardHeaderComponent, IgxCardHeaderTitleDirective, IgxCardContentDirective, IgxButtonDirective, IgxSelectComponent, FormsModule, IgxSelectItemComponent, AsyncPipe]
1414
})
1515
export class GridRemotePagingSampleComponent implements OnInit, AfterViewInit, OnDestroy {
1616
@ViewChild('grid1', { static: true }) public grid1: IgxGridComponent;

src/app/grid-row-draggable/grid-row-draggable.sample.html

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,17 @@
2121
</ng-template>
2222
</igx-grid>
2323
<igx-grid #grid2 igxDrop [data]="newData" [primaryKey]="'ProductID'"
24-
[width]="'500px'" [height]="'600px'" [emptyGridTemplate]="dragHereTemplate"
25-
(enter)="onEnterAllowed($event)" (leave)="onLeaveAllowed($event)" (dropped)="onDropAllowed($event)">
24+
[width]="'500px'" [height]="'600px'"
25+
(enter)="onEnterAllowed($event)" (leave)="onLeaveAllowed($event)" (dropped)="onDropAllowed($event)">
2626
<igx-column [field]="'ProductName'" [width]="'200px'"></igx-column>
2727
<igx-column [field]="'UnitsInStock'"></igx-column>
2828
<igx-column [field]="'ProductID'" [editable]="true"></igx-column>
2929
<ng-template igxDragIndicatorIcon>
3030
<igx-icon>info</igx-icon>
3131
</ng-template>
32+
<ng-template igxGridEmpty>Drag Here</ng-template>
3233
</igx-grid>
3334
</div>
3435
<div class="dropable-area">
3536
<div igxDrop (enter)="onEnterBlocked($event)" (leave)="onLeaveBlocked($event)" (dropped)="onDropBlocked($event)">Drag here</div>
3637
</div>
37-
<ng-template #dragHereTemplate>Drag Here</ng-template>
38-

src/app/grid-row-draggable/grid-row-draggable.sample.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { FormsModule } from '@angular/forms';
55
import { Observable } from 'rxjs';
66

77
import { RemoteService } from '../shared/remote.service';
8-
import { IgxButtonGroupComponent, IgxCellTemplateDirective, IgxColumnComponent, IgxGridComponent, IgxIconComponent, IgxSwitchComponent, IgxRowDragGhostDirective, IgxDragIndicatorIconDirective, IgxDropDirective } from 'igniteui-angular';
8+
import { IgxButtonGroupComponent, IgxCellTemplateDirective, IgxColumnComponent, IgxGridComponent, IgxIconComponent, IgxSwitchComponent, IgxRowDragGhostDirective, IgxDragIndicatorIconDirective, IgxDropDirective, IgxGridEmptyTemplateDirective } from 'igniteui-angular';
99
import { IgxRowDragDirective } from 'projects/igniteui-angular/src/lib/grids/row-drag.directive';
1010

1111

@@ -20,7 +20,7 @@ enum DragIcon {
2020
templateUrl: 'grid-row-draggable.sample.html',
2121
styleUrls: ['grid-row-draggable.sample.scss'],
2222
providers: [RemoteService],
23-
imports: [IgxButtonGroupComponent, IgxSwitchComponent, FormsModule, IgxGridComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxIconComponent, IgxRowDragDirective, IgxRowDragGhostDirective, IgxDropDirective, IgxDragIndicatorIconDirective, AsyncPipe]
23+
imports: [IgxButtonGroupComponent, IgxSwitchComponent, FormsModule, IgxGridComponent, IgxColumnComponent, IgxCellTemplateDirective, IgxIconComponent, IgxRowDragDirective, IgxRowDragGhostDirective, IgxDropDirective, IgxDragIndicatorIconDirective, IgxGridEmptyTemplateDirective, AsyncPipe]
2424
})
2525
export class GridRowDraggableComponent implements AfterViewInit {
2626
@HostBinding('style.--ig-size')

0 commit comments

Comments
 (0)