Skip to content

Commit 33040f3

Browse files
committed
Merge branch 'pivot-grid-master' of https://github.com/IgniteUI/igniteui-angular into mdragnev/feat-10713
2 parents c28f07e + 9bac3bc commit 33040f3

35 files changed

+684
-391
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ All notable changes for each version of this project will be documented in this
3333
<igx-column field="Age"></igx-column>
3434
</igx-grid>
3535
```
36+
- Scrolling with the mouse wheel over cells with templates that include scrollable containers now correctly scroll these inner containers before the grid body scrolls.
3637

3738
## 13.0.5
3839

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ You can include Ignite UI for Angular in your project as a dependency using the
218218

219219
- [COVID-19 Dashboard](https://github.com/IgniteUI/COVID-19-Dashboard) - This dynamic dashboard was built using Indigo.Design and Ignite UI for Angular leveraging timely reports data from CSSEGISandData/COVID-19 to create an useful and impactful visualization. Built in a matter of hours, it showcases the Ignite UI Category and Data Charts, Map and List components for Angular and the how easy it is to get those quickly configured and populated with data.
220220

221-
-[Inventory Management App](https://github.com/IgniteUI/InventoryManagementApp) - The Inventory Management App consists of 2 pages: The Products Page and the Dashboard Page. The Products Page contains a grid with product information and includes a number of useful features
221+
- [Inventory Management App](https://github.com/IgniteUI/InventoryManagementApp) - The Inventory Management App consists of 2 pages: The Products Page and the Dashboard Page. The Products Page contains a grid with product information and includes a number of useful features
222222

223223
### Angular apps with ASP.NET Core Web Application
224224
If you consider Angular client side application with ASP.NET Core application you can check out our [ASP.NET-Core-Samples](https://github.com/IgniteUI/ASP.NET-Core-Samples)

projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-component.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,10 @@
587587
@extend %igx-grid__tr-pivot-group !optional
588588
}
589589

590+
@include e(tr-header-row) {
591+
@extend %igx-grid__tr-header-row !optional;
592+
}
593+
590594
@include e(tr-pivot-toggle-icons) {
591595
@extend %igx-grid__tr-pivot-toggle-icons !optional;
592596
}

projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3003,6 +3003,14 @@
30033003
%igx-grid__tr-pivot-toggle-icons {
30043004
display: inline-flex !important;
30053005
}
3006+
3007+
%igx-grid__tr-header-row {
3008+
igx-pivot-row-dimension-header-group {
3009+
igx-pivot-row-dimension-header {
3010+
align-items: center;
3011+
}
3012+
}
3013+
}
30063014
// Pivot grid END
30073015
}
30083016

projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,10 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
414414

415415
if (this.igxForScrollOrientation === 'vertical') {
416416
this.dc.instance._viewContainer.element.nativeElement.style.top = '0px';
417-
this.scrollComponent = vc.createComponent(VirtualHelperComponent).instance;
417+
this.scrollComponent = this.syncScrollService.getScrollMaster(this.igxForScrollOrientation);
418+
if (!this.scrollComponent || !this.document.contains(this.scrollComponent.elementRef.nativeElement)) {
419+
this.scrollComponent = vc.createComponent(VirtualHelperComponent).instance
420+
}
418421
this._maxHeight = this._calcMaxBrowserHeight();
419422
this.scrollComponent.size = this.igxForOf ? this._calcHeight() : 0;
420423
this.syncScrollService.setScrollMaster(this.igxForScrollOrientation, this.scrollComponent);
@@ -721,6 +724,34 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
721724
return scroll;
722725
}
723726

727+
/**
728+
* Returns the index of the element at the specified offset.
729+
* ```typescript
730+
* this.parentVirtDir.getIndexAtScroll(100);
731+
* ```
732+
*/
733+
public getIndexAtScroll(scrollOffset: number) {
734+
return this.getIndexAt(scrollOffset, this.sizesCache);
735+
}
736+
/**
737+
* Returns whether the target index is outside the view.
738+
* ```typescript
739+
* this.parentVirtDir.isIndexOutsideView(10);
740+
* ```
741+
*/
742+
public isIndexOutsideView(index: number) {
743+
const targetNode = index >= this.state.startIndex && index <= this.state.startIndex + this.state.chunkSize ?
744+
this._embeddedViews.map(view =>
745+
view.rootNodes.find(node => node.nodeType === Node.ELEMENT_NODE) || view.rootNodes[0].nextElementSibling)[index - this.state.startIndex] : null;
746+
const rowHeight = this.getSizeAt(index);
747+
const containerSize = parseInt(this.igxForContainerSize, 10);
748+
const containerOffset = -(this.scrollPosition - this.sizesCache[this.state.startIndex]);
749+
const endTopOffset = targetNode ? targetNode.offsetTop + rowHeight + containerOffset : containerSize + rowHeight;
750+
return !targetNode || targetNode.offsetTop < Math.abs(containerOffset)
751+
|| containerSize && endTopOffset - containerSize > 5;
752+
}
753+
754+
724755
/**
725756
* @hidden
726757
* Function that recalculates and updates cache sizes.
@@ -1115,20 +1146,16 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
11151146
protected initSizesCache(items: any[]): number {
11161147
let totalSize = 0;
11171148
let size = 0;
1118-
const dimension = this.igxForScrollOrientation === 'horizontal' ?
1119-
this.igxForSizePropName : 'height';
1149+
const dimension = this.igxForSizePropName || 'height';
11201150
let i = 0;
11211151
this.sizesCache = [];
11221152
this.heightCache = [];
11231153
this.sizesCache.push(0);
11241154
const count = this.isRemote ? this.totalItemCount : items.length;
11251155
for (i; i < count; i++) {
1126-
if (dimension === 'height') {
1127-
// cols[i][dimension] = parseInt(this.igxForItemSize, 10) || 0;
1128-
size = parseInt(this.igxForItemSize, 10) || 0;
1156+
size = this._getItemSize(items[i], dimension);
1157+
if (this.igxForScrollOrientation === 'vertical') {
11291158
this.heightCache.push(size);
1130-
} else {
1131-
size = this._getItemSize(items[i], dimension);
11321159
}
11331160
totalSize += size;
11341161
this.sizesCache.push(totalSize);
@@ -1359,6 +1386,11 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
13591386
this._virtScrollTop = realPercentScrolled * maxVirtScrollTop;
13601387
}
13611388

1389+
protected _getItemSize(item, dimension: string): number {
1390+
const dim = item ? item[dimension] : null;
1391+
return typeof dim === 'number' ? dim : parseInt(this.igxForItemSize, 10) || 0;
1392+
}
1393+
13621394
private _updateVScrollOffset() {
13631395
let scrollOffset = 0;
13641396
let currentScrollTop = this.scrollPosition;
@@ -1380,10 +1412,6 @@ export class IgxForOfDirective<T> implements OnInit, OnChanges, DoCheck, OnDestr
13801412
this.dc.instance._viewContainer.element.nativeElement.style.left = -scrollOffset + 'px';
13811413
}
13821414

1383-
private _getItemSize(item, dimension: string): number {
1384-
const dim = item[dimension];
1385-
return typeof dim === 'number' ? dim : parseInt(this.igxForItemSize, 10) || 0;
1386-
}
13871415

13881416
private _adjustScrollPositionAfterSizeChange(sizeDiff) {
13891417
// if data has been changed while container is scrolled
@@ -1436,10 +1464,14 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
14361464
* @internal
14371465
*/
14381466
public get sizesCache(): number[] {
1439-
if (this.syncService.isMaster(this)) {
1467+
if (this.igxForScrollOrientation === 'horizontal') {
1468+
if (this.syncService.isMaster(this)) {
1469+
return this._sizesCache;
1470+
}
1471+
return this.syncService.sizesCache(this.igxForScrollOrientation);
1472+
} else {
14401473
return this._sizesCache;
14411474
}
1442-
return this.syncService.sizesCache(this.igxForScrollOrientation);
14431475
}
14441476
/**
14451477
* @hidden
@@ -1450,7 +1482,7 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
14501482
}
14511483

14521484
protected get itemsDimension() {
1453-
return this.igxForScrollOrientation === 'horizontal' ? this.igxForSizePropName : 'height';
1485+
return this.igxForSizePropName || 'height';
14541486
}
14551487

14561488
/**
@@ -1578,10 +1610,9 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
15781610

15791611
protected getItemSize(item) {
15801612
let size = 0;
1581-
const dimension = this.igxForScrollOrientation === 'horizontal' ?
1582-
this.igxForSizePropName : 'height';
1583-
if (dimension === 'height') {
1584-
size = parseInt(this.igxForItemSize, 10) || 0;
1613+
const dimension = this.igxForSizePropName || 'height';
1614+
if (this.igxForScrollOrientation === 'vertical') {
1615+
size = this._getItemSize(item, dimension);
15851616
if (item && item.summaries) {
15861617
size = item.max;
15871618
} else if (item && item.groups && item.height) {
@@ -1594,7 +1625,7 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
15941625
}
15951626

15961627
protected initSizesCache(items: any[]): number {
1597-
if (!this.syncService.isMaster(this)) {
1628+
if (!this.syncService.isMaster(this) && this.igxForScrollOrientation === 'horizontal') {
15981629
const masterSizesCache = this.syncService.sizesCache(this.igxForScrollOrientation);
15991630
return masterSizesCache[masterSizesCache.length - 1];
16001631
}
@@ -1607,7 +1638,7 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
16071638
const count = this.isRemote ? this.totalItemCount : items.length;
16081639
for (i; i < count; i++) {
16091640
size = this.getItemSize(items[i]);
1610-
if (this.itemsDimension === 'height') {
1641+
if (this.igxForScrollOrientation === 'vertical') {
16111642
this.heightCache.push(size);
16121643
}
16131644
totalSize += size;
@@ -1744,10 +1775,15 @@ export class IgxGridForOfDirective<T> extends IgxForOfDirective<T> implements On
17441775
* @hidden
17451776
*/
17461777
protected _calcMaxChunkSize(): number {
1747-
if (this.syncService.isMaster(this)) {
1778+
if (this.igxForScrollOrientation === 'horizontal') {
1779+
if (this.syncService.isMaster(this)) {
1780+
return super._calcMaxChunkSize();
1781+
}
1782+
return this.syncService.chunkSize(this.igxForScrollOrientation);
1783+
} else {
17481784
return super._calcMaxChunkSize();
17491785
}
1750-
return this.syncService.chunkSize(this.igxForScrollOrientation);
1786+
17511787
}
17521788
}
17531789

projects/igniteui-angular/src/lib/directives/scroll-inertia/scroll_inertia.directive.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ export class IgxScrollInertiaDirective implements OnInit, OnDestroy {
138138
scrollDeltaY = this.calcAxisCoords(deltaScaledY, -1, 1);
139139
}
140140

141+
if (evt.composedPath && this.didChildScroll(evt, scrollDeltaX, scrollDeltaY)) {
142+
return;
143+
}
144+
141145
if (scrollDeltaX && this.IgxScrollInertiaDirection === 'horizontal') {
142146
const nextLeft = this._startX + scrollDeltaX * scrollStep;
143147
if (!smoothing) {
@@ -186,6 +190,36 @@ export class IgxScrollInertiaDirective implements OnInit, OnDestroy {
186190
}
187191
}
188192

193+
/**
194+
* @hidden
195+
* Checks if the wheel event would have scrolled an element under the display container
196+
* in DOM tree so that it can correctly be ignored until that element can no longer be scrolled.
197+
*/
198+
protected didChildScroll(evt, scrollDeltaX, scrollDeltaY): boolean {
199+
const path = evt.composedPath();
200+
let i = 0;
201+
while (i < path.length && path[i].localName !== 'igx-display-container') {
202+
const e = path[i++];
203+
if (e.scrollHeight > e.clientHeight) {
204+
if (scrollDeltaY > 0 && e.scrollHeight - Math.abs(Math.round(e.scrollTop)) !== e.clientHeight) {
205+
return true;
206+
}
207+
if (scrollDeltaY < 0 && e.scrollTop !== 0) {
208+
return true;
209+
}
210+
}
211+
if (e.scrollWidth > e.clientWidth) {
212+
if (scrollDeltaX > 0 && e.scrollWidth - Math.abs(Math.round(e.scrollLeft)) !== e.clientWidth) {
213+
return true;
214+
}
215+
if (scrollDeltaX < 0 && e.scrollLeft !== 0) {
216+
return true;
217+
}
218+
}
219+
}
220+
return false;
221+
}
222+
189223
/**
190224
* @hidden
191225
* Function that is called the first moment we start interacting with the content on a touch device

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

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1790,7 +1790,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy
17901790
*/
17911791
public getGridTemplate(isRow: boolean): string {
17921792
if (isRow) {
1793-
const rowsCount = this.grid.multiRowLayoutRowSize;
1793+
const rowsCount = !this.grid.isPivot ? this.grid.multiRowLayoutRowSize : this.children.length - 1;
17941794
return `repeat(${rowsCount},1fr)`;
17951795
} else {
17961796
return this.getColumnSizesString(this.children);
@@ -2312,23 +2312,7 @@ export class IgxColumnComponent implements AfterContentInit, OnDestroy, ColumnTy
23122312
* Returns the width and padding of a header cell.
23132313
*/
23142314
public getHeaderCellWidths() {
2315-
const range = this.grid.document.createRange();
2316-
2317-
// We do not cover cases where there are children with width 100% and etc,
2318-
// because then we try to get new column size, based on header content, which is sized based on column size...
2319-
const headerWidth = this.platform.getNodeSizeViaRange(range,
2320-
this.headerCell.nativeElement,
2321-
this.headerGroup.nativeElement);
2322-
2323-
const headerStyle = this.grid.document.defaultView.getComputedStyle(this.headerCell.nativeElement);
2324-
const headerPadding = parseFloat(headerStyle.paddingLeft) + parseFloat(headerStyle.paddingRight) +
2325-
parseFloat(headerStyle.borderRightWidth);
2326-
2327-
// Take into consideration the header group element, since column pinning applies borders to it if its not a columnGroup.
2328-
const headerGroupStyle = this.grid.document.defaultView.getComputedStyle(this.headerGroup.nativeElement);
2329-
const borderSize = !this.parent ? parseFloat(headerGroupStyle.borderRightWidth) + parseFloat(headerGroupStyle.borderLeftWidth) : 0;
2330-
2331-
return { width: Math.ceil(headerWidth), padding: Math.ceil(headerPadding + borderSize) };
2315+
return this.grid.getHeaderCellWidth(this.headerCell.nativeElement);
23322316
}
23332317

23342318
/**

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,7 @@ export interface GridType extends IGridDataBindable {
404404
hasColumnGroups: boolean;
405405
hasEditableColumns: boolean;
406406
uniqueColumnValuesStrategy: (column: ColumnType, tree: FilteringExpressionsTree, done: (values: any[]) => void) => void;
407+
getHeaderCellWidth: (element: HTMLElement) => ISizeInfo;
407408

408409
cdr: ChangeDetectorRef;
409410
document: Document;
@@ -643,3 +644,8 @@ export interface GridSVGIcon {
643644
name: string;
644645
value: string;
645646
}
647+
648+
export interface ISizeInfo {
649+
width: number,
650+
padding: number
651+
}

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

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ import {
123123
IPinColumnCancellableEventArgs
124124
} from './common/events';
125125
import { IgxAdvancedFilteringDialogComponent } from './filtering/advanced-filtering/advanced-filtering-dialog.component';
126-
import { ColumnType, GridServiceType, GridType, IGX_GRID_SERVICE_BASE, RowType } from './common/grid.interface';
126+
import { ColumnType, GridServiceType, GridType, IGX_GRID_SERVICE_BASE, ISizeInfo, RowType } from './common/grid.interface';
127127
import { DropPosition } from './moving/moving.service';
128128
import { IgxHeadSelectorDirective, IgxRowSelectorDirective } from './selection/row-selectors';
129129
import { IgxColumnComponent } from './columns/column.component';
@@ -2960,7 +2960,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
29602960
@Inject(IGX_GRID_SERVICE_BASE) public gridAPI: GridServiceType,
29612961
protected transactionFactory: IgxFlatTransactionFactory,
29622962
private elementRef: ElementRef<HTMLElement>,
2963-
private zone: NgZone,
2963+
protected zone: NgZone,
29642964
@Inject(DOCUMENT) public document: any,
29652965
public cdr: ChangeDetectorRef,
29662966
protected resolver: ComponentFactoryResolver,
@@ -3883,6 +3883,26 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
38833883
return this.width === null || diff >= 0;
38843884
}
38853885

3886+
/**
3887+
* @hidden @internal
3888+
* Gets the header cell inner width for auto-sizing.
3889+
*/
3890+
public getHeaderCellWidth(element: HTMLElement): ISizeInfo {
3891+
const range = this.document.createRange();
3892+
const headerWidth = this.platform.getNodeSizeViaRange(range,
3893+
element,
3894+
element.parentElement);
3895+
3896+
const headerStyle = this.document.defaultView.getComputedStyle(element);
3897+
const headerPadding = parseFloat(headerStyle.paddingLeft) + parseFloat(headerStyle.paddingRight) +
3898+
parseFloat(headerStyle.borderRightWidth);
3899+
3900+
// Take into consideration the header group element, since column pinning applies borders to it if its not a columnGroup.
3901+
const headerGroupStyle = this.document.defaultView.getComputedStyle(element.parentElement);
3902+
const borderSize = parseFloat(headerGroupStyle.borderRightWidth) + parseFloat(headerGroupStyle.borderLeftWidth);
3903+
return { width: Math.ceil(headerWidth), padding: Math.ceil(headerPadding + borderSize) };
3904+
}
3905+
38863906
/**
38873907
* @hidden @internal
38883908
* Gets the combined width of the columns that are specific to the enabled grid features. They are fixed.
@@ -6980,7 +7000,7 @@ export abstract class IgxGridBaseDirective extends DisplayDensityBase implements
69807000
this.cdr.markForCheck();
69817001
}
69827002

6983-
private verticalScrollHandler(event) {
7003+
protected verticalScrollHandler(event) {
69847004
this.verticalScrollContainer.onScroll(event);
69857005
this.disableTransitions = true;
69867006

0 commit comments

Comments
 (0)