diff --git a/CHANGELOG.md b/CHANGELOG.md index 232dc500cb0..8b61f3e9bd6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,13 @@ -# Ignite UI for Angular Change Log +# Ignite UI for Angular Change Log All notable changes for each version of this project will be documented in this file. +## 8.2.3 +- `IgxTextHighlightDirective` - The default highlight directive styles have been moved to a Sass theme - `igx-highlight-theme`; You can modify the resting and active background and text color styles of the directive by passing the respective properties to the Sass theme. You can still pass your own CSS classes to the highlight directive via the cssClass and activeCssClass inputs. + +- `IgxChip` + - **Breaking Change** The `originalEvent` property for the events `onMoveStart`, `onMoveEnd`, `onClick` and `onSelection` now provides the events, passed from the `igxDrag` directive. The passed original events are in other words the previous events that triggered the `igxChip` ones. They also have original events until a browser event is reached. + ## 8.2.0 ### New theme Ignite UI for angular now have a new theme that mimics Microsoft "Fluent" design system. @@ -75,6 +81,7 @@ For more information about the theming please read our [documentation](https://w - `isCellSelected` method has been deprecated. Now you can use `selected` property. - `rowSelectable` property has been deprecated. Now you can use `rowSelection` property to enable row selection and also you can show and hide the row selectors by setting `hideRowSelectors` property to true or false (which is the default value). - Removed deprecated event `OnFocusChange` + - `IgxGridBaseComponent` exposes a new property, `dataView` that returns the currently transformed paged/filtered/sorted/grouped data, displayed in the grid - **Breaking Change** `igxExcelStyleSortingTemplate` directive is renamed to `igxExcelStyleSorting`. - **Breaking Change** `igxExcelStyleMovingTemplate` directive is renamed to `igxExcelStyleMoving`. - **Breaking Change** `igxExcelStyleHidingTemplate` directive is renamed to `igxExcelStyleHiding`. diff --git a/projects/igniteui-angular/src/lib/chips/chip.component.html b/projects/igniteui-angular/src/lib/chips/chip.component.html index 17b43bf0166..639a9e26d81 100644 --- a/projects/igniteui-angular/src/lib/chips/chip.component.html +++ b/projects/igniteui-angular/src/lib/chips/chip.component.html @@ -7,7 +7,7 @@ (dragStart)="onChipDragStart($event)" (dragEnd)="onChipDragEnd()" (transitioned)="onChipMoveEnd($event)" - (click)="onChipDragClicked($event)" + (dragClick)="onChipDragClicked($event)" igxDrop (enter)="onChipDragEnterHandler($event)" (dropped)="onChipDrop($event)"> diff --git a/projects/igniteui-angular/src/lib/chips/chip.component.ts b/projects/igniteui-angular/src/lib/chips/chip.component.ts index 887ec6daf62..25584835772 100644 --- a/projects/igniteui-angular/src/lib/chips/chip.component.ts +++ b/projects/igniteui-angular/src/lib/chips/chip.component.ts @@ -24,7 +24,7 @@ import { IBaseEventArgs } from '../core/utils'; export interface IBaseChipEventArgs extends IBaseEventArgs { - originalEvent: PointerEvent | MouseEvent | TouchEvent | KeyboardEvent | IDropBaseEventArgs; + originalEvent: IDragBaseEventArgs | IDropBaseEventArgs | KeyboardEvent | MouseEvent | TouchEvent; owner: IgxChipComponent; } @@ -557,7 +557,7 @@ export class IgxChipComponent extends DisplayDensityBase { // Start chip igxDrag behavior public onChipDragStart(event: IDragStartEventArgs) { this.onMoveStart.emit({ - originalEvent: event.originalEvent, + originalEvent: event, owner: this }); event.cancel = !this.draggable || this.disabled; @@ -578,7 +578,7 @@ export class IgxChipComponent extends DisplayDensityBase { public onChipMoveEnd(event: IDragBaseEventArgs) { // moveEnd is triggered after return animation has finished. This happen when we drag and release the chip. this.onMoveEnd.emit({ - originalEvent: event.originalEvent, + originalEvent: event, owner: this }); @@ -592,14 +592,14 @@ export class IgxChipComponent extends DisplayDensityBase { */ public onChipDragClicked(event: IDragBaseEventArgs) { const clickEventArgs: IChipClickEventArgs = { - originalEvent: event.originalEvent, + originalEvent: event, owner: this, cancel: false }; this.onClick.emit(clickEventArgs); if (!clickEventArgs.cancel && this.selectable && !this.disabled) { - this.changeSelection(!this.selected, event.originalEvent); + this.changeSelection(!this.selected, event); } } // End chip igxDrag behavior diff --git a/projects/igniteui-angular/src/lib/chips/chip.spec.ts b/projects/igniteui-angular/src/lib/chips/chip.spec.ts index 365d60af69e..4f1e0977bac 100644 --- a/projects/igniteui-angular/src/lib/chips/chip.spec.ts +++ b/projects/igniteui-angular/src/lib/chips/chip.spec.ts @@ -415,9 +415,19 @@ describe('IgxChip', () => { fix.detectChanges(); expect(secondChipComp.onSelection.emit).toHaveBeenCalled(); expect(secondChipComp.onSelectionDone.emit).not.toHaveBeenCalled(); + expect(secondChipComp.onSelection.emit).not.toHaveBeenCalledWith({ + originalEvent: null, + owner: secondChipComp, + cancel: false, + selected: true + }); await wait(400); expect(secondChipComp.onSelectionDone.emit).toHaveBeenCalled(); + expect(secondChipComp.onSelectionDone.emit).not.toHaveBeenCalledWith({ + originalEvent: null, + owner: secondChipComp + }); })); it('should not fire onSelection event when selectable is false', () => { diff --git a/projects/igniteui-angular/src/lib/chips/chips-area.component.ts b/projects/igniteui-angular/src/lib/chips/chips-area.component.ts index d7efddae3cd..b15fc34bb91 100644 --- a/projects/igniteui-angular/src/lib/chips/chips-area.component.ts +++ b/projects/igniteui-angular/src/lib/chips/chips-area.component.ts @@ -21,12 +21,12 @@ import { IChipEnterDragAreaEventArgs, IBaseChipEventArgs } from './chip.component'; -import { IDropBaseEventArgs } from '../directives/drag-drop/drag-drop.directive'; +import { IDropBaseEventArgs, IDragBaseEventArgs } from '../directives/drag-drop/drag-drop.directive'; import { takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; export interface IBaseChipsAreaEventArgs { - originalEvent: PointerEvent | MouseEvent | TouchEvent | KeyboardEvent | IDropBaseEventArgs; + originalEvent: IDragBaseEventArgs | IDropBaseEventArgs | KeyboardEvent | MouseEvent | TouchEvent; owner: IgxChipsAreaComponent; } @@ -152,7 +152,6 @@ export class IgxChipsAreaComponent implements DoCheck, AfterViewInit, OnDestroy private modifiedChipsArray: IgxChipComponent[]; private _differ: IterableDiffer | null = null; - private selectedChips: IgxChipComponent[] = []; protected destroy$ = new Subject(); constructor(public cdr: ChangeDetectorRef, public element: ElementRef, @@ -166,11 +165,11 @@ export class IgxChipsAreaComponent implements DoCheck, AfterViewInit, OnDestroy public ngAfterViewInit() { // If we have initially selected chips through their inputs, we need to get them, because we cannot listen to their events yet. if (this.chipsList.length) { - this.selectedChips = this.chipsList.filter((item: IgxChipComponent) => item.selected); - if (this.selectedChips.length) { + const selectedChips = this.chipsList.filter((item: IgxChipComponent) => item.selected); + if (selectedChips.length) { this.onSelection.emit({ originalEvent: null, - newSelection: this.selectedChips, + newSelection: selectedChips, owner: this }); } @@ -324,16 +323,17 @@ export class IgxChipsAreaComponent implements DoCheck, AfterViewInit, OnDestroy * @hidden */ protected onChipSelectionChange(event: IChipSelectEventArgs) { - if (event.selected) { - this.selectedChips.push(event.owner); - } else if (!event.selected) { - this.selectedChips = this.selectedChips.filter((chip) => { + let selectedChips = this.chipsList.filter((chip) => chip.selected); + if (event.selected && !selectedChips.includes(event.owner)) { + selectedChips.push(event.owner); + } else if (!event.selected && selectedChips.includes(event.owner)) { + selectedChips = selectedChips.filter((chip) => { return chip.id !== event.owner.id; }); } this.onSelection.emit({ originalEvent: event.originalEvent, - newSelection: this.selectedChips, + newSelection: selectedChips, owner: this }); } diff --git a/projects/igniteui-angular/src/lib/chips/chips-area.spec.ts b/projects/igniteui-angular/src/lib/chips/chips-area.spec.ts index 54529b6f8ec..13b8818d046 100644 --- a/projects/igniteui-angular/src/lib/chips/chips-area.spec.ts +++ b/projects/igniteui-angular/src/lib/chips/chips-area.spec.ts @@ -386,7 +386,8 @@ describe('IgxChipsArea', () => { const firstChipComp = fix.componentInstance.chips.toArray()[1]; spyOn(firstChipComp.onClick, 'emit'); - firstChipComp.chipArea.nativeElement.click(); + firstChipComp.chipArea.nativeElement.dispatchEvent(new PointerEvent('pointerdown', { pointerId: 1})); + firstChipComp.chipArea.nativeElement.dispatchEvent(new PointerEvent('pointerup')); fix.detectChanges(); expect(firstChipComp.onClick.emit).toHaveBeenCalled(); @@ -857,26 +858,22 @@ describe('IgxChipsArea', () => { const chipAreaComp = fix.componentInstance.chipsArea; const secondChipComp = fix.componentInstance.chips.toArray()[1]; + const pointerDownEvt = new PointerEvent('pointerdown', { pointerId: 1 }); + const pointerUpEvt = new PointerEvent('pointerup', { pointerId: 1 }); spyOn(chipAreaComp.onSelection, 'emit'); fix.detectChanges(); - secondChipComp.chipArea.nativeElement.click(); + secondChipComp.chipArea.nativeElement.dispatchEvent(pointerDownEvt); fix.detectChanges(); - - expect(chipAreaComp.onSelection.emit).toHaveBeenCalledWith({ - originalEvent: null, - owner: chipAreaComp, - newSelection: [secondChipComp] - }); - - secondChipComp.chipArea.nativeElement.click(); + secondChipComp.chipArea.nativeElement.dispatchEvent(pointerUpEvt); fix.detectChanges(); - expect(chipAreaComp.onSelection.emit).toHaveBeenCalledWith({ + expect(chipAreaComp.onSelection.emit).toHaveBeenCalled(); + expect(chipAreaComp.onSelection.emit).not.toHaveBeenCalledWith({ originalEvent: null, owner: chipAreaComp, - newSelection: [] + newSelection: [secondChipComp] }); }); @@ -889,8 +886,6 @@ describe('IgxChipsArea', () => { fix.detectChanges(); const secondChipComp = fix.componentInstance.chips.toArray(); - - expect(chipAreaComp['selectedChips']).toEqual([secondChipComp[0], secondChipComp[1]]); expect(chipAreaComp.onSelection.emit).toHaveBeenCalledWith({ originalEvent: null, owner: chipAreaComp, diff --git a/projects/igniteui-angular/src/lib/combo/combo.component.html b/projects/igniteui-angular/src/lib/combo/combo.component.html index 6584ac0695d..3643e909e0f 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.component.html +++ b/projects/igniteui-angular/src/lib/combo/combo.component.html @@ -24,7 +24,7 @@ - @@ -47,7 +47,7 @@ diff --git a/projects/igniteui-angular/src/lib/combo/combo.component.ts b/projects/igniteui-angular/src/lib/combo/combo.component.ts index 5297e6e1a8b..65372dc2fda 100644 --- a/projects/igniteui-angular/src/lib/combo/combo.component.ts +++ b/projects/igniteui-angular/src/lib/combo/combo.component.ts @@ -670,7 +670,7 @@ export class IgxComboComponent extends DisplayDensityBase implements IgxComboBas * ``` */ @Input() - public placeholder = ''; + public placeholder; /** * @hidden @internal diff --git a/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-component.scss index f27ca101f83..9abb087f1be 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-component.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-component.scss @@ -23,8 +23,7 @@ @extend %igx-chip__item--hover !optional; } - &:focus, - &:focus-within { + &:focus { @extend %igx-chip__item--focus !optional; } } diff --git a/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-theme.scss index b546b1b2240..b45639fda32 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/chip/_chip-theme.scss @@ -402,9 +402,20 @@ display: none; } - &:focus-within { + // FIX IE11 and Edge focus styles. + // [focus-within] is not supported by IE & Edge. + &:focus { outline-style: none; - color: igx-color(map-get($theme, 'palette'), error); + + igx-icon { + color: igx-color(map-get($theme, 'palette'), error); + } + } + + igx-icon { + &:focus{ + outline-style: none; + } } [dir='rtl'] & { diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss index e557ca93588..bd6f54b6888 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid-toolbar/_grid-toolbar-theme.scss @@ -168,38 +168,11 @@ height: map-get($grid-toolbar-height, 'comfortable'); %igx-button--flat { - background: --var($theme, 'button-background'); - color: --var($theme, 'button-text-color'); margin-left: rem(8); - - &:hover { - background: --var($theme, 'button-hover-background'); - color: --var($theme, 'button-hover-text-color'); - } - - &:focus, - &:active { - background: --var($theme, 'button-focus-background'); - color: --var($theme, 'button-focus-text-color'); - } } %igx-button--icon { - background: --var($theme, 'button-background'); - color: --var($theme, 'button-text-color'); margin-left: rem(8); - border-radius: 0; - - &:hover { - background: --var($theme, 'button-hover-background'); - color: --var($theme, 'button-hover-text-color'); - } - - &:focus, - &:active { - background: --var($theme, 'button-focus-background'); - color: --var($theme, 'button-focus-text-color'); - } } %igx-grid-toolbar__button-space { diff --git a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss index 599d0b49936..971e7e0c32a 100644 --- a/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/src/lib/core/styles/components/grid/_grid-theme.scss @@ -1189,6 +1189,7 @@ %grid-cell-text { font-style: italic; color: --var($theme, 'cell-edited-value-color'); + padding: 0 1px; } } diff --git a/projects/igniteui-angular/src/lib/core/styles/components/highlight/highlight-component.scss b/projects/igniteui-angular/src/lib/core/styles/components/highlight/highlight-component.scss new file mode 100644 index 00000000000..21c3552dc5a --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/components/highlight/highlight-component.scss @@ -0,0 +1,20 @@ +//// +/// @group components +/// @author Simeon Simeonoff +/// @requires {mixin} bem-block +/// @requires {mixin} bem-elem +/// @requires {mixin} bem-mod +//// +@include b(igx-highlight) { + // Register the component in the component registry + $this: bem--selector-to-string(&); + @include register-component(str-slice($this, 2, -1)); + + @extend %igx-highlight !optional; + + @include m(active) { + @extend %igx-highlight !optional; + @extend %igx-highlight--active !optional; + } +} + diff --git a/projects/igniteui-angular/src/lib/core/styles/components/highlight/highlight-theme.scss b/projects/igniteui-angular/src/lib/core/styles/components/highlight/highlight-theme.scss new file mode 100644 index 00000000000..89a8adfb9c5 --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/components/highlight/highlight-theme.scss @@ -0,0 +1,70 @@ +//// +/// @group themes +/// @access public +/// @author Simeon Simeonoff +//// + +/// If only background color(s) specified, text color(s) will be assigned automatically to a contrasting color. +/// @param {Map} $palette [$default-palette] - The palette used as basis for styling the component. +/// @param {Map} $schema [$light-schema] - The schema used as basis for styling the component. +/// @param {Color} $resting-background [null]- The background color used for the highlight in its resting state. +/// @param {Color} $resting-color [null] - The text color used for the highlight in its resting state. +/// @param {Color} $active-background [null] - The background color used for the highlight in its active state. +/// @param {Color} $active-color [null] - The text color used for the highlight in its active state. +/// @requires $default-palette +/// @requires $light-schema +/// @requires apply-palette +/// @requires text-contrast +/// @requires extend +/// +/// @example scss Change the background and icon colors in icon highlight +/// $my-avatar-theme: igx-avatar-theme($icon-background: black, $icon-color: white); +/// // Pass the theme to the igx-avatar component mixin +/// @include igx-avatar($my-avatar-theme); +@function igx-highlight-theme( + $palette: $default-palette, + $schema: $light-schema, + $resting-background: null, + $resting-color: null, + $active-background: null, + $active-color: null, +) { + $name: 'igx-highlight'; + $theme: apply-palette(map-get($schema, $name), $palette); + + @if not($resting-color) and $resting-background { + $resting-color: text-contrast($resting-background); + } + + @if not($active-color) and $active-background { + $active-color: text-contrast($active-background); + } + + @return extend($theme, ( + name: $name, + palette: $palette, + resting-background: $resting-background, + resting-color: $resting-color, + active-background: $active-background, + active-color: $active-color, + )); +} + +/// @param {Map} $theme - The theme used to style the component. +/// @requires {mixin} igx-root-css-vars +/// @requires rem +/// @requires --var +@mixin igx-highlight($theme) { + @include igx-root-css-vars($theme); + + %igx-highlight { + color: --var($theme, 'resting-color'); + background: --var($theme, 'resting-background'); + } + + %igx-highlight--active { + color: --var($theme, 'active-color'); + background: --var($theme, 'active-background'); + } +} + diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss index 5b48aabcbf0..bf61d59d43a 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/_core.scss @@ -42,6 +42,7 @@ @import '../components/grid-summary/grid-summary-component'; @import '../components/grid-paginator/grid-paginator-component'; @import '../components/grid-toolbar/grid-toolbar-component'; +@import '../components/highlight/highlight-component'; @import '../components/icon/icon-component'; @import '../components/input/input-group-component'; @import '../components/list/list-component'; diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss index c38ac6926fc..3eb9f776c84 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/_index.scss @@ -29,6 +29,7 @@ @import '../components/grid-summary/grid-summary-theme'; @import '../components/grid-paginator/grid-paginator-theme'; @import '../components/grid-toolbar/grid-toolbar-theme'; +@import '../components/highlight/highlight-theme'; @import '../components/overlay/overlay-theme'; @import '../components/toast/toast-theme'; @import '../components/tooltip/tooltip-theme'; @@ -278,6 +279,10 @@ @include igx-grid-toolbar(igx-grid-toolbar-theme($palette, $schema)); } + @if not(index($exclude, 'igx-highlight')) { + @include igx-highlight(igx-highlight-theme($palette, $schema)); + } + @if not(index($exclude, 'igx-icon')) { @include igx-icon(igx-icon-theme($palette, $schema)); } diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_grid.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_grid.scss index baef7724404..3b336e03c23 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_grid.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_grid.scss @@ -13,6 +13,7 @@ /// @prop {Color} row-even-background [#222] - The background color of even rows. /// @prop {Map} row-hover-background [igx-color: ('grays', 100), hexrgba: #222] - The hover row background color. /// @prop {Map} row-selected-background [igx-color: ('secondary', 500), rgba: .24, hexrgba: #222] - The selected row background color. +/// @prop {Map} row-selected-hover-background [igx-color: ('secondary', 'A700'), rgba: .24, hexrgba: #222] - The selected row background color on hover. /// @prop {Color} row-selected-text-color [#fff] - The selected row text color. /// @prop {Color} ghost-header-background [#222] - The dragged header background color. /// @prop {Color} cell-editing-background [#222] - The background for the cell in editing mode. @@ -52,6 +53,12 @@ $_base-dark-grid: ( hexrgba: #222 ), + row-selected-hover-background: ( + igx-color: ('secondary', 'A700'), + rgba: .24, + hexrgba: #222 + ), + row-selected-text-color: #fff, ghost-header-background: #222, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_highlight.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_highlight.scss new file mode 100644 index 00000000000..4eae2ce3c2f --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_highlight.scss @@ -0,0 +1,20 @@ +@import '../light/highlight'; +//// +/// @group schemas +/// @access private +/// @author Simeon Simeonoff +//// + +/// Generates a dark highlight schema. +/// @type {Map} +/// @requires {function} extend +/// @requires $_light-highlight +/// @see $default-palette +$_dark-highlight: extend($_light-highlight); + +/// Generates a dark fluent highlight schema. +/// @type {Map} +/// @requires {function} extend +/// @requires $_fluent-highlight +$_dark-fluent-highlight: extend($_fluent-highlight); + diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss index c1838937e46..863fefe3c15 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/dark/_index.scss @@ -25,6 +25,7 @@ @import './grid-pagination'; @import './grid-summary'; @import './grid-toolbar'; +@import './highlight'; @import './icon'; @import './input-group'; @import './list'; @@ -66,6 +67,7 @@ /// @property {Map} igx-grid-paginator [$_dark-grid-pagination] /// @property {Map} igx-grid-summary [$_dark-grid-summary] /// @property {Map} igx-grid-toolbar [$_dark-grid-toolbar] +/// @property {Map} igx-highlight [$_dark-highlight] /// @property {Map} igx-icon [$_dark-icon] /// @property {Map} igx-input-group [$_dark-input-group] /// @property {Map} igx-list [$_dark-list] @@ -106,6 +108,7 @@ $dark-schema: ( igx-grid-paginator: $_dark-grid-pagination, igx-grid-summary: $_dark-grid-summary, igx-grid-toolbar: $_dark-grid-toolbar, + igx-highlight: $_dark-highlight, igx-icon: $_dark-icon, igx-input-group: $_dark-input-group, igx-list: $_dark-list, @@ -149,6 +152,7 @@ $dark-schema: ( /// @property {map} igx-grid-paginator: [$_dark-fluent-grid-pagination], /// @property {map} igx-grid-summary: [$_dark-fluent-grid-summary], /// @property {map} igx-grid-toolbar: [$_dark-fluent-grid-toolbar], +/// @property {map} igx-highlight: [$_dark-fluent-highlight], /// @property {map} igx-icon: [$_dark-fluent-icon], /// @property {map} igx-input-group: [$_dark-fluent-input-group], /// @property {map} igx-list: [$_dark-fluent-list], @@ -189,6 +193,7 @@ $dark-fluent-schema: ( igx-grid-paginator: $_dark-fluent-grid-pagination, igx-grid-summary: $_dark-fluent-grid-summary, igx-grid-toolbar: $_dark-fluent-grid-toolbar, + igx-highlight: $_dark-fluent-highlight, igx-icon: $_dark-fluent-icon, igx-input-group: $_dark-fluent-input-group, igx-list: $_dark-fluent-list, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss index 039642195c5..3e225c45bb0 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_grid.scss @@ -27,9 +27,9 @@ /// @prop {Color} row-even-background [#fff] - The background color of even rows. /// @prop {Color} row-odd-text-color [inherit] - The text color of odd rows. /// @prop {Color} row-even-text-color [inherit] - The text color of even rows. -/// @prop {Map} row-selected-background [igx-color: ('secondary', 50), hexrgba: #fff] - The selected row background color. +/// @prop {Map} row-selected-background [igx-color: ('secondary', 50)] - The selected row background color. /// @prop {Map} row-selected-text-color [igx-contrast-color: ('secondary', 50)] - The selected row text color. -/// @prop {Map} row-selected-hover-background [igx-color: ('secondary', 50), hexrgba: #fff] - The selected row hover background. +/// @prop {Map} row-selected-hover-background [igx-color: ('secondary', 50)] - The selected row hover background. /// @prop {Map} row-hover-background [igx-color: ('grays', 100), hexrgba: #fff] - The hover row background color. /// @prop {Map} row-hover-text-color [igx-contrast-color: ('grays', 200)] - The hover row text color. /// @prop {Map} row-border-color [igx-color: ('grays', 300)] - The row bottom border color. @@ -132,12 +132,10 @@ $_light-grid: extend( row-selected-background: ( igx-color: ('secondary', 50), - hexrgba: #fff ), row-selected-hover-background: ( igx-color: ('secondary', 50), - hexrgba: #fff ), row-selected-text-color: ( @@ -334,7 +332,7 @@ $_light-grid: extend( /// @prop {Map} row-selected-hover-background [igx-color: ('grays', 200), hexrgba: #fff] - The selected row hover background. /// @prop {Map} row-border-color [igx-color: ('grays', 100)] - The row bottom border color. /// @prop {Map} pinned-border-color [igx-color: ('grays', 200)] - The color of the pinned border. -/// @prop {Map} cell-active-border-color [igx-color: ('primary', 100), hexrgba: #fff] - The active(focused) cell border color. +/// @prop {Map} cell-active-border-color [igx-color: ('primary', 100)] - The active(focused) cell border color. /// @prop {Map} cell-selected-background [igx-color: ('grays', 300), hexrgba: #fff] - The selected cell background color. /// @prop {Map} grouparea-background [igx-color: 'surface'] - The grid group area background color. /// @prop {Map} group-row-background [igx-color: ('grays', 50), hexrgba: #fff] - The grid group row background color. @@ -385,7 +383,6 @@ $_fluent-grid: extend( cell-active-border-color: ( igx-color: ('primary', 100), - hexrgba: #fff ), cell-selected-background: ( diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_highlight.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_highlight.scss new file mode 100644 index 00000000000..836323e482c --- /dev/null +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_highlight.scss @@ -0,0 +1,39 @@ +//// +/// @group schemas +/// @access private +/// @author Simeon Simeonoff +//// + +/// Generates a light highlight schema. +/// @type {Map} +/// @property {Map} resting-background [igx-color: ('secondary', 400)] - The background color used for the highlight in its resting state. +/// @property {Map} resting-color [igx-color: ('secondary', 400), text-contrast: ()] - The icon color used for the highlight in its resting state. +/// @property {Map} active-background [igx-color: ('secondary', 600)] - The background color used for the highlight in its active state. +/// @property {Map} active-color [igx-color: ('secondary', 400), text-contrast: ()] - The text color used for the highlight in its active state. +/// @see $default-palette +$_light-highlight: ( + resting-background: ( + igx-color: ('secondary', 50) + ), + + resting-color: ( + igx-color: ('secondary', 50), + text-contrast: () + ), + + active-background: ( + igx-color: ('secondary', 200) + ), + + active-color: ( + igx-color: ('secondary', 200), + text-contrast: () + ), +); + +/// Generates a fluent highlight schema. +/// @type {Map} +/// @requires {function} extend +/// @requires $_light-highlight +$_fluent-highlight: extend($_light-highlight); + diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss index c6dee81a4d2..ce6dd1bd7c9 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/light/_index.scss @@ -26,6 +26,7 @@ @import './grid-pagination'; @import './grid-summary'; @import './grid-toolbar'; +@import './highlight'; @import './icon'; @import './input-group'; @import './list'; @@ -67,6 +68,7 @@ /// @property {Map} igx-grid-paginator [$_light-grid-pagination] /// @property {Map} igx-grid-summary [$_light-grid-summary] /// @property {Map} igx-grid-toolbar [$_light-grid-toolbar] +/// @property {Map} igx-highlight [$_light-highlight] /// @property {Map} igx-icon [$_light-icon] /// @property {Map} igx-input-group [$_light-input-group] /// @property {Map} igx-list [$_light-list] @@ -110,6 +112,7 @@ $light-schema: ( igx-grid-paginator: $_light-grid-pagination, igx-grid-summary: $_light-grid-summary, igx-grid-toolbar: $_light-grid-toolbar, + igx-highlight: $_light-highlight, igx-icon: $_light-icon, igx-input-group: $_light-input-group, igx-list: $_light-list, @@ -153,6 +156,7 @@ $light-fluent-schema: ( igx-grid-paginator: $_fluent-grid-pagination, igx-grid-summary: $_fluent-grid-summary, igx-grid-toolbar: $_fluent-grid-toolbar, + igx-highlight: $_fluent-highlight, igx-icon: $_fluent-icon, igx-input-group: $_fluent-input-group, igx-list: $_fluent-list, diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss index 5c8417e25d9..a6b35ca91eb 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/round-light/_index.scss @@ -26,6 +26,7 @@ @import '../light/grid-pagination'; @import '../light/grid-summary'; @import '../light/grid-toolbar'; +@import '../light/highlight'; @import '../light/icon'; @import '../light/input-group'; @import '../light/list'; @@ -67,6 +68,7 @@ /// @property {Map} igx-grid-paginator [$_light-grid-pagination] /// @property {Map} igx-grid-summary [$_light-grid-summary] /// @property {Map} igx-grid-toolbar [$_light-grid-toolbar] +/// @property {Map} igx-highlight [$_light-highlight] /// @property {Map} igx-icon [$_light-icon] /// @property {Map} igx-input-group [$_light-input-group] /// @property {Map} igx-list [$_light-list] @@ -108,6 +110,7 @@ $light-round-schema: ( igx-grid-paginator: extend($_light-grid-pagination, $_round-shape-grid-pagination), igx-grid-summary: extend($_light-grid-summary, $_round-shape-grid-summary), igx-grid-toolbar: extend($_light-grid-toolbar, $_round-shape-tooltip), + igx-highlight: $_light-highlight, igx-icon: extend($_light-icon, $_round-shape-icon), igx-input-group: extend($_light-input-group, $_round-shape-input-group), igx-list: extend($_light-list, $_round-shape-list), diff --git a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss index ba885ee310c..779b6581809 100644 --- a/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss +++ b/projects/igniteui-angular/src/lib/core/styles/themes/schemas/square-light/_index.scss @@ -26,6 +26,7 @@ @import '../light/grid-pagination'; @import '../light/grid-summary'; @import '../light/grid-toolbar'; +@import '../light/highlight'; @import '../light/icon'; @import '../light/input-group'; @import '../light/list'; @@ -67,6 +68,7 @@ /// @property {Map} igx-grid-paginator [$_light-grid-pagination] /// @property {Map} igx-grid-summary [$_light-grid-summary] /// @property {Map} igx-grid-toolbar [$_light-grid-toolbar] +/// @property {Map} igx-highlight [$_light-highlight] /// @property {Map} igx-icon [$_light-icon] /// @property {Map} igx-input-group [$_light-input-group] /// @property {Map} igx-list [$_light-list] @@ -108,6 +110,7 @@ $light-square-schema: ( igx-grid-paginator: extend($_light-grid-pagination, $_square-shape-grid-pagination), igx-grid-summary: extend($_light-grid-summary, $_square-shape-grid-summary), igx-grid-toolbar: extend($_light-grid-toolbar, $_square-shape-tooltip), + igx-highlight: $_light-highlight, igx-icon: extend($_light-icon, $_square-shape-icon), igx-input-group: extend($_light-input-group, $_square-shape-input-group), igx-list: extend($_light-list, $_square-shape-list), diff --git a/projects/igniteui-angular/src/lib/core/touch.ts b/projects/igniteui-angular/src/lib/core/touch.ts index daf8640a082..65580066f9e 100644 --- a/projects/igniteui-angular/src/lib/core/touch.ts +++ b/projects/igniteui-angular/src/lib/core/touch.ts @@ -1,6 +1,7 @@ import { Inject, Injectable, NgZone } from '@angular/core'; import { ɵgetDOM as getDOM } from '@angular/platform-browser'; import { DOCUMENT } from '@angular/common'; +import { PlatformUtil } from './utils'; const EVENT_SUFFIX = 'precise'; @@ -11,26 +12,31 @@ const EVENT_SUFFIX = 'precise'; */ @Injectable() export class HammerGesturesManager { + private platformBrowser: boolean; /** * Event option defaults for each recognizer, see http://hammerjs.github.io/api/ for API listing. */ - protected hammerOptions: HammerOptions = { - // D.P. #447 Force TouchInput due to PointerEventInput bug (https://github.com/hammerjs/hammer.js/issues/1065) - // see https://github.com/IgniteUI/igniteui-angular/issues/447#issuecomment-324601803 - inputClass: Hammer.TouchInput, - recognizers: [ - [ Hammer.Pan, { threshold: 0 } ], - [ Hammer.Swipe, { - direction: Hammer.DIRECTION_HORIZONTAL - }], - [Hammer.Tap], - [Hammer.Tap, { event: 'doubletap', taps: 2 }, ['tap']] - ] - }; + protected hammerOptions: HammerOptions = {}; private _hammerManagers: Array<{ element: EventTarget, manager: HammerManager; }> = []; - constructor(private _zone: NgZone, @Inject(DOCUMENT) private doc: any) { + constructor(private _zone: NgZone, @Inject(DOCUMENT) private doc: any, private platformUtil: PlatformUtil) { + this.platformBrowser = this.platformUtil.isBrowser; + if (this.platformBrowser) { + this.hammerOptions = { + // D.P. #447 Force TouchInput due to PointerEventInput bug (https://github.com/hammerjs/hammer.js/issues/1065) + // see https://github.com/IgniteUI/igniteui-angular/issues/447#issuecomment-324601803 + inputClass: Hammer.TouchInput, + recognizers: [ + [Hammer.Pan, { threshold: 0 }], + [Hammer.Swipe, { + direction: Hammer.DIRECTION_HORIZONTAL + }], + [Hammer.Tap], + [Hammer.Tap, { event: 'doubletap', taps: 2 }, ['tap']] + ] + }; + } } public supports(eventName: string): boolean { @@ -41,10 +47,14 @@ export class HammerGesturesManager { * Add listener extended with options for Hammer.js. Will use defaults if none are provided. * Modeling after other event plugins for easy future modifications. */ - public addEventListener(element: HTMLElement, - eventName: string, - eventHandler: (eventObj) => void, - options: HammerOptions = null): () => void { + public addEventListener( + element: HTMLElement, + eventName: string, + eventHandler: (eventObj) => void, + options: HammerOptions = null): () => void { + if (!this.platformBrowser) { + return; + } // Creating the manager bind events, must be done outside of angular return this._zone.runOutsideAngular(() => { @@ -67,6 +77,10 @@ export class HammerGesturesManager { * @param target Can be one of either window, body or document(fallback default). */ public addGlobalEventListener(target: string, eventName: string, eventHandler: (eventObj) => void): () => void { + if (!this.platformBrowser) { + return; + } + const element = this.getGlobalEventTarget(target); // Creating the manager bind events, must be done outside of angular diff --git a/projects/igniteui-angular/src/lib/core/utils.ts b/projects/igniteui-angular/src/lib/core/utils.ts index 3c2369b2ae8..1d4a72f24ea 100644 --- a/projects/igniteui-angular/src/lib/core/utils.ts +++ b/projects/igniteui-angular/src/lib/core/utils.ts @@ -1,3 +1,6 @@ +import { Injectable, PLATFORM_ID, Inject } from '@angular/core'; +import { isPlatformBrowser } from '@angular/common'; + /** *@hidden */ @@ -228,12 +231,14 @@ export function isFirefox(): boolean { /** * @hidden - * TODO: make injectable, check isPlatformBrowser() */ +@Injectable({ providedIn: 'root' }) export class PlatformUtil { - static isIOS(): boolean { - const iosBrowser = typeof window !== 'undefined' && /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window); - return iosBrowser; + public isBrowser: boolean = isPlatformBrowser(this.platformId); + + public isIOS = this.isBrowser && /iPad|iPhone|iPod/.test(navigator.userAgent) && !('MSStream' in window); + + constructor(@Inject(PLATFORM_ID) private platformId: Object) { } } @@ -246,8 +251,21 @@ export function isLeftClick(event: PointerEvent) { /** @hidden */ export function isNavigationKey(key: string): boolean { - return ['down', 'up', 'left', 'right', 'arrowdown', 'arrowup', 'arrowleft', 'arrowright', - 'home', 'end', 'space', 'spacebar', ' '].indexOf(key) !== -1; + return [ + 'down', + 'up', + 'left', + 'right', + 'arrowdown', + 'arrowup', + 'arrowleft', + 'arrowright', + 'home', + 'end', + 'space', + 'spacebar', + ' ' + ].indexOf(key) !== -1; } /** @@ -285,8 +303,21 @@ export interface CancelableBrowserEventArgs extends CancelableEventArgs { event?: Event; } -export const NAVIGATION_KEYS = new Set(['down', 'up', 'left', 'right', 'arrowdown', 'arrowup', 'arrowleft', 'arrowright', - 'home', 'end', 'space', 'spacebar', ' ']); +export const NAVIGATION_KEYS = new Set([ + 'down', + 'up', + 'left', + 'right', + 'arrowdown', + 'arrowup', + 'arrowleft', + 'arrowright', + 'home', + 'end', + 'space', + 'spacebar', + ' ' +]); export const ROW_EXPAND_KEYS = new Set('right down arrowright arrowdown'.split(' ')); export const ROW_COLLAPSE_KEYS = new Set('left up arrowleft arrowup'.split(' ')); export const SUPPORTED_KEYS = new Set([...Array.from(NAVIGATION_KEYS), 'tab', 'enter', 'f2', 'escape', 'esc']); diff --git a/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts b/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts index 0c54471268b..a670da82696 100644 --- a/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/drag-drop/drag-drop.directive.ts @@ -1043,7 +1043,9 @@ export class IgxDragDirective implements AfterContentInit, OnDestroy { } } else { // Trigger our own click event because when there is no ghost, native click cannot be prevented when dragging. - this.dragClick.emit(eventArgs); + this.zone.run(() => { + this.dragClick.emit(eventArgs); + }); } } diff --git a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.spec.ts b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.spec.ts index 421fd5e245b..2429a8ef82a 100644 --- a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.spec.ts @@ -24,7 +24,6 @@ import { take } from 'rxjs/operators'; import { UIInteractions, wait } from '../../test-utils/ui-interactions.spec'; import { configureTestSuite } from '../../test-utils/configure-suite'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; describe('IgxForOf directive -', () => { const INACTIVE_VIRT_CONTAINER = 'igx-display-container--inactive'; @@ -294,7 +293,6 @@ describe('IgxForOf directive -', () => { }); it('should always fill available space for last chunk size calculation - vertical virtualization', async () => { - resizeObserverIgnoreError(); fix.componentInstance.height = '1900px'; const virtualContainer = fix.componentInstance.parentVirtDir; virtualContainer.igxForSizePropName = 'height'; diff --git a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts index ff8d3d62f24..a8c48bb0516 100644 --- a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.spec.ts @@ -288,21 +288,6 @@ describe('IgxHighlight', () => { const activeSpans = fix.debugElement.nativeElement.querySelectorAll('.' + component.activeHighlightClass); expect(spans.length).toBe(4); expect(activeSpans.length).toBe(1); - - const activeSpan = activeSpans[0]; - const activeStyle = getComputedStyle(activeSpan); - expect(activeStyle.background.indexOf('rgb(255, 165, 0)')).toBe(0); - expect(activeStyle.color).toBe('rgb(0, 0, 0)'); - expect(activeStyle.fontWeight).toBe('400'); - - for (const span of spans) { - if (span !== activeSpan) { - const style = getComputedStyle(span); - expect(style.background.indexOf('rgb(255, 255, 0)')).toBe(0); - expect(style.color).toBe('rgb(0, 0, 0)'); - expect(style.fontWeight).toBe('400'); - } - } }); }); diff --git a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts index cbca1ab7dd9..73a42652984 100644 --- a/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/text-highlight/text-highlight.directive.ts @@ -9,7 +9,7 @@ import { OnDestroy, Renderer2, SimpleChanges, - AfterViewChecked + AfterViewChecked, } from '@angular/core'; import { takeUntil } from 'rxjs/operators'; import { Subject } from 'rxjs'; @@ -67,6 +67,8 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke private _forceEvaluation = false; private _activeElementIndex = -1; private _valueChanged: boolean; + private _defaultCssClass = 'igx-highlight'; + private _defaultActiveCssClass = 'igx-highlight--active'; /** * Determines the `CSS` class of the highlight elements. @@ -391,8 +393,8 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke } const elementToActivate = spans[index]; + this.renderer.addClass(elementToActivate, this._defaultActiveCssClass); this.renderer.addClass(elementToActivate, this.activeCssClass); - this.renderer.setAttribute(elementToActivate, 'style', 'background:orange;color:black'); } } @@ -409,8 +411,8 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke } const elementToDeactivate = spans[this._activeElementIndex]; + this.renderer.removeClass(elementToDeactivate, this._defaultActiveCssClass); this.renderer.removeClass(elementToDeactivate, this.activeCssClass); - this.renderer.setAttribute(elementToDeactivate, 'style', 'background:yellow;color:black'); this._activeElementIndex = -1; } @@ -437,7 +439,7 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke if (exactMatch) { if (contentStringResolved === searchTextResolved) { // tslint:disable-next-line:max-line-length - this.appendSpan(`${stringValue}`); + this.appendSpan(`${stringValue}`); matchCount++; } else { this.appendText(stringValue); @@ -452,7 +454,7 @@ export class IgxTextHighlightDirective implements AfterViewInit, AfterViewChecke this.appendText(stringValue.substring(previousMatchEnd, start)); // tslint:disable-next-line:max-line-length - this.appendSpan(`${stringValue.substring(start, end)}`); + this.appendSpan(`${stringValue.substring(start, end)}`); previousMatchEnd = end; matchCount++; diff --git a/projects/igniteui-angular/src/lib/grids/cell.component.ts b/projects/igniteui-angular/src/lib/grids/cell.component.ts index 733a08248fb..7d6318ae664 100644 --- a/projects/igniteui-angular/src/lib/grids/cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/cell.component.ts @@ -558,7 +558,8 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy { public cdr: ChangeDetectorRef, private element: ElementRef, protected zone: NgZone, - private touchManager: HammerGesturesManager) { } + private touchManager: HammerGesturesManager, + protected platformUtil: PlatformUtil) { } private addPointerListeners(selection) { if (selection !== GridSelectionMode.multiple) { return; } @@ -590,7 +591,7 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy { this.nativeElement.addEventListener('compositionend', this.compositionEndHandler); } }); - if (PlatformUtil.isIOS()) { + if (this.platformUtil.isIOS) { this.touchManager.addEventListener(this.nativeElement, 'doubletap', this.onDoubleClick, { cssProps: { } /* don't disable user-select, etc */ } as HammerOptions); diff --git a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts index 6bae484aec3..ba18c9a1ceb 100644 --- a/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts +++ b/projects/igniteui-angular/src/lib/grids/common/grid.interface.ts @@ -1,6 +1,7 @@ import { FilterMode } from './enums'; export interface GridType { + id: string; nativeElement: HTMLElement; rowEditable: boolean; rootSummariesEnabled: boolean; @@ -24,6 +25,7 @@ export interface GridType { pinnedColumns: any; summariesRowList: any; headerContainer: any; + dataView: any[]; rowInEditMode: any; rowEditTabs: any; diff --git a/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.ts index 02e788ce7d6..63d65cda585 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/advanced-filtering/advanced-filtering-dialog.component.ts @@ -254,7 +254,7 @@ export class IgxAdvancedFilteringDialogComponent implements AfterViewInit, OnDes } get filterableColumns(): IgxColumnComponent[] { - return this.grid.columns.filter((col) => col.filterable); + return this.grid.columns.filter((col) => !col.columnGroup && col.filterable); } public dragStart(dragArgs: IDragStartEventArgs) { diff --git a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts index cbc146a7c32..957f32d45b4 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-base.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-base.component.ts @@ -890,7 +890,10 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements this._isLoading = value; this.evaluateLoadingState(); } - this.notifyChanges(); + Promise.resolve().then(() => { + // wait for the current detection cycle to end before triggering a new one. + this.notifyChanges(); + }); } /** @@ -4630,8 +4633,8 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements public hasVerticalSroll() { if (this._init) { return false; } const isScrollable = this.verticalScrollContainer ? this.verticalScrollContainer.isScrollable() : false; - return !!(this.calcWidth && this.verticalScrollContainer.igxForOf && - this.verticalScrollContainer.igxForOf.length > 0 && + return !!(this.calcWidth && this.dataView && + this.dataView.length > 0 && isScrollable); } @@ -4997,6 +5000,17 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements return 0; } + /** + * Returns the currently transformed paged/filtered/sorted/grouped data, displayed in the grid. + * ```typescript + * const dataView = this.grid.dataView; + * ``` + * @memberof IgxGridComponent + */ + get dataView(): any[] { + return this.verticalScrollContainer.igxForOf; + } + /** * Get current selection state. * Returns an array with selected rows' IDs (primaryKey or rowData) @@ -5215,7 +5229,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements * If `headers` is enabled, it will use the column header (if any) instead of the column field. */ getSelectedData(formatters = false, headers = false) { - const source = this.verticalScrollContainer.igxForOf; + const source = this.dataView; return this.extractDataFromSelection(source, formatters, headers); } @@ -5284,12 +5298,12 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements * @memberof IgxGridBaseComponent */ public navigateTo(rowIndex: number, visibleColIndex = -1, cb: Function = null) { - if (rowIndex < 0 || rowIndex > this.verticalScrollContainer.igxForOf.length - 1 + if (rowIndex < 0 || rowIndex > this.dataView.length - 1 || (visibleColIndex !== -1 && this.columnList.map(col => col.visibleIndex).indexOf(visibleColIndex) === -1)) { return; } this.wheelHandler(); - if (this.verticalScrollContainer.igxForOf.slice(rowIndex, rowIndex + 1).find(rec => rec.expression || rec.childGridsData)) { + if (this.dataView.slice(rowIndex, rowIndex + 1).find(rec => rec.expression || rec.childGridsData)) { visibleColIndex = -1; } if (visibleColIndex === -1 || this.navigation.isColumnFullyVisible(visibleColIndex)) { @@ -5325,7 +5339,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements const colIndexes = callback ? columns.filter((col) => callback(col)).map(editCol => editCol.visibleIndex).sort((a, b) => a - b) : columns.map(editCol => editCol.visibleIndex).sort((a, b) => a - b); const nextCellIndex = colIndexes.find(index => index > curVisibleColIndex); - if (this.verticalScrollContainer.igxForOf.slice(currRowIndex, currRowIndex + 1) + if (this.dataView.slice(currRowIndex, currRowIndex + 1) .find(rec => !rec.expression && !rec.summaries && !rec.childGridsData) && nextCellIndex !== undefined) { return { rowIndex: currRowIndex, visibleColumnIndex: nextCellIndex }; } else { @@ -5357,7 +5371,7 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements const colIndexes = callback ? columns.filter((col) => callback(col)).map(editCol => editCol.visibleIndex).sort((a, b) => b - a) : columns.map(editCol => editCol.visibleIndex).sort((a, b) => b - a); const prevCellIndex = colIndexes.find(index => index < curVisibleColIndex); - if (this.verticalScrollContainer.igxForOf.slice(currRowIndex, currRowIndex + 1) + if (this.dataView.slice(currRowIndex, currRowIndex + 1) .find(rec => !rec.expression && !rec.summaries && !rec.childGridsData) && prevCellIndex !== undefined) { return { rowIndex: currRowIndex, visibleColumnIndex: prevCellIndex }; } else { @@ -5400,24 +5414,24 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements private getPrevDataRowIndex(currentRowIndex): number { if (currentRowIndex <= 0) { return currentRowIndex; } - const prevRow = this.verticalScrollContainer.igxForOf.slice(0, currentRowIndex).reverse() + const prevRow = this.dataView.slice(0, currentRowIndex).reverse() .find(rec => !rec.expression && !rec.summaries && !rec.childGridsData); - return prevRow ? this.verticalScrollContainer.igxForOf.indexOf(prevRow) : currentRowIndex; + return prevRow ? this.dataView.indexOf(prevRow) : currentRowIndex; } private getNextDataRowIndex(currentRowIndex): number { - if (currentRowIndex === this.verticalScrollContainer.igxForOf.length) { return currentRowIndex; } + if (currentRowIndex === this.dataView.length) { return currentRowIndex; } - const nextRow = this.verticalScrollContainer.igxForOf.slice(currentRowIndex + 1, this.verticalScrollContainer.igxForOf.length) + const nextRow = this.dataView.slice(currentRowIndex + 1, this.dataView.length) .find(rec => !rec.expression && !rec.summaries && !rec.childGridsData); - return nextRow ? this.verticalScrollContainer.igxForOf.indexOf(nextRow) : currentRowIndex; + return nextRow ? this.dataView.indexOf(nextRow) : currentRowIndex; } private isValidPosition(rowIndex, colIndex): boolean { const rows = this.summariesRowList.filter(s => s.index !== 0).concat(this.rowList.toArray()).length; const cols = this.columnList.filter(col => !col.columnGroup && col.visibleIndex >= 0).length; if (rows < 1 || cols < 1) { return false; } - if (rowIndex > -1 && rowIndex < this.verticalScrollContainer.igxForOf.length && + if (rowIndex > -1 && rowIndex < this.dataView.length && colIndex > - 1 && colIndex <= this.unpinnedColumns[this.unpinnedColumns.length - 1].visibleIndex) { return true; } @@ -5614,11 +5628,11 @@ export abstract class IgxGridBaseComponent extends DisplayDensityBase implements if (delayScrolling) { this.verticalScrollContainer.onDataChanged.pipe(first()).subscribe(() => { this.scrollDirective(this.verticalScrollContainer, - typeof (row) === 'number' ? row : this.verticalScrollContainer.igxForOf.indexOf(row)); + typeof (row) === 'number' ? row : this.dataView.indexOf(row)); }); } else { this.scrollDirective(this.verticalScrollContainer, - typeof (row) === 'number' ? row : this.verticalScrollContainer.igxForOf.indexOf(row)); + typeof (row) === 'number' ? row : this.dataView.indexOf(row)); } this.scrollToHorizontally(column); diff --git a/projects/igniteui-angular/src/lib/grids/grid-mrl-navigation.service.ts b/projects/igniteui-angular/src/lib/grids/grid-mrl-navigation.service.ts index 3eff15e7133..dac709b9091 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-mrl-navigation.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-mrl-navigation.service.ts @@ -249,7 +249,7 @@ export class IgxGridMRLNavigationService extends IgxGridNavigationService { moveNext = true; } const rowIndex = moveNext ? selectedNode.row + 1 : selectedNode.row; - if (rowIndex > this.grid.verticalScrollContainer.igxForOf.length - 1) { + if (rowIndex > this.grid.dataView.length - 1) { // end of rows reached. return; } @@ -469,7 +469,7 @@ export class IgxGridMRLNavigationService extends IgxGridNavigationService { } private _isGroupRecordAt(rowIndex: number) { - const record = this.grid.verticalScrollContainer.igxForOf[rowIndex]; + const record = this.grid.dataView[rowIndex]; return record.records && record.records.length; } diff --git a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts index abaaeede32f..5d3ee042462 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-navigation.service.ts @@ -22,7 +22,7 @@ export class IgxGridNavigationService { } get displayContainerScrollLeft() { - return Math.round(this.grid.parentVirtDir.getHorizontalScroll().scrollLeft); + return Math.ceil(this.grid.parentVirtDir.getHorizontalScroll().scrollLeft); } get verticalDisplayContainerElement() { @@ -267,7 +267,7 @@ export class IgxGridNavigationService { (cells[cells.length - 1] as HTMLElement).focus(); } else { this.getFocusableGrid().nativeElement.focus({ preventScroll: true }); - this.grid.verticalScrollContainer.scrollTo(this.grid.verticalScrollContainer.igxForOf.length - 1); + this.grid.verticalScrollContainer.scrollTo(this.grid.dataView.length - 1); this.grid.verticalScrollContainer.onChunkLoad .pipe(first()).subscribe(() => { const cells = this.grid.nativeElement.querySelectorAll( @@ -315,7 +315,7 @@ export class IgxGridNavigationService { public navigateDown(rowElement, selectedNode: ISelectionNode) { const currentRowIndex = selectedNode.row; const visibleColumnIndex = selectedNode.column; - if (currentRowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1 || + if (currentRowIndex === this.grid.dataView.length - 1 || (currentRowIndex === 0 && rowElement.tagName.toLowerCase() === 'igx-grid-summary-row')) { // check if this is rootSummary row return; @@ -389,7 +389,7 @@ export class IgxGridNavigationService { this.onKeydownEnd(rowIndex); } else { this.getFocusableGrid().nativeElement.focus({ preventScroll: true }); - this.grid.verticalScrollContainer.scrollTo(this.grid.verticalScrollContainer.igxForOf.length - 1); + this.grid.verticalScrollContainer.scrollTo(this.grid.dataView.length - 1); this.grid.verticalScrollContainer.onChunkLoad .pipe(first()).subscribe(() => { const rows = this.getAllRows(); @@ -405,7 +405,7 @@ export class IgxGridNavigationService { const verticalScroll = this.grid.verticalScrollContainer.getVerticalScroll(); if (verticalScroll.scrollHeight === 0 || verticalScroll.scrollTop === verticalScroll.scrollHeight - this.grid.verticalScrollContainer.igxForContainerSize) { - const rowIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const rowIndex = this.grid.dataView.length - 1; const row = this.grid.nativeElement.querySelector(`[data-rowindex="${rowIndex}"]`) as HTMLElement; if (row && row.tagName.toLowerCase() === 'igx-grid-groupby-row') { row.focus(); @@ -414,10 +414,10 @@ export class IgxGridNavigationService { const isSummary = (row && row.tagName.toLowerCase() === 'igx-grid-summary-row') ? true : false; this.onKeydownEnd(rowIndex, isSummary); } else { - this.grid.verticalScrollContainer.scrollTo(this.grid.verticalScrollContainer.igxForOf.length - 1); + this.grid.verticalScrollContainer.scrollTo(this.grid.dataView.length - 1); this.grid.verticalScrollContainer.onChunkLoad .pipe(first()).subscribe(() => { - const rowIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const rowIndex = this.grid.dataView.length - 1; const row = this.grid.nativeElement.querySelector(`[data-rowindex="${rowIndex}"]`) as HTMLElement; if (row && row.tagName.toLowerCase() === 'igx-grid-groupby-row') { row.focus(); @@ -447,7 +447,7 @@ export class IgxGridNavigationService { const rowEl = this.grid.rowList.find(row => row.index === rowIndex + 1) ? this.grid.rowList.find(row => row.index === rowIndex + 1) : this.grid.summariesRowList.find(row => row.index === rowIndex + 1); - if (rowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1 && this.grid.rootSummariesEnabled) { + if (rowIndex === this.grid.dataView.length - 1 && this.grid.rootSummariesEnabled) { this.onKeydownHome(0, true); return; } @@ -628,7 +628,7 @@ export class IgxGridNavigationService { protected getNextRowByIndex(nextIndex) { return this.grid.tbody.nativeElement.querySelector( - `[data-rowindex="${nextIndex}"]`); + `[data-rowindex="${nextIndex}"][data-gridid="${this.grid.id}"]`); } private getAllRows() { diff --git a/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts index 1e425e0890a..ecbfc912386 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/cell.spec.ts @@ -182,19 +182,26 @@ describe('IgxGrid - Cell component #grid', () => { it('Should not attach doubletap handler for non-iOS', () => { const addListenerSpy = spyOn(HammerGesturesManager.prototype, 'addEventListener'); - spyOn(PlatformUtil, 'isIOS').and.returnValue(false); + const platformUtil: PlatformUtil = TestBed.get(PlatformUtil); + const oldIsIOS = platformUtil.isIOS; + platformUtil.isIOS = false; const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); + // spyOnProperty(PlatformUtil.prototype, 'isIOS').and.returnValue(false); + expect(addListenerSpy).not.toHaveBeenCalled(); + + platformUtil.isIOS = oldIsIOS; }); it('Should handle doubletap on iOS, trigger onDoubleClick event', () => { const addListenerSpy = spyOn(HammerGesturesManager.prototype, 'addEventListener'); - spyOn(PlatformUtil, 'isIOS').and.returnValue(true); + const platformUtil: PlatformUtil = TestBed.get(PlatformUtil); + const oldIsIOS = platformUtil.isIOS; + platformUtil.isIOS = true; const fix = TestBed.createComponent(DefaultGridComponent); fix.detectChanges(); const grid = fix.componentInstance.instance; - const cellElem = fix.debugElement.query(By.css(CELL_CSS_CLASS)); const firstCell = grid.getCellByColumn(0, 'index'); // should attach 'doubletap' @@ -217,6 +224,8 @@ describe('IgxGrid - Cell component #grid', () => { expect(event.preventDefault).toHaveBeenCalled(); expect(grid.onDoubleClick.emit).toHaveBeenCalledWith(args); expect(firstCell).toBe(fix.componentInstance.clickedCell); + + platformUtil.isIOS = oldIsIOS; }); it('Should blur selected cell when scrolling with mouse wheel', (async () => { diff --git a/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts index 3bfcb69f9c9..ce8832c1037 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/column-resizing.spec.ts @@ -13,7 +13,6 @@ import { SampleTestData } from '../../test-utils/sample-test-data.spec'; import { IColumnResized } from '../../test-utils/grid-interfaces.spec'; import { MultiColumnHeadersComponent } from '../../test-utils/grid-samples.spec'; import { configureTestSuite } from '../../test-utils/configure-suite'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; describe('IgxGrid - Deferred Column Resizing #grid', () => { configureTestSuite(); @@ -192,8 +191,6 @@ describe('IgxGrid - Deferred Column Resizing #grid', () => { const fixture = TestBed.createComponent(ResizableColumnsComponent); fixture.detectChanges(); - resizeObserverIgnoreError(); - const grid = fixture.componentInstance.grid; const column = grid.getColumnByName('ID'); const headers: DebugElement[] = fixture.debugElement.queryAll(By.css(COLUMN_HEADER_CLASS)); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-cell-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-cell-selection.spec.ts index 28ca55b6fb9..94f9429a891 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-cell-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-cell-selection.spec.ts @@ -10,7 +10,7 @@ import { SelectionWithScrollsComponent, import { SortingDirection } from '../../data-operations/sorting-expression.interface'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { UIInteractions, wait } from '../../test-utils/ui-interactions.spec'; -import { setupGridScrollDetection, resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; +import { setupGridScrollDetection } from '../../test-utils/helper-utils.spec'; import { DefaultSortingStrategy } from 'igniteui-angular'; import { GridSelectionMode } from '../common/enums'; @@ -293,7 +293,7 @@ describe('IgxGrid - Cell selection #grid', () => { GridSelectionFunctions.verifyCellSelected(firstCell); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); @@ -514,7 +514,7 @@ describe('IgxGrid - Cell selection #grid', () => { expect(selectionChangeSpy).toHaveBeenCalledTimes(0); expect(grid.getSelectedData()).toEqual(expectedData); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); @@ -538,7 +538,7 @@ describe('IgxGrid - Cell selection #grid', () => { expect(selectionChangeSpy).toHaveBeenCalledTimes(0); expect(grid.getSelectedData()).toEqual(expectedData); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); @@ -1040,7 +1040,7 @@ describe('IgxGrid - Cell selection #grid', () => { GridSelectionFunctions.verifyCellsRegionSelected(grid, 0, 0, 0, 0); GridSelectionFunctions.verifySelectedRange(grid, 0, 0, 0, 0); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); @@ -1616,7 +1616,6 @@ describe('IgxGrid - Cell selection #grid', () => { let detect; beforeEach(fakeAsync(/** height/width setter rAF */() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(SelectionWithScrollsComponent); fix.detectChanges(); grid = fix.componentInstance.grid; diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts index 14bdf57eb43..2c37244b697 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-advanced.spec.ts @@ -13,9 +13,9 @@ import { changei18n, getCurrentResourceStrings } from '../../core/i18n/resources import { FilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; import { FilteringLogic } from '../../data-operations/filtering-expression.interface'; import { + IgxGridAdvancedFilteringColumnGroupComponent, IgxGridAdvancedFilteringComponent } from '../../test-utils/grid-samples.spec'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; const ADVANCED_FILTERING_OPERATOR_LINE_AND_CSS_CLASS = 'igx-filter-tree__line--and'; const ADVANCED_FILTERING_OPERATOR_LINE_OR_CSS_CLASS = 'igx-filter-tree__line--or'; @@ -27,6 +27,7 @@ describe('IgxGrid - Advanced Filtering', () => { beforeEach(async(() => { TestBed.configureTestingModule({ declarations: [ + IgxGridAdvancedFilteringColumnGroupComponent, IgxGridAdvancedFilteringComponent ], imports: [ @@ -42,7 +43,6 @@ describe('IgxGrid - Advanced Filtering', () => { describe('', () => { let fix, grid: IgxGridComponent; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridAdvancedFilteringComponent); grid = fix.componentInstance.grid; fix.detectChanges(); @@ -2662,6 +2662,34 @@ describe('IgxGrid - Advanced Filtering', () => { })); }); }); + + describe('', () => { + let fix, grid: IgxGridComponent; + beforeEach(fakeAsync(() => { + fix = TestBed.createComponent(IgxGridAdvancedFilteringColumnGroupComponent); + grid = fix.componentInstance.grid; + fix.detectChanges(); + })); + + it('Should not display column groups in advanced filtering dialog.', fakeAsync(() => { + // Open dialog through API. + grid.openAdvancedFilteringDialog(); + fix.detectChanges(); + + // Click the initial 'Add And Group' button. + const addAndGroupButton = GridFunctions.getAdvancedFilteringInitialAddGroupButtons(fix)[0]; + addAndGroupButton.click(); + tick(100); + fix.detectChanges(); + + // Open column dropdown and verify that there are no column groups present. + GridFunctions.clickAdvancedFilteringColumnSelect(fix); + fix.detectChanges(); + const dropdownValues = GridFunctions.getAdvancedFilteringSelectDropdownItems(fix).map((x: any) => x.innerText); + const expectedValues = ['ID', 'ProductName', 'Downloads', 'Released', 'ReleaseDate', 'Another Field']; + expect(expectedValues).toEqual(dropdownValues); + })); + }); }); @@ -2854,8 +2882,6 @@ function verifyContextMenuType(fix, shouldBeContextualGroup: boolean) { function verifyEqualArrays(firstArr: any[], secondArr: any[]) { expect(firstArr.length).toEqual(secondArr.length, 'Array lengths mismatch.'); - firstArr = firstArr.sort(); - secondArr = secondArr.sort(); // Verify sorted arrays have equal respective elements. const len = firstArr.length; for (let index = 0; index < len; index++) { diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts index 87fbe4e5421..3462baba806 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-filtering-ui.spec.ts @@ -43,7 +43,7 @@ import { IgxGridFilteringESFLoadOnDemandComponent, CustomFilteringStrategyComponent } from '../../test-utils/grid-samples.spec'; -import { HelperUtils, resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; +import { HelperUtils } from '../../test-utils/helper-utils.spec'; import { GridSelectionMode, FilterMode } from '../common/enums'; const FILTER_UI_ROW = 'igx-grid-filtering-row'; @@ -68,7 +68,6 @@ describe('IgxGrid - Filtering actions #grid', () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridFilteringComponent); fix.detectChanges(); @@ -1693,7 +1692,6 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridFilteringComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -3415,7 +3413,6 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridFilteringMCHComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -3531,7 +3528,6 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridFilteringScrollComponent); grid = fix.componentInstance.grid; fix.detectChanges(); @@ -3564,7 +3560,6 @@ describe('IgxGrid - Filtering Row UI actions #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridFilteringTemplateComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -3621,7 +3616,6 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxGridFilteringComponent); grid = fix.componentInstance.grid; grid.filterMode = FilterMode.excelStyleFilter; @@ -5688,7 +5682,7 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); + fix = TestBed.createComponent(IgxGridFilteringESFTemplatesComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -5731,7 +5725,6 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => { describe(null, () => { let fix, grid; beforeEach(fakeAsync(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxTestExcelFilteringDatePickerComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -5851,7 +5844,6 @@ describe('IgxGrid - Filtering actions - Excel style filtering #grid', () => { let grid; beforeEach(async(() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(CustomFilteringStrategyComponent); grid = fix.componentInstance.grid; fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts index df5082eef47..d5326063aee 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-keyBoardNav.spec.ts @@ -981,7 +981,7 @@ describe('IgxGrid - Keyboard navigation #grid', () => { }); fix.detectChanges(); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); @@ -1009,7 +1009,7 @@ describe('IgxGrid - Keyboard navigation #grid', () => { }); fix.detectChanges(); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts index 362e715bd4d..b0f8114673d 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid-summary.spec.ts @@ -209,7 +209,6 @@ describe('IgxGrid - Summaries #grid', () => { })); it('should render correct data after hiding one bigger and then one smaller summary when scrolled to the bottom', (async () => { - resizeObserverIgnoreError(); const fixture = TestBed.createComponent(VirtualSummaryColumnComponent); fixture.detectChanges(); await wait(100); @@ -292,7 +291,6 @@ describe('IgxGrid - Summaries #grid', () => { let fix; let grid: IgxGridComponent; beforeEach(fakeAsync(/** height/width setter rAF */() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(SummaryColumnComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -1163,7 +1161,6 @@ describe('IgxGrid - Summaries #grid', () => { let fix; let grid; beforeEach(fakeAsync(/** height/width setter rAF */() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(SummariesGroupByTransactionsComponent); fix.detectChanges(); grid = fix.componentInstance.grid; @@ -1389,7 +1386,7 @@ describe('IgxGrid - Summaries #grid', () => { }); fix.detectChanges(); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(100); fix.detectChanges(); @@ -1455,7 +1452,7 @@ describe('IgxGrid - Summaries #grid', () => { ['Count', 'Earliest', 'Latest'], ['9', 'Dec 18, 2007', 'Dec 9, 2017']); GridSummaryFunctions.verifyColumnSummaries(summaryRow, 4, ['Min', 'Max'], ['19', '50']); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(50); fix.detectChanges(); @@ -1485,7 +1482,7 @@ describe('IgxGrid - Summaries #grid', () => { GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 0, 4, ['Min', 'Max'], ['19', '50']); GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 0, 5, ['Count'], ['9']); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(50); fix.detectChanges(); GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 18, 5, ['Count'], ['1']); @@ -1548,7 +1545,7 @@ describe('IgxGrid - Summaries #grid', () => { GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 0, 2, ['Count'], ['8']); GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 0, 4, ['Min', 'Max'], ['19', '50']); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(50); fix.detectChanges(); @@ -1617,7 +1614,7 @@ describe('IgxGrid - Summaries #grid', () => { GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 4, 2, ['Count'], ['3']); GridSummaryFunctions.verifyColumnSummariesBySummaryRowIndex(fix, 4, 4, ['Min', 'Max'], ['19', '50']); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(50); fix.detectChanges(); @@ -1757,7 +1754,7 @@ describe('IgxGrid - Summaries #grid', () => { expect(groupRows[0].groupRow.value).toEqual(-1); expect(groupRows[1].groupRow.value).toEqual(19); - grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); + grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); await wait(50); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts index f59827372f0..35b585ad7d3 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.spec.ts @@ -1016,7 +1016,6 @@ describe('IgxGrid Component Tests #grid', () => { it(`should render 10 records if height is 100% and parent container's height is unset and display density is changed`, async () => { - resizeObserverIgnoreError(); const fix = TestBed.createComponent(IgxGridWrappedInContComponent); fix.detectChanges(); @@ -1593,8 +1592,6 @@ describe('IgxGrid Component Tests #grid', () => { }); it('IgxTabs: should initialize a grid with correct width/height', async () => { - resizeObserverIgnoreError(); - const grid = fix.componentInstance.grid3; const tab = fix.componentInstance.tabs; expect(grid.calcHeight).toBe(510); diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts index 09a3d625277..d4b59ef209a 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.component.ts @@ -592,6 +592,9 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB * @memberof IgxGridComponent */ public groupBy(expression: IGroupingExpression | Array): void { + if (this.checkIfNoColumnField(expression)) { + return; + } this.endEdit(true); if (expression instanceof Array) { this._gridAPI.groupBy_multiple(expression); @@ -979,7 +982,7 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB }; - this.verticalScrollContainer.igxForOf.forEach(process); + this.dataView.forEach(process); return this.extractDataFromSelection(source, formatters, headers); } else { return super.getSelectedData(formatters, headers); @@ -992,4 +995,17 @@ export class IgxGridComponent extends IgxGridBaseComponent implements IGridDataB this.navigation.grid = this; } } + + private checkIfNoColumnField(expression: IGroupingExpression | Array | any): boolean { + if (expression instanceof Array) { + for (const singleExpression of expression) { + if (!singleExpression.fieldName) { + return true; + } + } + return false; + } + return !expression.fieldName; + } + } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.directives.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.directives.ts index 3a72c9a2ed9..ef30229b9ec 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.directives.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.directives.ts @@ -78,7 +78,7 @@ export class IgxGroupAreaDropDirective extends IgxDropDirective { } const grid = column.grid; const isGrouped = grid.groupingExpressions.findIndex((item) => item.fieldName === column.field) !== -1; - if (column.groupable && !isGrouped && !column.columnGroup) { + if (column.groupable && !isGrouped && !column.columnGroup && !!column.field) { drag.icon.innerText = 'group_work'; this.hovered = true; } else { @@ -106,7 +106,7 @@ export class IgxGroupAreaDropDirective extends IgxDropDirective { } const grid = column.grid; const isGrouped = grid.groupingExpressions.findIndex((item) => item.fieldName === column.field) !== -1; - if (column.groupable && !isGrouped && !column.columnGroup) { + if (column.groupable && !isGrouped && !column.columnGroup && !!column.field) { grid.groupBy({ fieldName: column.field, dir: SortingDirection.Asc, ignoreCase: column.sortingIgnoreCase, strategy: column.sortStrategy, groupingComparer: column.groupingComparer }); } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts index 8c870292433..0fc6ab866de 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.groupby.spec.ts @@ -40,6 +40,7 @@ describe('IgxGrid - GroupBy #grid', () => { GroupableGridComponent, CustomTemplateGridComponent, GroupByDataMoreColumnsComponent, + GroupByEmptyColumnFieldComponent, MultiColumnHeadersWithGroupingComponent ], imports: [NoopAnimationsModule, IgxGridModule] @@ -715,7 +716,6 @@ describe('IgxGrid - GroupBy #grid', () => { })); it('should allow grouping of already sorted column', async(() => { - resizeObserverIgnoreError(); const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.componentInstance.enableSorting = true; @@ -905,10 +905,10 @@ describe('IgxGrid - GroupBy #grid', () => { // verify virtualization states - should be in last chunk const virtState = grid.verticalScrollContainer.state; - expect(virtState.startIndex).toBe(grid.verticalScrollContainer.igxForOf.length - virtState.chunkSize); + expect(virtState.startIndex).toBe(grid.dataView.length - virtState.chunkSize); // verify last row is visible at bottom - const lastRow = grid.getRowByIndex(grid.verticalScrollContainer.igxForOf.length - 1); + const lastRow = grid.getRowByIndex(grid.dataView.length - 1); expect(lastRow.nativeElement.getBoundingClientRect().bottom).toBe(grid.tbody.nativeElement.getBoundingClientRect().bottom); }); @@ -1407,7 +1407,6 @@ describe('IgxGrid - GroupBy #grid', () => { })); it('should update horizontal virtualization state correcly when data row views are re-used from cache.', async () => { - resizeObserverIgnoreError(); const fix = TestBed.createComponent(GroupableGridComponent); const grid = fix.componentInstance.instance; fix.detectChanges(); @@ -1688,11 +1687,15 @@ describe('IgxGrid - GroupBy #grid', () => { expect(chips[1].querySelectorAll(CHIP_REMOVE_ICON).length).toEqual(1); // check click does not allow changing sort dir - chips[0].children[0].click(); + chips[0].children[0].dispatchEvent(new PointerEvent('pointerdown', { pointerId: 1 })); + tick(); + chips[0].children[0].dispatchEvent(new PointerEvent('pointerup')); tick(); fix.detectChanges(); - chips[1].children[0].click(); + chips[1].children[0].dispatchEvent(new PointerEvent('pointerdown', { pointerId: 1 })); + tick(); + chips[1].children[0].dispatchEvent(new PointerEvent('pointerup')); tick(); fix.detectChanges(); @@ -1834,7 +1837,6 @@ describe('IgxGrid - GroupBy #grid', () => { })); it('should reorder groups when reordering chip', async () => { - resizeObserverIgnoreError(); const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; fix.detectChanges(); @@ -2026,6 +2028,19 @@ describe('IgxGrid - GroupBy #grid', () => { expect(m).toBe('Maximum amount of grouped columns is 10.'); })); + it('should not allow grouping by column with no name', fakeAsync(() => { + const fix = TestBed.createComponent(GroupByEmptyColumnFieldComponent); + const grid = fix.componentInstance.instance; + fix.detectChanges(); + tick(); + const expr = grid.columns.map(val => { + return { fieldName: val.field, dir: SortingDirection.Asc, ignoreCase: true }; + }); + grid.groupBy(expr); + tick(); + expect(grid.groupsRowList.toArray().length).toBe(0); + })); + it('should display column header text in the grouping chip.', fakeAsync(() => { const fix = TestBed.createComponent(DefaultGridComponent); const grid = fix.componentInstance.instance; @@ -2741,5 +2756,25 @@ export class GroupByDataMoreColumnsComponent extends DataParent { public instance: IgxGridComponent; } +@Component({ + template: ` + + + + + + + + ` +}) +export class GroupByEmptyColumnFieldComponent extends DataParent { + public width = '200px'; + @ViewChild(IgxGridComponent, { read: IgxGridComponent, static: true }) + public instance: IgxGridComponent; +} + export class CustomSortingStrategy extends DefaultSortingStrategy { } diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.pagination.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.pagination.spec.ts index 9916f6c03fb..4fa54a3a0a9 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.pagination.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.pagination.spec.ts @@ -1,7 +1,12 @@ import { async, TestBed, fakeAsync, tick, ComponentFixture } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { IgxGridModule } from './index'; -import { ReorderedColumnsComponent, PagingAndEditingComponent, GridIDNameJobTitleComponent } from '../../test-utils/grid-samples.spec'; +import { + ReorderedColumnsComponent, + PagingAndEditingComponent, + GridIDNameJobTitleComponent, + GridWithUndefinedDataComponent +} from '../../test-utils/grid-samples.spec'; import { PagingComponent } from '../../test-utils/grid-base-components.spec'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { IgxGridComponent } from './grid.component'; @@ -9,7 +14,6 @@ import { IgxGridComponent } from './grid.component'; import { configureTestSuite } from '../../test-utils/configure-suite'; import { wait } from '../../test-utils/ui-interactions.spec'; import { IgxNumberFilteringOperand } from '../../data-operations/filtering-condition'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; describe('IgxGrid - Grid Paging #grid', () => { @@ -22,7 +26,8 @@ describe('IgxGrid - Grid Paging #grid', () => { ReorderedColumnsComponent, PagingComponent, PagingAndEditingComponent, - GridIDNameJobTitleComponent + GridIDNameJobTitleComponent, + GridWithUndefinedDataComponent ], imports: [IgxGridModule, NoopAnimationsModule] }).compileComponents(); @@ -64,7 +69,7 @@ describe('IgxGrid - Grid Paging #grid', () => { verifyGridPager(fix, 3, '1', '1 of 4', [true, true, false, false]); })); - it('should paginate data API', fakeAsync (() => { + it('should paginate data API', fakeAsync(() => { const fix = TestBed.createComponent(PagingComponent); fix.detectChanges(); @@ -192,7 +197,6 @@ describe('IgxGrid - Grid Paging #grid', () => { })); it('change paging pages per page API', (async () => { - resizeObserverIgnoreError(); const fix = TestBed.createComponent(ReorderedColumnsComponent); fix.detectChanges(); @@ -283,7 +287,7 @@ describe('IgxGrid - Grid Paging #grid', () => { verifyGridPager(fix, 2, '9', '3 of 3', []); }); - it('activate/deactivate paging', fakeAsync(() => { + it('activate/deactivate paging', fakeAsync(() => { const fix = TestBed.createComponent(ReorderedColumnsComponent); const grid = fix.componentInstance.grid; fix.detectChanges(); @@ -306,7 +310,6 @@ describe('IgxGrid - Grid Paging #grid', () => { })); it('should change not leave prev page data after scorlling', (async () => { - resizeObserverIgnoreError(); const fix = TestBed.createComponent(PagingComponent); fix.componentInstance.perPage = 5; fix.componentInstance.grid.height = '300px'; @@ -465,6 +468,27 @@ describe('IgxGrid - Grid Paging #grid', () => { expect(gridElement.querySelector(PAGER_CLASS)).not.toBeNull(); })); + it('should not throw error when data is undefined', fakeAsync(() => { + let errorMessage = ''; + const fix = TestBed.createComponent(GridWithUndefinedDataComponent); + try { + fix.detectChanges(); + } catch (ex) { + errorMessage = ex.message; + } + expect(errorMessage).toBe(''); + const grid = fix.componentInstance.grid; + let paginator = grid.nativeElement.querySelector(PAGER_CLASS); + expect(paginator).toBeNull(); + expect(grid.rowList.length).toBe(0); + tick(305); + fix.detectChanges(); + + paginator = grid.nativeElement.querySelector(PAGER_CLASS); + expect(paginator).toBeDefined(); + expect(grid.rowList.length).toBe(5); + })); + function verifyGridPager(fix, rowsCount, firstCellValue, pagerText, buttonsVisibility) { const disabled = 'igx-button--disabled'; const grid = fix.componentInstance.grid; diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts index b8e96f4b0c4..f3622f4afe6 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.pipes.ts @@ -105,7 +105,7 @@ export class IgxGridPagingPipe implements PipeTransform { index: page, recordsPerPage: perPage }; - DataUtil.correctPagingState(state, collection.data.length); + DataUtil.correctPagingState(state, collection.data ? collection.data.length : 0); const result = { data: DataUtil.page(cloneArray(collection.data), state), diff --git a/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts index 90677228689..f28439576c8 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/grid.search.spec.ts @@ -12,7 +12,7 @@ import { configureTestSuite } from '../../test-utils/configure-suite'; import { wait } from '../../test-utils/ui-interactions.spec'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { DataType } from '../../data-operations/data-util'; -import { setupGridScrollDetection, resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; +import { setupGridScrollDetection } from '../../test-utils/helper-utils.spec'; describe('IgxGrid - search API #grid', () => { configureTestSuite(); @@ -834,7 +834,6 @@ describe('IgxGrid - search API #grid', () => { /* ScrollableGrid */ describe('', () => { beforeEach(async () => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(ScrollableGridSearchComponent); fix.detectChanges(); @@ -1009,7 +1008,6 @@ describe('IgxGrid - search API #grid', () => { /* GroupableGrid */ describe('', () => { beforeEach(fakeAsync(/** height/width setter rAF */() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(GroupableGridSearchComponent); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts b/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts index e8e96ecc011..6e82a309c56 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/groupby-row.component.ts @@ -83,6 +83,7 @@ export class IgxGridGroupByRowComponent { * ``` */ @Input() + @HostBinding('attr.data-gridID') public gridID: string; /** @@ -274,7 +275,7 @@ export class IgxGridGroupByRowComponent { if (shift) { this.grid.navigation.performShiftTabKey(this.nativeElement, activeNode); } else { - if (this.index === this.grid.verticalScrollContainer.igxForOf.length - 1 && this.grid.rootSummariesEnabled) { + if (this.index === this.grid.dataView.length - 1 && this.grid.rootSummariesEnabled) { this.grid.navigation.onKeydownHome(0, true); } else { const orderedColumns = this.grid.navigation.gridOrderedColumns; diff --git a/projects/igniteui-angular/src/lib/grids/grid/row-drag.directive.spec.ts b/projects/igniteui-angular/src/lib/grids/grid/row-drag.directive.spec.ts index d6cd8b9a43a..418fcd2822f 100644 --- a/projects/igniteui-angular/src/lib/grids/grid/row-drag.directive.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/grid/row-drag.directive.spec.ts @@ -21,7 +21,6 @@ import { IgxStringFilteringOperand } from '../../data-operations/filtering-condi import { IgxHierarchicalGridComponent, IgxHierarchicalGridModule, IgxRowComponent } from '../hierarchical-grid'; import { IgxRowIslandComponent } from '../hierarchical-grid/row-island.component'; import { IgxTreeGridComponent, IgxTreeGridModule } from '../tree-grid'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; import { GridSelectionMode } from '../common/enums'; @@ -70,7 +69,6 @@ describe('IgxGrid - Row Drag Tests #grid', () => { let dragRows: DebugElement[]; // configureTestSuite(); beforeEach(async(() => { - resizeObserverIgnoreError(); fixture = TestBed.createComponent(IgxGridRowDraggableComponent); grid = fixture.componentInstance.instance; dropArea = fixture.componentInstance.dropArea; @@ -404,7 +402,6 @@ describe('IgxGrid - Row Drag Tests #grid', () => { } } beforeEach(async(() => { - resizeObserverIgnoreError(); fixture = TestBed.createComponent(IgxGridFeaturesRowDragComponent); dragGrid = fixture.componentInstance.dragGrid; dropGrid = fixture.componentInstance.dropGrid; @@ -790,7 +787,6 @@ describe('IgxGrid - Row Drag Tests #grid', () => { })); it('should be able to drag row on every hiearchical level', (async () => { - resizeObserverIgnoreError(); // first level row let dragIndicatorElement: Element = dragIndicatorElements[1].nativeElement; let rowToDrag = dragGrid.getRowByIndex(0); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts index 9ad3c241591..93780f4826f 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-cell.component.ts @@ -6,6 +6,7 @@ import { IgxHierarchicalGridComponent } from './hierarchical-grid.component'; // import { IgxHierarchicalSelectionAPIService } from './selection'; import { IgxGridSelectionService, IgxGridCRUDService } from '../../core/grid-selection'; import { HammerGesturesManager } from '../../core/touch'; +import { PlatformUtil } from '../../core/utils'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -27,9 +28,10 @@ export class IgxHierarchicalGridCellComponent extends IgxGridCellComponent imple public cdr: ChangeDetectorRef, private helement: ElementRef, protected zone: NgZone, - touchManager: HammerGesturesManager + touchManager: HammerGesturesManager, + protected platformUtil: PlatformUtil ) { - super(selectionService, crudService, gridAPI, cdr, helement, zone, touchManager); + super(selectionService, crudService, gridAPI, cdr, helement, zone, touchManager, platformUtil); // this.hSelection = selection; } diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-navigation.service.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-navigation.service.ts index 4e5307a8b0a..e4c11161b76 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-navigation.service.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid-navigation.service.ts @@ -52,7 +52,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi return scrollHeight === 0 || Math.round(scrollTop + grid.verticalScrollContainer.igxForContainerSize) === scrollHeight; } private getIsChildAtIndex(index) { - return this.grid.isChildGridRecord(this.grid.verticalScrollContainer.igxForOf[index]); + return this.grid.isChildGridRecord(this.grid.dataView[index]); } public getCellElementByVisibleIndex(rowIndex, visibleColumnIndex, isSummary = false) { @@ -68,6 +68,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi } public navigateUp(rowElement, selectedNode: ISelectionNode) { + if (selectedNode.isSummaryRow) { return; } const prevElem = rowElement.previousElementSibling; const visibleColumnIndex = selectedNode.column; const currentRowIndex = selectedNode.row; @@ -103,6 +104,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi } } public navigateDown(rowElement, selectedNode: ISelectionNode) { + if (selectedNode.isSummaryRow) { return; } const nextElem = rowElement.nextElementSibling; const visibleColumnIndex = selectedNode.column; const currentRowIndex = selectedNode.row; @@ -120,11 +122,11 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi super.navigateDown(rowElement, selectedNode); } } - } else if (currentRowIndex !== this.grid.verticalScrollContainer.igxForOf.length - 1) { + } else if (currentRowIndex !== this.grid.dataView.length - 1) { // scroll next in view super.navigateDown(rowElement, selectedNode); } else if (this.grid.parent !== null && - currentRowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1) { + currentRowIndex === this.grid.dataView.length - 1) { // move to next row in sibling layout or in parent this.focusNext(visibleColumnIndex); } @@ -152,7 +154,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi public navigateBottom(visibleColumnIndex) { // handle scenario where last index is child grid // in that case focus cell in last data row - const lastIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const lastIndex = this.grid.dataView.length - 1; if (this.getIsChildAtIndex(lastIndex)) { const targetIndex = lastIndex - 1; const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(targetIndex, true); @@ -189,7 +191,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi public goToLastCell() { // handle scenario where last index is child grid // in that case focus last cell in last data row - const lastIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const lastIndex = this.grid.dataView.length - 1; if (this.getIsChildAtIndex(lastIndex)) { const targetIndex = lastIndex - 1; const scrTopPosition = this.grid.verticalScrollContainer.getScrollForIndex(targetIndex, true); @@ -269,7 +271,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi const isSummaryRow = selectedNode.isSummaryRow; const summaryRows = this.grid.summariesRowList.toArray(); const hasSummaries = summaryRows.length > 0; - const isLastDataRow = rowIndex === this.grid.verticalScrollContainer.igxForOf.length - 1; + const isLastDataRow = rowIndex === this.grid.dataView.length - 1; const nextIsDataRow = this.grid.dataRowList.find(row => row.index === rowIndex + 1); const isLastColumn = this.grid.unpinnedColumns[this.grid.unpinnedColumns.length - 1].visibleIndex === visibleColumnIndex; const isLastSummaryRow = hasSummaries && isSummaryRow; @@ -313,7 +315,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi const parentHasSummary = parent.summariesRowList.length > 0; const parentRowIndex = parseInt( this.getClosestElemByTag(currentRowEl, 'igx-child-grid-row').parentNode.getAttribute('data-rowindex'), 10); - const isLastRowInParent = parent.verticalScrollContainer.igxForOf.length - 1 === parentRowIndex; + const isLastRowInParent = parent.dataView.length - 1 === parentRowIndex; // check if next is sibling const childRowContainer = this.getChildGridRowContainer(this.grid); const nextIsSiblingChild = !!childRowContainer.nextElementSibling; @@ -404,7 +406,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi const gridElem = this.getLastGridElem(currentRowEl.previousElementSibling); this.performShiftTabIntoChild(gridElem, currentRowEl, rowIndex); } else if (visibleColumnIndex === 0 && isSummary) { - const lastRowIndex = this.grid.verticalScrollContainer.igxForOf.length - 1; + const lastRowIndex = this.grid.dataView.length - 1; if (lastRowIndex === -1) { // no child data if (this.grid.allowFiltering && this.grid.filterMode === FilterMode.quickFilter) { @@ -531,7 +533,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi visibleColumnIndex = Math.min(lastCellIndex, visibleColumnIndex); const isScrolledToBottom = this._isScrolledToBottom(childGrid); - const lastIndex = childGrid.verticalScrollContainer.igxForOf.length - 1; + const lastIndex = childGrid.dataView.length - 1; if (!isScrolledToBottom) { // scroll to end this.scrollGrid(childGrid, 'bottom', () => this.focusPrevChild(elem, visibleColumnIndex, grid)); @@ -609,7 +611,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi const verticalScroll = nextParentGrid.verticalScrollContainer.getVerticalScroll(); const parentState = nextParentGrid.verticalScrollContainer.state; const atLastChunk = parentState.startIndex + parentState.chunkSize === - nextParentGrid.verticalScrollContainer.igxForOf.length; + nextParentGrid.dataView.length; if (next) { if (nextIsSiblingChild) { this.focusNextChild(next, visibleColumnIndex, nextParentGrid); @@ -752,7 +754,7 @@ export class IgxHierarchicalGridNavigationService extends IgxGridNavigationServi } else { switch (target) { case 'top': grid.verticalScrollContainer.scrollTo(0); break; - case 'bottom': grid.verticalScrollContainer.scrollTo(grid.verticalScrollContainer.igxForOf.length - 1); break; + case 'bottom': grid.verticalScrollContainer.scrollTo(grid.dataView.length - 1); break; case 'next': grid.verticalScrollContainer.scrollNext(); break; case 'prev': grid.verticalScrollContainer.scrollPrev(); break; } diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts index 122572f73b5..b6abff92f15 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.component.ts @@ -618,7 +618,7 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseCompone $implicit: rowData, moveView: view, owner: tmlpOutlet, - index: this.verticalScrollContainer.igxForOf.indexOf(rowData) + index: this.dataView.indexOf(rowData) }; } else { const rowID = this.primaryKey ? rowData.rowID : this.data.indexOf(rowData.rowID); @@ -626,14 +626,14 @@ export class IgxHierarchicalGridComponent extends IgxHierarchicalGridBaseCompone return { $implicit: rowData, templateID: 'childRow-' + rowID, - index: this.verticalScrollContainer.igxForOf.indexOf(rowData) + index: this.dataView.indexOf(rowData) }; } } else { return { $implicit: rowData, templateID: 'dataRow', - index: this.verticalScrollContainer.igxForOf.indexOf(rowData) + index: this.dataView.indexOf(rowData) }; } } diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts index dd014678dcd..b98cc1aad52 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.integration.spec.ts @@ -17,7 +17,6 @@ import { take } from 'rxjs/operators'; import { IgxHierarchicalTransactionServiceFactory } from './hierarchical-grid-base.component'; import { IgxIconModule } from '../../icon'; import { IgxHierarchicalGridCellComponent } from './hierarchical-cell.component'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; import { GridSelectionMode } from '../common/enums'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; @@ -237,10 +236,10 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { }); fixture.detectChanges(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(100); fixture.detectChanges(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(100); fixture.detectChanges(); @@ -316,10 +315,10 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { // }); // fixture.detectChanges(); - // hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + // hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); // await wait(100); // fixture.detectChanges(); - // hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + // hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); // await wait(100); // fixture.detectChanges(); // const childGrids = fixture.debugElement.queryAll(By.css('igx-child-grid-row')); @@ -515,22 +514,21 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { describe('Paging', () => { it('should work on data records only when paging is enabled and should not be affected by child grid rows.', (async() => { - resizeObserverIgnoreError(); hierarchicalGrid.paging = true; hierarchicalGrid.reflow(); fixture.detectChanges(); - expect(hierarchicalGrid.verticalScrollContainer.igxForOf.length).toEqual(15); + expect(hierarchicalGrid.dataView.length).toEqual(15); hierarchicalGrid.dataRowList.toArray()[1].nativeElement.children[0].click(); fixture.detectChanges(); - expect(hierarchicalGrid.verticalScrollContainer.igxForOf.length).toEqual(16); + expect(hierarchicalGrid.dataView.length).toEqual(16); hierarchicalGrid.dataRowList.toArray()[0].nativeElement.children[0].click(); fixture.detectChanges(); - expect(hierarchicalGrid.verticalScrollContainer.igxForOf.length).toEqual(17); + expect(hierarchicalGrid.dataView.length).toEqual(17); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(100); fixture.detectChanges(); @@ -549,7 +547,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { expect((hierarchicalGrid.dataRowList.toArray()[0] as IgxHierarchicalRowComponent).expanded).toBeTruthy(); expect((hierarchicalGrid.dataRowList.toArray()[1] as IgxHierarchicalRowComponent).expanded).toBeTruthy(); - expect(hierarchicalGrid.verticalScrollContainer.igxForOf.length).toEqual(17); + expect(hierarchicalGrid.dataView.length).toEqual(17); let childGrids = fixture.debugElement.queryAll(By.css('igx-child-grid-row')); let childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance; @@ -563,7 +561,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { expect(hierarchicalGrid.dataRowList.toArray()[0].cells.first.value).toEqual('15'); expect((hierarchicalGrid.dataRowList.toArray()[0] as IgxHierarchicalRowComponent).expanded).toBeFalsy(); expect((hierarchicalGrid.dataRowList.toArray()[1] as IgxHierarchicalRowComponent).expanded).toBeFalsy(); - expect(hierarchicalGrid.verticalScrollContainer.igxForOf.length).toEqual(15); + expect(hierarchicalGrid.dataView.length).toEqual(15); childGrids = fixture.debugElement.queryAll(By.css('igx-child-grid-row')); expect(childGrids.length).toEqual(0); @@ -575,7 +573,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { expect(hierarchicalGrid.dataRowList.toArray()[0].cells.first.value).toEqual('0'); expect((hierarchicalGrid.dataRowList.toArray()[0] as IgxHierarchicalRowComponent).expanded).toBeTruthy(); expect((hierarchicalGrid.dataRowList.toArray()[1] as IgxHierarchicalRowComponent).expanded).toBeTruthy(); - expect(hierarchicalGrid.verticalScrollContainer.igxForOf.length).toEqual(17); + expect(hierarchicalGrid.dataView.length).toEqual(17); childGrids = fixture.debugElement.queryAll(By.css('igx-child-grid-row')); childGrid = childGrids[0].query(By.css('igx-hierarchical-grid')).componentInstance; @@ -584,7 +582,6 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { })); it('should allow scrolling to the last row after page size has been changed and rows are expanded.', (async() => { - resizeObserverIgnoreError(); hierarchicalGrid.paging = true; hierarchicalGrid.perPage = 20; hierarchicalGrid.reflow(); @@ -605,7 +602,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { expect(hierarchicalGrid.hasVerticalSroll()).toBeTruthy(); // scroll bottom - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(30); fixture.detectChanges(); @@ -620,7 +617,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { hierarchicalGrid.getRowByKey('1').nativeElement.children[0].click(); await wait(30); fixture.detectChanges(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(30); fixture.detectChanges(); @@ -635,7 +632,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { hierarchicalGrid.getRowByKey('2').nativeElement.children[0].click(); await wait(30); fixture.detectChanges(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(30); fixture.detectChanges(); @@ -650,7 +647,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { hierarchicalGrid.getRowByKey('3').nativeElement.children[0].click(); await wait(30); fixture.detectChanges(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(30); fixture.detectChanges(); @@ -665,7 +662,7 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { hierarchicalGrid.getRowByKey('4').nativeElement.children[0].click(); await wait(30); fixture.detectChanges(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(30); fixture.detectChanges(); @@ -678,7 +675,6 @@ describe('IgxHierarchicalGrid Integration #hGrid', () => { })); it('should corerctly hide/show vertical scrollbar after page is changed.', (async() => { - resizeObserverIgnoreError(); hierarchicalGrid.paging = true; hierarchicalGrid.perPage = 5; fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts index a57492403a0..5e15d578937 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.navigation.spec.ts @@ -8,7 +8,7 @@ import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { IgxRowIslandComponent } from './row-island.component'; import { By } from '@angular/platform-browser'; import { IgxHierarchicalRowComponent } from './hierarchical-row.component'; -import { setupHierarchicalGridScrollDetection, resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; +import { setupHierarchicalGridScrollDetection } from '../../test-utils/helper-utils.spec'; describe('IgxHierarchicalGrid Basic Navigation #hGrid', () => { configureTestSuite(); @@ -25,7 +25,6 @@ describe('IgxHierarchicalGrid Basic Navigation #hGrid', () => { })); beforeEach(async(() => { - resizeObserverIgnoreError(); fixture = TestBed.createComponent(IgxHierarchicalGridTestBaseComponent); fixture.detectChanges(); hierarchicalGrid = fixture.componentInstance.hgrid; @@ -33,23 +32,35 @@ describe('IgxHierarchicalGrid Basic Navigation #hGrid', () => { })); // simple tests - it('should allow navigating down from parent row into child grid.', () => { - const fCell = hierarchicalGrid.dataRowList.toArray()[0].cells.toArray()[0].nativeElement; + it('should allow navigating down from parent row into child grid.', (async() => { + hierarchicalGrid.expandChildren = false; + hierarchicalGrid.height = '600px'; + hierarchicalGrid.width = '800px'; + fixture.componentInstance.rowIsland.height = '350px'; + fixture.detectChanges(); + await wait(100); + + const row1 = hierarchicalGrid.dataRowList.toArray()[0] as IgxHierarchicalRowComponent; + UIInteractions.clickElement(row1.expander); + fixture.detectChanges(); + await wait(100); + + const fCell = hierarchicalGrid.dataRowList.toArray()[1].cells.toArray()[0].nativeElement; fCell.focus(); fixture.detectChanges(); + const keyboardEvent = new KeyboardEvent('keydown', { code: 'ArrowDown', key: 'ArrowDown' }); fCell.dispatchEvent(keyboardEvent); + await wait(100); fixture.detectChanges(); - const childGrid = hierarchicalGrid.hgridAPI.getChildGrids(false)[0]; - const childFirstCell = childGrid.dataRowList.toArray()[0].cells.toArray()[0]; - - expect(childFirstCell.selected).toBe(true); - expect(childFirstCell.focused).toBe(true); - }); + const sCell = hierarchicalGrid.dataRowList.toArray()[2].cells.toArray()[0]; + expect(sCell.selected).toBe(true); + expect(sCell.focused).toBe(true); + })); it('should allow navigating up from child row into parent grid.', () => { const childGrid = hierarchicalGrid.hgridAPI.getChildGrids(false)[0]; @@ -537,7 +548,7 @@ describe('IgxHierarchicalGrid Basic Navigation #hGrid', () => { it('should retain focused cell when expand/collapse hierarchical row using ALT+Arrow Right/ALT+Arrow Left.', (async () => { // scroll to last row - const lastDataIndex = hierarchicalGrid.verticalScrollContainer.igxForOf.length - 2; + const lastDataIndex = hierarchicalGrid.dataView.length - 2; hierarchicalGrid.verticalScrollContainer.scrollTo(lastDataIndex); await wait(100); fixture.detectChanges(); @@ -877,7 +888,7 @@ describe('IgxHierarchicalGrid Complex Navigation #hGrid', () => { await wait(100); fixture.detectChanges(); const child = hierarchicalGrid.hgridAPI.getChildGrids(false)[0]; - const lastIndex = child.verticalScrollContainer.igxForOf.length - 1; + const lastIndex = child.dataView.length - 1; child.verticalScrollContainer.scrollTo(lastIndex); await wait(100); fixture.detectChanges(); @@ -956,7 +967,7 @@ describe('IgxHierarchicalGrid Multi-layout Navigation #hGrid', () => { const child1 = hierarchicalGrid.hgridAPI.getChildGrids(false)[0]; const child2 = hierarchicalGrid.hgridAPI.getChildGrids(false)[4]; - child1.verticalScrollContainer.scrollTo(child1.verticalScrollContainer.igxForOf.length - 1); + child1.verticalScrollContainer.scrollTo(child1.dataView.length - 1); await wait(100); fixture.detectChanges(); @@ -977,7 +988,7 @@ describe('IgxHierarchicalGrid Multi-layout Navigation #hGrid', () => { const child1 = hierarchicalGrid.hgridAPI.getChildGrids(false)[0]; const child2 = hierarchicalGrid.hgridAPI.getChildGrids(false)[4]; - child1.verticalScrollContainer.scrollTo(child1.verticalScrollContainer.igxForOf.length - 1); + child1.verticalScrollContainer.scrollTo(child1.dataView.length - 1); await wait(100); fixture.detectChanges(); const rowVirt = child1.dataRowList.toArray()[0].virtDirRow; diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts index ce0c241b6c9..022ed8934ce 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.spec.ts @@ -13,7 +13,6 @@ import { DisplayDensity } from '../../core/displayDensity'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { IGridCellEventArgs } from '../grid'; import { GridSelectionMode } from '../common/enums'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; describe('Basic IgxHierarchicalGrid #hGrid', () => { configureTestSuite(); @@ -30,7 +29,6 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { })); beforeEach(async(() => { - resizeObserverIgnoreError(); fixture = TestBed.createComponent(IgxHierarchicalGridTestBaseComponent); fixture.detectChanges(); hierarchicalGrid = fixture.componentInstance.hgrid; @@ -144,7 +142,7 @@ describe('Basic IgxHierarchicalGrid #hGrid', () => { fixture.detectChanges(); expect(row.expanded).toBe(true); // scroll to bottom - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(100); fixture.detectChanges(); // scroll to top @@ -424,7 +422,6 @@ describe('IgxHierarchicalGrid Row Islands #hGrid', () => { })); beforeEach(async(() => { - resizeObserverIgnoreError(); fixture = TestBed.createComponent(IgxHierarchicalGridMultiLayoutComponent); fixture.detectChanges(); hierarchicalGrid = fixture.componentInstance.hgrid; @@ -622,7 +619,7 @@ describe('IgxHierarchicalGrid Row Islands #hGrid', () => { const child2 = children[1]; expect(child1._destroyed).toBeFalsy(); expect(child2._destroyed).toBeFalsy(); - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); await wait(100); fixture.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts index 85f2e4655a7..bbc6e3b4a3b 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.virtualization.spec.ts @@ -9,7 +9,7 @@ import { wait, UIInteractions } from '../../test-utils/ui-interactions.spec'; import { FilteringExpressionsTree, FilteringLogic, IgxStringFilteringOperand } from 'igniteui-angular'; import { By } from '@angular/platform-browser'; import { first, delay } from 'rxjs/operators'; -import { setupHierarchicalGridScrollDetection, resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; +import { setupHierarchicalGridScrollDetection } from '../../test-utils/helper-utils.spec'; describe('IgxHierarchicalGrid Virtualization #hGrid', () => { configureTestSuite(); @@ -32,7 +32,6 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { })); it('should retain expansion state when scrolling.', async () => { - resizeObserverIgnoreError(); const firstRow = hierarchicalGrid.dataRowList.toArray()[0] as IgxHierarchicalRowComponent; // first child of the row should expand indicator firstRow.nativeElement.children[0].click(); @@ -127,7 +126,6 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { }); it('should render correct data for child grid after scrolling and start index changes.', async() => { - resizeObserverIgnoreError(); const firstRow = hierarchicalGrid.dataRowList.toArray()[0]; // first child of the row should expand indicator firstRow.nativeElement.children[0].click(); @@ -186,7 +184,6 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { }); it('should not lose scroll position after expanding a row when there are already expanded rows above.', async() => { - resizeObserverIgnoreError(); // Expand two rows at the top hierarchicalGrid.dataRowList.toArray()[2].nativeElement.children[0].click(); await wait(100); @@ -252,7 +249,7 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { fixture.detectChanges(); await wait(100); // scroll to bottom - hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.verticalScrollContainer.igxForOf.length - 1); + hierarchicalGrid.verticalScrollContainer.scrollTo(hierarchicalGrid.dataView.length - 1); fixture.detectChanges(); await wait(100); fixture.detectChanges(); @@ -280,7 +277,6 @@ describe('IgxHierarchicalGrid Virtualization #hGrid', () => { }); it('should update scroll height after expanding/collapsing row in a nested child grid that has no height.', async () => { - resizeObserverIgnoreError(); fixture.componentInstance.data = [ { ID: 0, ChildLevels: 3, ProductName: 'Product: A0 ' }, { ID: 1, ChildLevels: 3, ProductName: 'Product: A0 ' }, @@ -325,7 +321,6 @@ it('should update scroll height after expanding/collapsing row in a nested child }); it('should update context information correctly for child grid container after scrolling', async() => { - resizeObserverIgnoreError(); // expand 3rd row const row = hierarchicalGrid.dataRowList.toArray()[3]; row.nativeElement.children[0].click(); @@ -385,7 +380,6 @@ describe('IgxHierarchicalGrid Virtualization Custom Scenarios #hGrid', () => { })); it('should show scrollbar after expanding a row with data loaded after initial view initialization', async() => { - resizeObserverIgnoreError(); const fixture = TestBed.createComponent(IgxHierarchicalGridNoScrollTestComponent); fixture.detectChanges(); await wait(); diff --git a/projects/igniteui-angular/src/lib/grids/row.component.ts b/projects/igniteui-angular/src/lib/grids/row.component.ts index 75402875480..adb58cce3e4 100644 --- a/projects/igniteui-angular/src/lib/grids/row.component.ts +++ b/projects/igniteui-angular/src/lib/grids/row.component.ts @@ -59,6 +59,7 @@ export abstract class IgxRowComponent; @Input() + @HostBinding('attr.data-gridID') public gridID; @Input() diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts index 9a278525193..eccd53b739b 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-cell.component.ts @@ -3,7 +3,7 @@ import { Component, ChangeDetectorRef, ElementRef, ViewChild, Inject, import { IgxGridCellComponent } from '../cell.component'; import { IgxTreeGridAPIService } from './tree-grid-api.service'; import { GridBaseAPIService } from '../api.service'; -import { getNodeSizeViaRange } from '../../core/utils'; +import { getNodeSizeViaRange, PlatformUtil } from '../../core/utils'; import { DOCUMENT } from '@angular/common'; import { IgxGridBaseComponent, IGridDataBindable } from '../grid'; import { IgxGridSelectionService, IgxGridCRUDService } from '../../core/grid-selection'; @@ -26,8 +26,9 @@ export class IgxTreeGridCellComponent extends IgxGridCellComponent implements On element: ElementRef, protected zone: NgZone, touchManager: HammerGesturesManager, - @Inject(DOCUMENT) public document) { - super(selectionService, crudService, gridAPI, cdr, element, zone, touchManager); + @Inject(DOCUMENT) public document, + protected platformUtil: PlatformUtil) { + super(selectionService, crudService, gridAPI, cdr, element, zone, touchManager, platformUtil); this.treeGridAPI = gridAPI; } diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-expanding.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-expanding.spec.ts index 00f7e12f41e..ef48c294e99 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-expanding.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-expanding.spec.ts @@ -15,7 +15,6 @@ import { configureTestSuite } from '../../test-utils/configure-suite'; import { first } from 'rxjs/operators'; import { wait } from '../../test-utils/ui-interactions.spec'; import { IgxGridModule } from '../grid'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; import { GridFunctions } from '../../test-utils/grid-functions.spec'; import { GridSelectionMode } from '../common/enums'; @@ -259,7 +258,6 @@ describe('IgxTreeGrid - Expanding / Collapsing #tGrid', () => { }); it('should expand/collapse when using \'expandAll\' and \'collapseAll\' methods', async () => { - resizeObserverIgnoreError(); treeGrid.perPage = 50; await wait(); fix.detectChanges(); @@ -714,7 +712,6 @@ describe('IgxTreeGrid - Expanding / Collapsing #tGrid', () => { }); it('should expand/collapse when using \'expandAll\' and \'collapseAll\' methods', () => { - resizeObserverIgnoreError(); let rows = TreeGridFunctions.getAllRows(fix); expect(rows.length).toBe(3); diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-multi-cell-selection.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-multi-cell-selection.spec.ts index 1d13b701893..0785e785487 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-multi-cell-selection.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-multi-cell-selection.spec.ts @@ -127,7 +127,7 @@ describe('IgxTreeGrid - Multi Cell selection #tGrid', () => { { ID: 17 } ]; - treeGrid.verticalScrollContainer.scrollTo(treeGrid.verticalScrollContainer.igxForOf.length - 1); + treeGrid.verticalScrollContainer.scrollTo(treeGrid.dataView.length - 1); await wait(30); fix.detectChanges(); @@ -169,7 +169,7 @@ describe('IgxTreeGrid - Multi Cell selection #tGrid', () => { GridSelectionFunctions.verifyCellSelected(firstCell); - treeGrid.verticalScrollContainer.scrollTo(treeGrid.verticalScrollContainer.igxForOf.length - 1); + treeGrid.verticalScrollContainer.scrollTo(treeGrid.dataView.length - 1); await wait(200); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-search.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-search.spec.ts index 22f2823f212..032eb9a6411 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-search.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-search.spec.ts @@ -11,7 +11,6 @@ import { configureTestSuite } from '../../test-utils/configure-suite'; import { IgxStringFilteringOperand } from '../../data-operations/filtering-condition'; import { SortingDirection } from '../../data-operations/sorting-expression.interface'; import { wait } from '../../test-utils/ui-interactions.spec'; -import { resizeObserverIgnoreError } from '../../test-utils/helper-utils.spec'; const HIGHLIGHT_CLASS = 'igx-highlight'; const ACTIVE_CLASS = 'igx-highlight__active'; @@ -317,7 +316,6 @@ describe('IgxTreeGrid - search API #tGrid', () => { describe('Scrollable TreeGrid', () => { beforeEach(async() => { - resizeObserverIgnoreError(); fix = TestBed.createComponent(IgxTreeGridSummariesScrollingComponent); fix.detectChanges(); fixNativeElement = fix.debugElement.nativeElement; diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts index ef6f1bcb8ac..35230a18b1e 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid-summaries.spec.ts @@ -1391,7 +1391,7 @@ describe('IgxTreeGrid - Summaries #tGrid', () => { treeGrid.expandAll(); fix.detectChanges(); - treeGrid.verticalScrollContainer.scrollTo(treeGrid.verticalScrollContainer.igxForOf.length - 1); + treeGrid.verticalScrollContainer.scrollTo(treeGrid.dataView.length - 1); await wait(100); fix.detectChanges(); diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts index 47eade9b688..7950acc7628 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.component.ts @@ -697,11 +697,11 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent implements IGridD if (delayScrolling) { this.verticalScrollContainer.onDataChanged.pipe(first()).subscribe(() => { this.scrollDirective(this.verticalScrollContainer, - typeof(row) === 'number' ? row : this.verticalScrollContainer.igxForOf.indexOf(record)); + typeof(row) === 'number' ? row : this.dataView.indexOf(record)); }); } else { this.scrollDirective(this.verticalScrollContainer, - typeof(row) === 'number' ? row : this.verticalScrollContainer.igxForOf.indexOf(record)); + typeof(row) === 'number' ? row : this.dataView.indexOf(record)); } this.scrollToHorizontally(column); @@ -732,7 +732,7 @@ export class IgxTreeGridComponent extends IgxGridBaseComponent implements IGridD source.push(record.data); }; - this.verticalScrollContainer.igxForOf.forEach(process); + this.dataView.forEach(process); return this.extractDataFromSelection(source, formatters, headers); } diff --git a/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.spec.ts b/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.spec.ts index 730b8c250b5..36af4b07945 100644 --- a/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.spec.ts +++ b/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.spec.ts @@ -1,18 +1,12 @@ -import { - async, - ComponentFixture, - fakeAsync, - TestBed, - tick -} from '@angular/core/testing'; - -import { Component, ViewChild } from '@angular/core'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Component, ViewChild, PLATFORM_ID } from '@angular/core'; import { By } from '@angular/platform-browser'; import { wait } from '../test-utils/ui-interactions.spec'; import { IgxNavigationDrawerModule } from './navigation-drawer.module'; import { IgxNavigationToggleDirective, IgxNavigationCloseDirective } from '../core/navigation/directives'; import { IgxNavigationDrawerComponent } from './navigation-drawer.component'; import { IgxNavigationService } from '../core/navigation/nav.service'; +import { PlatformUtil } from '../core/utils'; // HammerJS simulator from https://github.com/hammerjs/simulator, manual typings TODO declare var Simulator: any; @@ -45,13 +39,17 @@ describe('Navigation Drawer', () => { jasmine.DEFAULT_TIMEOUT_INTERVAL = oldTimeout; }); + afterAll(() => { + TestBed.resetTestingModule(); + }); + it('should initialize without DI service', async(() => { TestBed.compileComponents().then(() => { const fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); - expect(fixture.componentInstance.viewChild instanceof + expect(fixture.componentInstance.navDrawer instanceof IgxNavigationDrawerComponent).toBeTruthy(); - expect(fixture.componentInstance.viewChild.state).toBeNull(); + expect(fixture.componentInstance.navDrawer.state).toBeNull(); }); })); @@ -60,10 +58,10 @@ describe('Navigation Drawer', () => { const fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - expect(fixture.componentInstance.viewChild).toBeDefined(); - expect(fixture.componentInstance.viewChild instanceof + expect(fixture.componentInstance.navDrawer).toBeDefined(); + expect(fixture.componentInstance.navDrawer instanceof IgxNavigationDrawerComponent).toBeTruthy(); - expect(fixture.componentInstance.viewChild.state instanceof IgxNavigationService) + expect(fixture.componentInstance.navDrawer.state instanceof IgxNavigationService) .toBeTruthy(); }); })); @@ -75,8 +73,8 @@ describe('Navigation Drawer', () => { const fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); - expect(fixture.componentInstance.viewChild).toBeDefined(); - expect(fixture.componentInstance.viewChild instanceof + expect(fixture.componentInstance.navDrawer).toBeDefined(); + expect(fixture.componentInstance.navDrawer instanceof IgxNavigationDrawerComponent).toBeTruthy(); expect(() => fixture.destroy()).not.toThrow(); }); @@ -88,17 +86,17 @@ describe('Navigation Drawer', () => { fixture.detectChanges(); const domNavDrawer = fixture.debugElement.query(By.css('igx-nav-drawer')).nativeElement; - expect(fixture.componentInstance.viewChild.id).toContain('igx-nav-drawer-'); + expect(fixture.componentInstance.navDrawer.id).toContain('igx-nav-drawer-'); expect(domNavDrawer.id).toContain('igx-nav-drawer-'); - expect(fixture.componentInstance.viewChild.drawer.classList).toContain('igx-nav-drawer__aside'); - expect(fixture.componentInstance.viewChild.overlay.classList).toContain('igx-nav-drawer__overlay'); - expect(fixture.componentInstance.viewChild.styleDummy.classList).toContain('igx-nav-drawer__style-dummy'); - expect(fixture.componentInstance.viewChild.hasAnimateWidth).toBeFalsy(); + expect(fixture.componentInstance.navDrawer.drawer.classList).toContain('igx-nav-drawer__aside'); + expect(fixture.componentInstance.navDrawer.overlay.classList).toContain('igx-nav-drawer__overlay'); + expect(fixture.componentInstance.navDrawer.styleDummy.classList).toContain('igx-nav-drawer__style-dummy'); + expect(fixture.componentInstance.navDrawer.hasAnimateWidth).toBeFalsy(); - fixture.componentInstance.viewChild.id = 'customNavDrawer'; + fixture.componentInstance.navDrawer.id = 'customNavDrawer'; fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.id).toBe('customNavDrawer'); + expect(fixture.componentInstance.navDrawer.id).toBe('customNavDrawer'); expect(domNavDrawer.id).toBe('customNavDrawer'); }).catch((reason) => { @@ -118,8 +116,8 @@ describe('Navigation Drawer', () => { TestBed.compileComponents().then(() => { const fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - const state: IgxNavigationService = fixture.componentInstance.viewChild.state; - const touchManager = fixture.componentInstance.viewChild.touchManager; + const state: IgxNavigationService = fixture.componentInstance.navDrawer.state; + const touchManager = fixture.componentInstance.navDrawer.touchManager; expect(state.get('testNav')).toBeDefined(); expect(touchManager.getManagerForElement(document) instanceof Hammer.Manager).toBeTruthy(); @@ -137,7 +135,7 @@ describe('Navigation Drawer', () => { TestBed.compileComponents().then(() => { const fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - const drawer: IgxNavigationDrawerComponent = fixture.componentInstance.viewChild; + const drawer: IgxNavigationDrawerComponent = fixture.componentInstance.navDrawer; expect(drawer.isOpen).toBeFalsy(); drawer.open(); @@ -168,7 +166,7 @@ describe('Navigation Drawer', () => { TestBed.compileComponents().then(() => { fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - drawer = fixture.componentInstance.viewChild; + drawer = fixture.componentInstance.navDrawer; spyOn(drawer.closing, 'emit'); spyOn(drawer.closed, 'emit'); @@ -210,7 +208,7 @@ describe('Navigation Drawer', () => { const fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.hasAnimateWidth).toBeTruthy(); + expect(fixture.componentInstance.navDrawer.hasAnimateWidth).toBeTruthy(); expect(fixture.debugElement.query((x) => x.nativeNode.nodeName === 'ASIDE').nativeElement.classList) .toContain('igx-nav-drawer__aside--mini'); }).catch((reason) => { @@ -249,7 +247,7 @@ describe('Navigation Drawer', () => { fixture.componentInstance.miniView = true; fixture.detectChanges(); - expect(asideElem.styles['width']).toEqual(fixture.componentInstance.viewChild.miniWidth); + expect(asideElem.styles['width']).toEqual(fixture.componentInstance.navDrawer.miniWidth); }).catch((reason) => { return Promise.reject(reason); }); @@ -269,15 +267,15 @@ describe('Navigation Drawer', () => { const fixture = TestBed.createComponent(TestComponentPin); fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.pin).toBeTruthy(); + expect(fixture.componentInstance.navDrawer.pin).toBeTruthy(); expect(fixture.debugElement.query((x) => x.nativeNode.nodeName === 'ASIDE').nativeElement.classList) .toContain('igx-nav-drawer__aside--pinned'); - expect(fixture.componentInstance.viewChild.enableGestures).toBe(false); + expect(fixture.componentInstance.navDrawer.enableGestures).toBe(false); fixture.componentInstance.enableGestures = 'true'; fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.enableGestures).toBeTruthy(); + expect(fixture.componentInstance.navDrawer.enableGestures).toBeTruthy(); }).catch((reason) => { return Promise.reject(reason); @@ -326,7 +324,7 @@ describe('Navigation Drawer', () => { TestBed.compileComponents() .then(() => { const fixture = TestBed.createComponent(TestComponentPin); - const drawer = fixture.componentInstance.viewChild; + const drawer = fixture.componentInstance.navDrawer; drawer.isOpen = true; fixture.detectChanges(); const drawerElem = fixture.debugElement.query((x) => x.nativeNode.nodeName === 'IGX-NAV-DRAWER').nativeElement; @@ -355,22 +353,22 @@ describe('Navigation Drawer', () => { TestBed.compileComponents().then(() => { fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.isOpen).toEqual(false); + expect(fixture.componentInstance.navDrawer.isOpen).toEqual(false); // timeouts are +50 on the gesture to allow the swipe to be detected and triggered after the touches: return swipe(document.body, 80, 10, 100, 250, 0); }) .then(() => { - expect(fixture.componentInstance.viewChild.isOpen) + expect(fixture.componentInstance.navDrawer.isOpen) .toEqual(false, 'should ignore swipes too far away from the edge'); return swipe(document.body, 10, 10, 150, 250, 0); }) .then(() => { - expect(fixture.componentInstance.viewChild.isOpen).toEqual(true, 'Should accept edge swipe'); + expect(fixture.componentInstance.navDrawer.isOpen).toEqual(true, 'Should accept edge swipe'); return swipe(document.body, 180, 10, 150, -180, 0); }) .then(() => { - expect(fixture.componentInstance.viewChild.isOpen).toEqual(false); + expect(fixture.componentInstance.navDrawer.isOpen).toEqual(false); done(); }) .catch((reason) => { @@ -386,9 +384,9 @@ describe('Navigation Drawer', () => { TestBed.compileComponents().then(() => { fixture = TestBed.createComponent(TestComponentDIComponent); fixture.detectChanges(); - navDrawer = fixture.componentInstance.viewChild; + navDrawer = fixture.componentInstance.navDrawer; - expect(fixture.componentInstance.viewChild.isOpen).toEqual(false); + expect(fixture.componentInstance.navDrawer.isOpen).toEqual(false); const listener = navDrawer.renderer.listen(document.body, 'panmove', () => { @@ -443,12 +441,12 @@ describe('Navigation Drawer', () => { fixture.componentInstance.drawerMiniWidth = 68; fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.maxEdgeZone) + expect(fixture.componentInstance.navDrawer.maxEdgeZone) .toBe(fixture.componentInstance.drawerMiniWidth * 1.1); fixture.componentInstance.drawerMiniWidth = 80; fixture.detectChanges(); - expect(fixture.componentInstance.viewChild.maxEdgeZone) + expect(fixture.componentInstance.navDrawer.maxEdgeZone) .toBe(fixture.componentInstance.drawerMiniWidth * 1.1); }).catch((reason) => { @@ -456,7 +454,7 @@ describe('Navigation Drawer', () => { }); })); - it('should update width from css or property', fakeAsync((done) => { + it('should update width from css or property', async(done) => { const template = ` @@ -469,41 +467,36 @@ describe('Navigation Drawer', () => { }); // compile after overrides, not in before each: https://github.com/angular/angular/issues/10712 - TestBed.compileComponents().then(() => { - fixture = TestBed.createComponent(TestComponentDIComponent); - fixture.detectChanges(); - // const comp: DebugElement = fixture.debugElement.query(By.component(IgxNavbarComponent)); + await TestBed.compileComponents(); + fixture = TestBed.createComponent(TestComponentDIComponent); + fixture.detectChanges(); + // const comp: DebugElement = fixture.debugElement.query(By.component(IgxNavbarComponent)); - // defaults: - expect(fixture.componentInstance.viewChild.drawer.style.width).toBe(''); - return fixture.componentInstance.viewChild.open(); - }) - .then(() => { - expect(fixture.componentInstance.viewChild.drawer.style.width).toBe(''); + // defaults: + expect(fixture.componentInstance.navDrawer.drawer.style.width).toBe(''); + fixture.componentInstance.navDrawer.open(); + await wait(200); - fixture.componentInstance.drawerMiniWidth = '80px'; - fixture.componentInstance.drawerWidth = '250px'; - fixture.detectChanges(); - return fixture.whenStable(); // let changes apply in the meantime - }) - .then(() => { - expect(fixture.componentInstance.viewChild.drawer.style.width).toBe('250px'); - return fixture.componentInstance.viewChild.close(); - }) - .then(() => { - tick(1000); - expect(fixture.componentInstance.viewChild.drawer.style.width).toBe('80px'); - fixture.componentInstance.drawerWidth = '350px'; - fixture.detectChanges(); - return fixture.componentInstance.viewChild.open(); - }) - .then(() => { - expect(fixture.componentInstance.viewChild.drawer.style.width).toBe('350px'); - done(); - }).catch((reason) => { - return Promise.reject(reason); - }); - })); + expect(fixture.componentInstance.navDrawer.drawer.style.width).toBe(''); + + fixture.componentInstance.drawerMiniWidth = '80px'; + fixture.componentInstance.drawerWidth = '250px'; + fixture.detectChanges(); + await wait(200); + + expect(fixture.componentInstance.navDrawer.drawer.style.width).toBe('250px'); + fixture.componentInstance.navDrawer.close(); + await wait(200); + + expect(fixture.componentInstance.navDrawer.drawer.style.width).toBe('80px'); + fixture.componentInstance.drawerWidth = '350px'; + fixture.detectChanges(); + fixture.componentInstance.navDrawer.open(); + await wait(200); + + expect(fixture.componentInstance.navDrawer.drawer.style.width).toBe('350px'); + done(); + }); it('should update pin based on window width (pinThreshold)', async (done) => { const template = `''`; @@ -523,7 +516,7 @@ describe('Navigation Drawer', () => { await fixture.whenStable(); // defaults: - expect(fixture.componentInstance.viewChild.pin).toBe(false, 'Should be initially unpinned'); + expect(fixture.componentInstance.navDrawer.pin).toBe(false, 'Should be initially unpinned'); expect(fixture.componentInstance.pin).toBe(false, 'Parent component pin should update initially'); // manual pin override @@ -533,7 +526,7 @@ describe('Navigation Drawer', () => { // wait for debounce await wait(200); - expect(fixture.componentInstance.viewChild.pin).toBe(false, `Shouldn't change state on resize if window width is the same`); + expect(fixture.componentInstance.navDrawer.pin).toBe(false, `Shouldn't change state on resize if window width is the same`); expect(fixture.componentInstance.pin).toBe(true, 'Parent component pin remain on resize if window width is the same'); fixture.componentInstance.pin = true; fixture.detectChanges(); @@ -543,7 +536,7 @@ describe('Navigation Drawer', () => { // wait for debounce await wait(200); - expect(fixture.componentInstance.viewChild.pin).toBe(true, 'Should pin on window resize over threshold'); + expect(fixture.componentInstance.navDrawer.pin).toBe(true, 'Should pin on window resize over threshold'); expect(fixture.componentInstance.pin).toBe(true, 'Parent pin update on window resize over threshold'); widthSpyOverride.and.returnValue(768); @@ -551,24 +544,29 @@ describe('Navigation Drawer', () => { // wait for debounce await wait(200); - expect(fixture.componentInstance.viewChild.pin).toBe(false, 'Should un-pin on window resize below threshold'); + expect(fixture.componentInstance.navDrawer.pin).toBe(false, 'Should un-pin on window resize below threshold'); expect(fixture.componentInstance.pin).toBe(false, 'Parent pin update on window resize below threshold'); fixture.componentInstance.pinThreshold = 500; expect(() => fixture.detectChanges()).not.toThrow(); await fixture.whenStable(); - expect(fixture.componentInstance.viewChild.pin).toBe(true, 'Should re-pin on window resize over threshold'); + expect(fixture.componentInstance.navDrawer.pin).toBe(true, 'Should re-pin on window resize over threshold'); expect(fixture.componentInstance.pin).toBe(true, 'Parent pin update on re-pin'); done(); }); it('should get correct window width', (done) => { const originalWidth = window.innerWidth; + const platformUtil: PlatformUtil = new PlatformUtil(TestBed.get(PLATFORM_ID)); + const drawer = new IgxNavigationDrawerComponent(null, null, null, null, platformUtil); // re-enable `getWindowWidth` const widthSpy = (widthSpyOverride as jasmine.Spy).and.callThrough(); - expect(widthSpy.call(null)).toEqual(originalWidth); + let width = widthSpy.call(drawer); + expect(width).toEqual(originalWidth); + (window as any).innerWidth = 0; // not that readonly in Chrome - expect(widthSpy.call(null)).toEqual(screen.width); + width = widthSpy.call(drawer); + expect(width).toEqual(screen.width); (window as any).innerWidth = originalWidth; done(); }); @@ -615,7 +613,7 @@ describe('Navigation Drawer', () => { template: '' }) class TestComponent { - @ViewChild(IgxNavigationDrawerComponent, { static: true }) public viewChild: IgxNavigationDrawerComponent; + @ViewChild(IgxNavigationDrawerComponent, { static: true }) public navDrawer: IgxNavigationDrawerComponent; } @Component({ @@ -626,7 +624,7 @@ class TestComponent { class TestComponentDIComponent { public drawerMiniWidth: string | number; public drawerWidth: string | number; - @ViewChild(IgxNavigationDrawerComponent, { static: true }) public viewChild: IgxNavigationDrawerComponent; + @ViewChild(IgxNavigationDrawerComponent, { static: true }) public navDrawer: IgxNavigationDrawerComponent; } class TestComponentPin extends TestComponentDIComponent { diff --git a/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.ts b/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.ts index e91a8c0f971..ce889b4d62f 100644 --- a/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.ts +++ b/projects/igniteui-angular/src/lib/navigation-drawer/navigation-drawer.component.ts @@ -21,6 +21,7 @@ import { debounce } from 'rxjs/operators'; import { IgxNavigationService, IToggleView } from '../core/navigation'; import { HammerGesturesManager } from '../core/touch'; import { IgxNavDrawerMiniTemplateDirective, IgxNavDrawerTemplateDirective } from './navigation-drawer.directives'; +import { PlatformUtil } from '../core/utils'; let NEXT_ID = 0; /** @@ -417,7 +418,8 @@ export class IgxNavigationDrawerComponent implements @Optional() private _state: IgxNavigationService, // private animate: AnimationBuilder, TODO protected renderer: Renderer, - private _touchManager: HammerGesturesManager) { + private _touchManager: HammerGesturesManager, + private platformUtil: PlatformUtil) { } /** @@ -619,11 +621,15 @@ export class IgxNavigationDrawerComponent implements * Sets the drawer width. */ private setDrawerWidth(width: string) { - requestAnimationFrame(() => { - if (this.drawer) { - this.renderer.setElementStyle(this.drawer, 'width', width); - } - }); + if (this.platformUtil.isBrowser) { + requestAnimationFrame(() => { + if (this.drawer) { + this.renderer.setElementStyle(this.drawer, 'width', width); + } + }); + } else { + this.renderer.setElementStyle(this.drawer, 'width', width); + } } /** @@ -649,7 +655,7 @@ export class IgxNavigationDrawerComponent implements this._touchManager.addGlobalEventListener('document', 'panmove', this.pan); this._touchManager.addGlobalEventListener('document', 'panend', this.panEnd); } - if (!this._resizeObserver) { + if (!this._resizeObserver && this.platformUtil.isBrowser) { this._resizeObserver = fromEvent(window, 'resize').pipe(debounce(() => interval(150))) .subscribe((value) => { this.checkPinThreshold(value); @@ -667,6 +673,9 @@ export class IgxNavigationDrawerComponent implements } private checkPinThreshold = (evt?: Event) => { + if (!this.platformUtil.isBrowser) { + return; + } let windowWidth; if (this.pinThreshold) { windowWidth = this.getWindowWidth(); @@ -810,9 +819,9 @@ export class IgxNavigationDrawerComponent implements if (this.hasAnimateWidth) { this.renderer.setElementStyle(this.drawer, 'width', x ? Math.abs(x) + 'px' : ''); } else { - this.renderer.setElementStyle(this.drawer, 'transform', x ? 'translate3d(' + x + 'px,0,0)' : ''); - this.renderer.setElementStyle(this.drawer, '-webkit-transform', - x ? 'translate3d(' + x + 'px,0,0)' : ''); + const transform = x ? 'translate3d(' + x + 'px,0,0)' : ''; + this.renderer.setElementStyle(this.drawer, 'transform', transform); + this.renderer.setElementStyle(this.drawer, '-webkit-transform', transform); } if (opacity !== undefined) { this.renderer.setElementStyle(this.overlay, 'opacity', opacity); diff --git a/projects/igniteui-angular/src/lib/tabs/tab-item.component.ts b/projects/igniteui-angular/src/lib/tabs/tab-item.component.ts index cf05840af10..4ef47be3e1c 100644 --- a/projects/igniteui-angular/src/lib/tabs/tab-item.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tab-item.component.ts @@ -6,20 +6,23 @@ import { HostListener, Input, TemplateRef, - ViewChild + ViewChild, + NgZone, + AfterViewInit, + OnDestroy } from '@angular/core'; import { IgxTabsGroupComponent } from './tabs-group.component'; import { IgxTabItemBase, IgxTabsBase } from './tabs.common'; import { IgxTabItemTemplateDirective } from './tabs.directives'; +import ResizeObserver from 'resize-observer-polyfill'; @Component({ selector: 'igx-tab-item', templateUrl: 'tab-item.component.html' }) -export class IgxTabItemComponent extends IgxTabItemBase { - +export class IgxTabItemComponent extends IgxTabItemBase implements AfterViewInit, OnDestroy { /** * Gets the group associated with the tab. * ```html @@ -82,8 +85,9 @@ export class IgxTabItemComponent extends IgxTabItemBase { private _changesCount = 0; // changes and updates accordingly applied to the tab. private _isSelected = false; private _disabled = false; + private _resizeObserver: ResizeObserver; - constructor(private _tabs: IgxTabsBase, private _element: ElementRef) { + constructor(private _tabs: IgxTabsBase, private _element: ElementRef, private _ngZone: NgZone) { super(); this._nativeTabItem = _element; } @@ -145,6 +149,20 @@ export class IgxTabItemComponent extends IgxTabItemBase { @HostBinding('attr.aria-controls') public ariaControls = 'igx-tab-item-group-' + this.index; + ngAfterViewInit(): void { + this._ngZone.runOutsideAngular(() => { + this._resizeObserver = new ResizeObserver(() => { + this._tabs.transformIndicatorAnimation(this._nativeTabItem.nativeElement, 0); + }); + }); + } + + ngOnDestroy(): void { + this._ngZone.runOutsideAngular(() => { + this._resizeObserver.disconnect(); + }); + } + /** * @hidden */ @@ -153,16 +171,6 @@ export class IgxTabItemComponent extends IgxTabItemBase { this.select(); } - /** - * @hidden - */ - @HostListener('window:resize', ['$event']) - public onResize(event) { - if (this.isSelected) { - this._tabs.transformIndicatorAnimation(this.nativeTabItem.nativeElement); - } - } - /** * @hidden */ @@ -269,6 +277,15 @@ export class IgxTabItemComponent extends IgxTabItemBase { */ public setSelectedInternal(newValue: boolean) { this._isSelected = newValue; + this._ngZone.runOutsideAngular(() => { + if (this._resizeObserver) { + if (this._isSelected) { + this._resizeObserver.observe(this._element.nativeElement); + } else { + this._resizeObserver.disconnect(); + } + } + }); this.tabindex = newValue ? 0 : -1; } diff --git a/projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts index d5d5ef9f9b5..1e4b0eede93 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs-group.component.ts @@ -93,13 +93,6 @@ export class IgxTabsGroupComponent extends IgxTabsGroupBase implements AfterCont @HostBinding('class.igx-tabs__group') public styleClass = true; - @HostListener('window:resize', ['$event']) - public onResize(event) { - if (this.isSelected) { - this._tabs.transformContentAnimation(this.relatedTab, 0); - } - } - /** * An accessor that returns the `IgxTabItemComponent` component. * ```typescript diff --git a/projects/igniteui-angular/src/lib/tabs/tabs.common.ts b/projects/igniteui-angular/src/lib/tabs/tabs.common.ts index bb186b57ea9..84a29e11e2f 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs.common.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs.common.ts @@ -17,7 +17,7 @@ export abstract class IgxTabsBase { scrollElement(element: any, scrollRight: boolean) {} performSelectionChange(newTab: IgxTabItemBase) {} transformContentAnimation(tab: IgxTabItemBase, duration: number) {} - transformIndicatorAnimation(element: HTMLElement) {} + transformIndicatorAnimation(element: HTMLElement, duration?: number) {} } /** @hidden */ diff --git a/projects/igniteui-angular/src/lib/tabs/tabs.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs.component.ts index 802ae79061f..45c2fc553ef 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs.component.ts @@ -13,7 +13,8 @@ import { QueryList, ViewChild, ViewChildren, - OnDestroy + OnDestroy, + NgZone } from '@angular/core'; import { Subscription } from 'rxjs'; import { IgxBadgeModule } from '../badge/badge.component'; @@ -23,6 +24,7 @@ import { IgxTabItemComponent } from './tab-item.component'; import { IgxTabsGroupComponent } from './tabs-group.component'; import { IgxLeftButtonStyleDirective, IgxRightButtonStyleDirective, IgxTabItemTemplateDirective } from './tabs.directives'; import { IgxTabsBase, IgxTabItemBase } from './tabs.common'; +import ResizeObserver from 'resize-observer-polyfill'; export enum TabsType { FIXED = 'fixed', @@ -228,6 +230,7 @@ export class IgxTabsComponent implements IgxTabsBase, AfterViewInit, OnDestroy { private _groupChanges$: Subscription; private _selectedIndex = -1; + private _resizeObserver: ResizeObserver; /** * @hidden @@ -295,7 +298,7 @@ export class IgxTabsComponent implements IgxTabsBase, AfterViewInit, OnDestroy { } } - constructor(private _element: ElementRef) { + constructor(private _element: ElementRef, private _ngZone: NgZone) { } /** @@ -326,6 +329,17 @@ export class IgxTabsComponent implements IgxTabsBase, AfterViewInit, OnDestroy { this._groupChanges$ = this.groups.changes.subscribe(() => { this.resetSelectionOnCollectionChanged(); }); + + this._ngZone.runOutsideAngular(() => { + this._resizeObserver = new ResizeObserver(() => { + if (!this.hasContentTabs && this._selectedIndex >= 0 && this._selectedIndex < this.tabs.length) { + const newTab = this.tabs.toArray()[this._selectedIndex]; + this.transformContentAnimation(newTab, 0); + } + }); + + this._resizeObserver.observe(this.tabsContainer.nativeElement); + }); } /** @@ -335,6 +349,10 @@ export class IgxTabsComponent implements IgxTabsBase, AfterViewInit, OnDestroy { if (this._groupChanges$) { this._groupChanges$.unsubscribe(); } + + this._ngZone.runOutsideAngular(() => { + this._resizeObserver.disconnect(); + }); } private resetSelectionOnCollectionChanged(): void { @@ -445,16 +463,17 @@ export class IgxTabsComponent implements IgxTabsBase, AfterViewInit, OnDestroy { // animation for the new panel/group (not needed for tab only mode) public transformContentAnimation(tab: IgxTabItemBase, duration: number): void { const contentOffset = this.tabsContainer.nativeElement.offsetWidth * tab.index; - this.contentsContainer.nativeElement.style.transitionDuration = `${duration}s`; + this.contentsContainer.nativeElement.style.transitionDuration = duration > 0 ? `${duration}s` : 'initial'; this.contentsContainer.nativeElement.style.transform = `translate(${-contentOffset}px)`; } /** * @hidden */ - public transformIndicatorAnimation(element: HTMLElement): void { + public transformIndicatorAnimation(element: HTMLElement, duration = 0.3): void { if (this.selectedIndicator) { this.selectedIndicator.nativeElement.style.visibility = 'visible'; + this.selectedIndicator.nativeElement.style.transitionDuration = duration > 0 ? `${duration}s` : 'initial'; this.selectedIndicator.nativeElement.style.width = `${element.offsetWidth}px`; this.selectedIndicator.nativeElement.style.transform = `translate(${element.offsetLeft}px)`; } diff --git a/projects/igniteui-angular/src/lib/test-utils/configure-suite.ts b/projects/igniteui-angular/src/lib/test-utils/configure-suite.ts index 083497736f1..c77b746e7e7 100644 --- a/projects/igniteui-angular/src/lib/test-utils/configure-suite.ts +++ b/projects/igniteui-angular/src/lib/test-utils/configure-suite.ts @@ -1,4 +1,5 @@ import { TestBed, getTestBed, ComponentFixture } from '@angular/core/testing'; +import { resizeObserverIgnoreError } from './helper-utils.spec'; /** * Per https://github.com/angular/angular/issues/12409#issuecomment-391087831 @@ -11,6 +12,7 @@ export const configureTestSuite = () => { originReset = TestBed.resetTestingModule; // TestBed.resetTestingModule(); TestBed.resetTestingModule = () => TestBed; + resizeObserverIgnoreError(); }); afterEach(() => { diff --git a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts index 3d9ab102764..e8de56547d9 100644 --- a/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/grid-samples.spec.ts @@ -1198,6 +1198,31 @@ export class IgxGridAdvancedFilteringComponent extends BasicGridComponent { } } +@Component({ + template: ` + + + + + + + + + + ` +}) +export class IgxGridAdvancedFilteringColumnGroupComponent extends BasicGridComponent { + public customFilter = CustomFilter.instance(); + public resizable = false; + public filterable = true; + + public data = SampleTestData.excelFilteringData(); + public activateFiltering(activate: boolean) { + this.grid.allowFiltering = activate; + this.grid.cdr.markForCheck(); + } +} + @Component({ template: ` @@ -1500,3 +1525,23 @@ export class CellEditingScrollTestComponent extends BasicGridComponent { { firstName: 'Michael', lastName: 'Parker', age: 48, isActive: true, birthday: new Date('08/08/1970'), fullName: 'Michael Parker' } ]; } + +@Component({ + template: GridTemplateStrings.declareGrid( + ` [width]="width" [height]="height" [paging]="'true'" [perPage]="perPage" [primaryKey]="'ProductID'"`, + '', ColumnDefinitions.productBasic) +}) +export class GridWithUndefinedDataComponent implements OnInit { + @ViewChild(IgxGridComponent, { static: true }) + public grid: IgxGridComponent; + public data ; + public perPage = 5; + public width = '800px'; + public height = '600px'; + + public ngOnInit(): void { + setTimeout(() => { + this.data = SampleTestData.foodProductDataExtended(); + }, 300); + } +} diff --git a/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts b/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts index de66a93ef95..bd372af470e 100644 --- a/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts +++ b/projects/igniteui-angular/src/lib/test-utils/helper-utils.spec.ts @@ -6,6 +6,7 @@ import { IgxGridBaseComponent } from '../grids/index'; import { IgxHierarchicalGridComponent } from '../grids/hierarchical-grid'; export function resizeObserverIgnoreError() { + jasmine.getEnv().allowRespy(true); const spy = spyOn(window, 'onerror').and.callFake((...args) => { if (args[0].toString().match('ResizeObserver loop limit exceeded')) { return; diff --git a/src/styles/igniteui-theme.scss b/src/styles/igniteui-theme.scss index eb1227b4153..06ff70f7ce6 100644 --- a/src/styles/igniteui-theme.scss +++ b/src/styles/igniteui-theme.scss @@ -26,13 +26,13 @@ .dark-theme { $igx-background-color: #333; $igx-foreground-color: text-contrast($igx-background-color); - + background: $igx-background-color; color: $igx-foreground-color; - + @include scrollbar-love(lighten($igx-background-color, 15%)); @include igx-dark-theme($green-palette); - + .nav-header { @include nav-logo('../assets/images/rsrcs/igniteui-logo-dark-bg', $igx-background-color); } @@ -41,7 +41,7 @@ .fluent-excel-theme { $igx-background-color: #fff; $igx-foreground-color: text-contrast($igx-background-color); - + background: $igx-background-color; color: $igx-foreground-color; @@ -71,13 +71,13 @@ .fluent-excel-dark-theme { $igx-background-color: #333; $igx-foreground-color: text-contrast($igx-background-color); - + background: $igx-background-color; color: $igx-foreground-color; - + @include scrollbar-love(lighten($igx-background-color, 15%)); @include igx-fluent-dark-theme($fluent-excel-palette); - + .nav-header { @include nav-logo('../assets/images/rsrcs/igniteui-logo-light-bg', $igx-foreground-color); } @@ -86,13 +86,13 @@ .light-square-theme { $igx-background-color: #fff; $igx-foreground-color: text-contrast($igx-background-color); - + background: $igx-background-color; color: $igx-foreground-color; - + @include scrollbar-love(); @include igx-light-square-theme($purple-palette); - + .nav-header { @include nav-logo('../assets/images/rsrcs/igniteui-logo-light-bg', $igx-background-color); } @@ -101,10 +101,10 @@ .light-round-theme { $igx-background-color: #fff; $igx-foreground-color: text-contrast($igx-background-color); - + background: $igx-background-color; color: $igx-foreground-color; - + @include scrollbar-love(); @include igx-theme($palette: $purple-palette, $schema: $light-round-schema); }