Skip to content

Commit 99352a2

Browse files
committed
Merge branch 'master' of https://github.com/IgniteUI/igniteui-angular into rkaraivanov/grids-spa-and-wellbeing
2 parents f7bf723 + 4581b5d commit 99352a2

38 files changed

+1669
-66
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes for each version of this project will be documented in this
55
## 12.1.0
66

77
### New Features
8+
- `igxGrid`
9+
- New `additionalTemplateContext` column input:
10+
11+
```html
12+
<igx-column [additionalTemplateContext]="contextObject">
13+
<ng-template igxCell let-cell="cell" let-props="additionalTemplateContext">
14+
{{ props }}
15+
</ng-template>
16+
</igx-column>
17+
```
818
- `Toolbar Actions`
919
- Exposed a new input property `overlaySettings` for all column actions (`hiding` | `pinning` | `advanced filtering` | `exporter`). Example below:
1020

projects/igniteui-angular/src/lib/data-operations/sorting-strategy.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ export class IgxSorting implements IGridSortingStrategy {
234234

235235
export class IgxDataRecordSorting extends IgxSorting {
236236

237-
protected getFieldValue(obj: any, key: string, isDate: boolean = false): any {
238-
return isDate ? parseDate(resolveNestedPath(obj.data, key)) : resolveNestedPath(obj.data, key);
237+
protected getFieldValue(obj: any, key: string, isDate: boolean = false, isTime: boolean = false): any {
238+
return super.getFieldValue(obj.data, key, isDate, isTime);
239239
}
240240
}

projects/igniteui-angular/src/lib/expansion-panel/expansion-panel.spec.ts

+33
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,39 @@ describe('igxExpansionPanel', () => {
198198
expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1);
199199
}));
200200

201+
it('Should expand/collapse without animation when animationSettings === null', fakeAsync(() => {
202+
const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent);
203+
fixture.detectChanges();
204+
const panel = fixture.componentInstance.panel;
205+
panel.animationSettings = null;
206+
expect(panel).toBeTruthy();
207+
208+
spyOn(panel.contentCollapsed, 'emit');
209+
spyOn(panel.contentExpanded, 'emit');
210+
spyOn(panel.contentCollapsing, 'emit');
211+
spyOn(panel.contentExpanding, 'emit');
212+
213+
panel.toggle();
214+
tick();
215+
fixture.detectChanges();
216+
expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(0); // Initially collapsed
217+
expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(0);
218+
expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1);
219+
expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1);
220+
expect(panel.contentExpanding.emit).toHaveBeenCalledBefore(panel.contentExpanded.emit);
221+
expect(panel.collapsed).toBeFalsy();
222+
223+
panel.toggle();
224+
tick();
225+
fixture.detectChanges();
226+
expect(panel.contentCollapsed.emit).toHaveBeenCalledTimes(1);
227+
expect(panel.contentCollapsing.emit).toHaveBeenCalledTimes(1);
228+
expect(panel.contentExpanded.emit).toHaveBeenCalledTimes(1);
229+
expect(panel.contentExpanding.emit).toHaveBeenCalledTimes(1);
230+
expect(panel.contentCollapsing.emit).toHaveBeenCalledBefore(panel.contentCollapsed.emit);
231+
expect(panel.collapsed).toBeTruthy();
232+
}));
233+
201234
it('Should allow expanding and collapsing events to be cancelled', fakeAsync(() => {
202235
const fixture = TestBed.createComponent(IgxExpansionPanelSampleComponent);
203236
fixture.detectChanges();

projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.spec.ts

+39
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { AnimationBuilder } from '@angular/animations';
22
import { TestBed } from '@angular/core/testing';
33
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
44
import { noop } from 'rxjs';
5+
import { growVerIn, growVerOut } from '../animations/main';
56
import { configureTestSuite } from '../test-utils/configure-suite';
67
import { ToggleAnimationPlayer ,ANIMATION_TYPE } from './toggle-animation-component';
78

@@ -40,5 +41,43 @@ describe('Toggle animation component', () => {
4041
player.playCloseAnimation(null, mockCB);
4142
expect(startPlayerSpy).toHaveBeenCalledWith(ANIMATION_TYPE.CLOSE, null, mockCB);
4243
});
44+
45+
it('Should allow overwriting animation setting with falsy value', () => {
46+
const player = new MockTogglePlayer(mockBuilder);
47+
expect(player.animationSettings).toEqual({
48+
openAnimation: growVerIn,
49+
closeAnimation: growVerOut
50+
});
51+
player.animationSettings = null;
52+
expect(player.animationSettings).toEqual(null);
53+
});
54+
55+
it('Should not throw if called with a falsy animationSettings value', () => {
56+
const player = new MockTogglePlayer(mockBuilder);
57+
player.animationSettings = null;
58+
const mockCb = jasmine.createSpy('mockCb');
59+
const mockElement = jasmine.createSpy('element');
60+
spyOn(player.openAnimationStart, 'emit');
61+
spyOn(player.openAnimationDone, 'emit');
62+
spyOn(player.closeAnimationStart, 'emit');
63+
spyOn(player.closeAnimationDone, 'emit');
64+
65+
player.playOpenAnimation({ nativeElement: mockElement }, mockCb);
66+
expect(player.openAnimationStart.emit).toHaveBeenCalledTimes(1);
67+
expect(player.openAnimationDone.emit).toHaveBeenCalledTimes(1);
68+
expect(player.closeAnimationStart.emit).toHaveBeenCalledTimes(0);
69+
expect(player.closeAnimationDone.emit).toHaveBeenCalledTimes(0);
70+
expect(player.openAnimationStart.emit).toHaveBeenCalledBefore(player.openAnimationDone.emit);
71+
expect(mockCb).toHaveBeenCalledTimes(1);
72+
73+
player.playCloseAnimation({ nativeElement: mockElement }, mockCb);
74+
expect(player.openAnimationStart.emit).toHaveBeenCalledTimes(1);
75+
expect(player.openAnimationDone.emit).toHaveBeenCalledTimes(1);
76+
expect(player.closeAnimationStart.emit).toHaveBeenCalledTimes(1);
77+
expect(player.closeAnimationDone.emit).toHaveBeenCalledTimes(1);
78+
expect(player.closeAnimationStart.emit).toHaveBeenCalledBefore(player.closeAnimationDone.emit);
79+
80+
expect(mockCb).toHaveBeenCalledTimes(2);
81+
});
4382
});
4483
});

projects/igniteui-angular/src/lib/expansion-panel/toggle-animation-component.ts

+35-13
Original file line numberDiff line numberDiff line change
@@ -99,19 +99,33 @@ export abstract class ToggleAnimationPlayer implements ToggleAnimationOwner, OnD
9999
target = this.initializePlayer(type, targetElement, callback);
100100
}
101101

102-
if (target.hasStarted()) {
102+
// V.S. Jun 28th, 2021 #9783: player will NOT be initialized w/ null settings
103+
// events will already be emitted
104+
if (!target || target.hasStarted()) {
103105
return;
104106
}
105107

106108
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationStart : this.closeAnimationStart;
107109
targetEmitter.emit();
108-
target.play();
110+
if (target) {
111+
target.play();
112+
}
109113
}
110114

111115
private initializePlayer(type: ANIMATION_TYPE, targetElement: ElementRef, callback: () => void): AnimationPlayer {
112116
const oppositeType = type === ANIMATION_TYPE.OPEN ? ANIMATION_TYPE.CLOSE : ANIMATION_TYPE.OPEN;
117+
// V.S. Jun 28th, 2021 #9783: Treat falsy animation settings as disabled animations
118+
const targetAnimationSettings = this.animationSettings || { closeAnimation: null, openAnimation: null };
113119
const animationSettings = type === ANIMATION_TYPE.OPEN ?
114-
this.animationSettings.openAnimation : this.animationSettings.closeAnimation;
120+
targetAnimationSettings.openAnimation : targetAnimationSettings.closeAnimation;
121+
// V.S. Jun 28th, 2021 #9783: When no animation in target direction, emit start and done events and return
122+
if (!animationSettings) {
123+
this.setCallback(type, callback);
124+
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationStart : this.closeAnimationStart;
125+
targetEmitter.emit();
126+
this.onDoneHandler(type);
127+
return;
128+
}
115129
const animation = useAnimation(animationSettings);
116130
const animationBuilder = this.builder.build(animation);
117131
const opposite = this.getPlayer(oppositeType);
@@ -132,23 +146,31 @@ export abstract class ToggleAnimationPlayer implements ToggleAnimationOwner, OnD
132146
const target = this.getPlayer(type);
133147
target.init();
134148
this.getPlayer(type).setPosition(1 - oppositePosition);
149+
this.setCallback(type, callback);
150+
target.onDone(() => {
151+
this.onDoneHandler(type);
152+
});
153+
return target;
154+
}
155+
156+
private onDoneHandler(type) {
157+
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationDone : this.closeAnimationDone;
158+
const targetCallback = type === ANIMATION_TYPE.OPEN ? this.onOpenedCallback : this.onClosedCallback;
159+
targetCallback();
160+
if (!(type === ANIMATION_TYPE.OPEN ? this.openInterrupted : this.closeInterrupted)) {
161+
targetEmitter.emit();
162+
}
163+
this.cleanUpPlayer(type);
164+
}
165+
166+
private setCallback(type: ANIMATION_TYPE, callback: () => void) {
135167
if (type === ANIMATION_TYPE.OPEN) {
136168
this.onOpenedCallback = callback;
137169
this.openInterrupted = false;
138170
} else if (type === ANIMATION_TYPE.CLOSE) {
139171
this.onClosedCallback = callback;
140172
this.closeInterrupted = false;
141173
}
142-
const targetEmitter = type === ANIMATION_TYPE.OPEN ? this.openAnimationDone : this.closeAnimationDone;
143-
target.onDone(() => {
144-
const targetCallback = type === ANIMATION_TYPE.OPEN ? this.onOpenedCallback : this.onClosedCallback;
145-
targetCallback();
146-
if (!(type === ANIMATION_TYPE.OPEN ? this.openInterrupted : this.closeInterrupted)) {
147-
targetEmitter.emit();
148-
}
149-
this.cleanUpPlayer(type);
150-
});
151-
return target;
152174
}
153175

154176

projects/igniteui-angular/src/lib/grids/cell.component.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {
165165
public get context(): any {
166166
return {
167167
$implicit: this.value,
168-
cell: this
168+
cell: this,
169+
additionalTemplateContext: this.column.additionalTemplateContext
169170
};
170171
}
171172

projects/igniteui-angular/src/lib/grids/columns/column.component.ts

+16
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,22 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy {
748748
@Input()
749749
public colStart: number;
750750

751+
/**
752+
* Sets/gets custom properties provided in additional template context.
753+
*
754+
* ```html
755+
* <igx-column [additionalTemplateContext]="contextObject">
756+
* <ng-template igxCell let-cell="cell" let-props="additionalTemplateContext">
757+
* {{ props }}
758+
* </ng-template>
759+
* </igx-column>
760+
* ```
761+
*
762+
* @memberof IgxColumnComponent
763+
*/
764+
@Input()
765+
public additionalTemplateContext: any;
766+
751767
/**
752768
* @hidden
753769
*/

projects/igniteui-angular/src/lib/grids/common/column.interface.ts

+1
Original file line numberDiff line numberDiff line change
@@ -49,5 +49,6 @@ export interface ColumnType {
4949
hasNestedPath: boolean;
5050
defaultTimeFormat: string;
5151
defaultDateTimeFormat: string;
52+
additionalTemplateContext: any;
5253
getGridTemplate(isRow: boolean, isIE: boolean): string;
5354
}

projects/igniteui-angular/src/lib/grids/common/grid.interface.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { ISortingExpression } from '../../data-operations/sorting-expression.int
77
import { IGroupingExpression } from '../../data-operations/grouping-expression.interface';
88
import { TransactionService, Transaction, State } from '../../services/public_api';
99
import { ITreeGridRecord } from '../tree-grid/public_api';
10-
import { IGroupByExpandState } from '../../data-operations/groupby-expand-state.interface';
1110
import { IGroupByRecord } from '../../data-operations/groupby-record.interface';
11+
import { IGroupByExpandState } from '../../data-operations/groupby-expand-state.interface';
1212

1313
export interface IGridDataBindable {
1414
data: any[] | null;
@@ -31,6 +31,7 @@ export interface GridType extends IGridDataBindable {
3131
id: string;
3232
renderedRowHeight: number;
3333
summaryPipeTrigger: number;
34+
hasColumnLayouts: boolean;
3435

3536
filterMode: FilterMode;
3637

@@ -100,8 +101,9 @@ export interface FlatGridType extends GridType {
100101
groupingExpressions: IGroupingExpression[];
101102
groupingExpressionsChange: EventEmitter<IGroupingExpression[]>;
102103

103-
clearGrouping(field: string): void;
104104
toggleGroup(groupRow: IGroupByRecord): void;
105+
clearGrouping(field: string): void;
106+
groupBy(expression: IGroupingExpression | Array<IGroupingExpression>): void;
105107
}
106108

107109
/**

projects/igniteui-angular/src/lib/grids/grid-common.module.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,14 @@ import { IgxGridFilteringModule } from './filtering/base/filtering.module';
3131
import { IgxRowDirective } from './row.directive';
3232
import {
3333
IgxExcelStyleHeaderIconDirective,
34+
IgxGroupAreaDropDirective,
3435
IgxHeaderCollapseIndicatorDirective,
3536
IgxHeaderExpandIndicatorDirective,
3637
IgxRowCollapsedIndicatorDirective,
3738
IgxRowExpandedIndicatorDirective
3839
} from './grid/grid.directives';
40+
import { IgxChipsModule } from '../chips/chips.module';
41+
import { IgxGroupByMetaPipe } from './grouping/group-by-area.directive';
3942
/**
4043
* @hidden
4144
*/
@@ -56,6 +59,8 @@ import {
5659
IgxHeaderExpandIndicatorDirective,
5760
IgxHeaderCollapseIndicatorDirective,
5861
IgxExcelStyleHeaderIconDirective,
62+
IgxGroupAreaDropDirective,
63+
IgxGroupByMetaPipe
5964
],
6065
entryComponents: [
6166
IgxAdvancedFilteringDialogComponent
@@ -89,6 +94,8 @@ import {
8994
IgxHeaderExpandIndicatorDirective,
9095
IgxHeaderCollapseIndicatorDirective,
9196
IgxExcelStyleHeaderIconDirective,
97+
IgxGroupAreaDropDirective,
98+
IgxGroupByMetaPipe
9299
],
93100
imports: [
94101
IgxGridColumnModule,
@@ -104,7 +111,8 @@ import {
104111
IgxGridExcelStyleFilteringModule,
105112
IgxRowDragModule,
106113
IgxPaginatorModule,
107-
IgxGridSharedModules
114+
IgxGridSharedModules,
115+
IgxChipsModule
108116
],
109117
providers: [
110118
{ provide: IgxGridTransaction, useClass: IgxBaseTransactionService }

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

+40
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ describe('IgxGrid - Column properties #grid', () => {
3434
ColumnsFromIterableComponent,
3535
TemplatedColumnsComponent,
3636
TemplatedInputColumnsComponent,
37+
TemplatedContextInputColumnsComponent,
3738
ColumnCellFormatterComponent,
3839
ColumnHaederClassesComponent,
3940
ColumnHiddenFromMarkupComponent,
@@ -308,6 +309,20 @@ describe('IgxGrid - Column properties #grid', () => {
308309

309310
});
310311

312+
it('should support passing properties through the additionalTemplateContext input property', () => {
313+
const fixture = TestBed.createComponent(TemplatedContextInputColumnsComponent);
314+
fixture.detectChanges();
315+
316+
const grid = fixture.componentInstance.instance;
317+
const contextObject = {property1: 'cellContent', property2: 'cellContent1'};
318+
const firstColumn = grid.columns[0];
319+
const secondColumn = grid.columns[1];
320+
321+
expect(firstColumn.additionalTemplateContext).toEqual(contextObject);
322+
expect(firstColumn.cells[0].nativeElement.innerText).toEqual(contextObject.property1);
323+
expect(secondColumn.cells[0].nativeElement.innerText).toEqual(contextObject.property2);
324+
});
325+
311326
it('should apply column\'s formatter programmatically', () => {
312327
const expectedVal = ['Johny', 'Sally', 'Tim'];
313328
const expectedValToLower = ['johny', 'sally', 'tim'];
@@ -1133,6 +1148,31 @@ export class TemplatedInputColumnsComponent {
11331148
public columns = Object.keys(this.data[0]);
11341149
}
11351150

1151+
1152+
@Component({
1153+
template: `
1154+
<igx-grid [data]="data">
1155+
<igx-column [additionalTemplateContext]="contextObject" field="FirstName">
1156+
<ng-template igxCell let-cell="cell">
1157+
{{ cell.column.additionalTemplateContext.property1 }}
1158+
</ng-template>
1159+
</igx-column>
1160+
<igx-column [additionalTemplateContext]="contextObject">
1161+
<ng-template igxCell let-cell="cell" let-props="additionalTemplateContext">
1162+
{{ props.property2 }}
1163+
</ng-template>
1164+
</igx-column>
1165+
</igx-grid>
1166+
`
1167+
})
1168+
export class TemplatedContextInputColumnsComponent {
1169+
@ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true })
1170+
public instance: IgxGridComponent;
1171+
public contextObject = {property1: 'cellContent', property2: 'cellContent1'};
1172+
1173+
public data = SampleTestData.personNameAgeData();
1174+
}
1175+
11361176
@Component({
11371177
template: `
11381178
<igx-grid [data]="data" height="500px" width="400px">

0 commit comments

Comments
 (0)