From 8d1f63fe5f0df12042f704b985fca4247a5efe7b Mon Sep 17 00:00:00 2001 From: Deyan Kamburov Date: Fri, 4 Mar 2022 11:35:24 +0200 Subject: [PATCH] chore(*): apply gitattributes changes to existing files --- README.md | 508 +++--- .../update-12_1_0/changes/classes.json | 56 +- .../src/lib/carousel/carousel-base.ts | 378 ++-- .../src/lib/carousel/public_api.ts | 8 +- .../calendar-container.component.ts | 18 +- .../lib/directives/for-of/for_of.directive.ts | 22 +- .../src/lib/grids/columns/column.module.ts | 50 +- .../excel-style-header.component.html | 56 +- .../excel-style-header.component.ts | 98 +- .../grids/filtering/excel-style/public_api.ts | 22 +- .../src/lib/grids/grid-common.module.ts | 150 +- .../src/lib/grids/grid-public-cell.ts | 558 +++--- .../src/lib/grids/grid-public-row.ts | 1578 ++++++++--------- .../grids/grouping/group-by-area.directive.ts | 388 ++-- .../hierarchical-grid.module.ts | 72 +- .../tree-grid/tree-grid.filtering.strategy.ts | 342 ++-- .../bottom-nav-content.component.html | 2 +- .../bottom-nav-content.component.ts | 28 +- .../bottom-nav-header.component.html | 2 +- .../bottom-nav/bottom-nav-header.component.ts | 58 +- .../bottom-nav/bottom-nav-item.component.html | 12 +- .../bottom-nav/bottom-nav-item.component.ts | 20 +- .../tabs/bottom-nav/bottom-nav.component.html | 28 +- .../tabs/bottom-nav/bottom-nav.component.ts | 110 +- .../tabs/bottom-nav/bottom-nav.directives.ts | 22 +- .../lib/tabs/bottom-nav/bottom-nav.module.ts | 64 +- .../src/lib/tabs/bottom-nav/public_api.ts | 12 +- .../src/lib/tabs/public_api.ts | 8 +- .../src/lib/tabs/tab-content.directive.ts | 64 +- .../src/lib/tabs/tab-header.directive.ts | 104 +- .../src/lib/tabs/tab-item.directive.ts | 124 +- .../src/lib/tabs/tabs.base.ts | 58 +- .../src/lib/tabs/tabs.directive.ts | 632 +++---- .../src/lib/tabs/tabs/public_api.ts | 12 +- .../lib/tabs/tabs/tab-content.component.html | 2 +- .../lib/tabs/tabs/tab-content.component.ts | 28 +- .../lib/tabs/tabs/tab-header.component.html | 14 +- .../src/lib/tabs/tabs/tab-header.component.ts | 268 +-- .../src/lib/tabs/tabs/tab-item.component.html | 12 +- .../src/lib/tabs/tabs/tab-item.component.ts | 22 +- .../src/lib/tabs/tabs/tabs.component.html | 46 +- .../src/lib/tabs/tabs/tabs.component.ts | 674 +++---- .../src/lib/tabs/tabs/tabs.directives.ts | 22 +- .../src/lib/tabs/tabs/tabs.module.ts | 72 +- .../grid-cell-api/grid-cell-api.sample.css | 150 +- .../grid-cell-api/grid-cell-api.sample.html | 606 +++---- src/app/grid-cell-api/grid-cell-api.sample.ts | 734 ++++---- .../grid-events/grid-events.component.html | 166 +- .../grid-events/grid-events.component.scss | 82 +- src/app/grid-events/grid-events.component.ts | 254 +-- src/app/grid-finjs/controllers.component.html | 66 +- src/app/grid-finjs/controllers.component.scss | 124 +- src/app/grid-finjs/controllers.component.ts | 212 +-- src/app/grid-finjs/main.component.html | 16 +- src/app/grid-finjs/main.component.scss | 42 +- src/app/grid-finjs/main.component.ts | 182 +- src/app/grid-row-api/grid-row-api.sample.css | 150 +- src/app/grid-row-api/grid-row-api.sample.html | 534 +++--- src/app/grid-row-api/grid-row-api.sample.ts | 646 +++---- src/app/grid-updates-test/aminoData.ts | 1104 ++++++------ .../grid-updates.component.html | 48 +- .../grid-updates.component.ts | 172 +- src/web.config | 32 +- 63 files changed, 6072 insertions(+), 6072 deletions(-) diff --git a/README.md b/README.md index eb34de5e27b..cbdc75cd0a0 100644 --- a/README.md +++ b/README.md @@ -1,254 +1,254 @@ -# Ignite UI for Angular - from Infragistics - -![Node.js CI](https://github.com/IgniteUI/igniteui-angular/workflows/Node.js%20CI/badge.svg) -[![Build Status](https://dev.azure.com/IgniteUI/igniteui-angular/_apis/build/status/IgniteUI.igniteui-angular)](https://dev.azure.com/IgniteUI/igniteui-angular/_build/latest?definitionId=3) -[![Coverage Status](https://coveralls.io/repos/github/IgniteUI/igniteui-angular/badge.svg?branch=master)](https://coveralls.io/github/IgniteUI/igniteui-angular?branch=master) -[![npm version](https://badge.fury.io/js/igniteui-angular.svg)](https://badge.fury.io/js/igniteui-angular) -[![Discord](https://img.shields.io/discord/836634487483269200?logo=discord&logoColor=ffffff)](https://discord.gg/39MjrTRqds) - -[Ignite UI for Angular](https://www.infragistics.com/products/ignite-ui-angular) is a complete set of Material-based UI Widgets, Components & Sketch UI kits, supporting directives for [Angular](https://angular.io/) by Infragistics. Ignite UI for Angular is designed to enable developers to build enterprise-ready, high-performance HTML5 & JavaScript apps for modern desktop browsers. With the use of all features, the world’s fastest Angular grid, 60+ real-time Angular charts, and more, you are empowered to engineer excellent mobile experiences and deliver progressive web apps (PWA’s) targeting Google's Angular framework. - -You can find source files under the [`src`](https://github.com/IgniteUI/igniteui-angular/tree/master/src) folder, including samples and tests. - - -### Angular Data Grid Overview - -The Ignite UI for [Angular Data Grid](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid) equips you with all the necessary features for manipulating and visualizing tabular data in a series of rows and columns with ease. You can find powerful grid elements for no-lag scrolling while rendering and going through millions of data points. - -Built for optimization and speed, our [Angular grid](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid) component lets you quickly bind data with very little code and allows you to implement a variety of events in order to tailor different behaviors. - -#### [View running Grid samples here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid) - -### Angular Charts & Graphs Overview - -Ignite UI for Angular arrives with an extensive library of data visualizations that enable stunning, interactive charts and dashboards for your modern web and mobile apps. All of them are designed to work flawlessly on every modern browser and provide complete touch as well as interactivity. Our comprehensive [Angular Charts](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/chart-overview) component supports more than 65 chart types that let you display all sorts of data representations and statistics. And with the rich and easy-to-use API, you can plot various types of charts. - -Some of the Angular chart types included are: [Polar chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/polar-chart), [Pie chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/pie-chart), [Donut chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/donut-chart), [Bubble chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/bubble-chart), [Area chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/area-chart), [Treemap chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/treemap-chart), and many others. And if you look for [Angular financial charts](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/stock-chart), with Ignite UI you can get the same features as the ones you come across with Google Finance and Yahoo Finance Charts. - -### Build Apps with Ignite UI for Angular faster using our [App Builder](https://www.infragistics.com/products/indigo-design/app-builder) -![5661 drag drop](https://user-images.githubusercontent.com/1472513/132676597-09eec222-42f7-40ff-bd0d-fe8b91fd0c1c.gif) -### Generate your Angular code projects using the [App Builder](https://www.infragistics.com/products/indigo-design/app-builder) -![0871 change-preview-code](https://user-images.githubusercontent.com/1472513/132676607-3851f308-416b-45d6-99bc-c34266b55c44.gif) - -### Current List of Components Include: - -|Components|Status|||Directives|Status||| -|:--|:--:|:--|:--|:--|:--:|:--|:--| -|accordion|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/accordion/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/accordion)| -|avatar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/avatar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/avatar)|autocomplete|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/autocomplete/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/autocomplete)| -|badge|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/badge/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/badge)|button|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/button/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button)| -|banner|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/banner/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/banner)|date time editor|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/date-time-editor/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date-time-editor)| -|bottom navigation|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tabs/bottom-nav/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabbar)|divider|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/button/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button)| -|button group|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/buttonGroup/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button-group)|dragdrop|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/divider/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/divider)| -|calendar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/calendar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/calendar)|filter|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/filter/README-FILTER.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list)| -|card|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/card/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/card)|focus-trap|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/focus-trap/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog)| -|carousel|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/carousel/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/carousel)|forOf|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/for-of/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/for-of)| -|checkbox|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/checkbox/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/checkbox)|hint|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| -|chips|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/chips/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/chip)|input|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/input/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| -|circular progress|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/progressbar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/circular-progress)|label|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/label/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/label-input)| -|combo|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/combo/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/combo)|layout|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/layout/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/layout)| -|date picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date-picker)|mask|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/mask/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/mask)| -|date range picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-range-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date-range-picker)|prefix|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| -|dialog|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/dialog/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog)|radio-group|:white_check_mark:||[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio-button)| -|drop down|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/drop-down/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/drop-down)|ripple|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/ripple/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/ripple)| -|expansion panel|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/expansion-panel/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/expansion-panel)|suffix|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| -|grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid)|text-highlight|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-highlight/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/texthighlight)| -|hierarchical grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/hierarchical-grid/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/hierarchicalgrid/hierarchical-grid)|toggle|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/toggle/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toggle)| -|icon|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/icon/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/icon)|tooltip|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/tooltip/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip)| -|input group|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)|Others|Status|Docs|| -|linear progress|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/progressbar)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear-progress)|Animations|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/animations/README.md)|| -|list|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/list/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list)|dataUtil|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATAUTIL.md)|| -|month picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/calendar/month-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/month-picker)|dataContainer|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATACONTAINER.md)|| -|navbar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navbar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navbar)|IgxGridState|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/state-persistence)|| -|navigation drawer|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navigation-drawer/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer)||||| -|pivot grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/pivot-grid/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/pivotgrid/pivot-grid) -|radio|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/radio/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio-button)||||| -|select|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/select/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/select)||||| -|simple-combo|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/simple-combo/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/simple-combo)||||| -|slider|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/slider/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/slider/slider)||||| -|snackbar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/snackbar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/snackbar)||||| -|stepper|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/stepper/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/stepper)| -|switch|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/switch/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/switch)||||| -|tabs|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tabs/tabs/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabs)||||| -|time picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/time-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/time-picker)||||| -|toast|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/toast/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toast)||||| -|tree|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tree/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tree)||||| -|tree grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/tree-grid/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/treegrid/tree-grid)||||| - -### Components available in [igniteui-angular-charts](https://www.npmjs.com/package/igniteui-angular-charts) -|Components|| -|:---|:---| -|Bar Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/bar-chart)| -|Line Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/line-chart)| -|Financial Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/stock-chart)| -|Doughnut Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/donut-chart)| -|Pie Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/pie-chart)| - -### Components available in [igniteui-angular-gauges](https://www.npmjs.com/package/igniteui-angular-gauges) -|Components|| -|:---|:---| -|Bullet Graph|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/bullet-graph)| -|Linear Gauge|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear-gauge)| -|Radial Gauge|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radial-gauge)| - -### Components available in [igniteui-angular-excel](https://www.npmjs.com/package/igniteui-angular-excel) -|Components|| -|:---|:---| -|Excel Library|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/excel-library)| - - -### Components available in [igniteui-angular-spreadsheet](https://www.npmjs.com/package/igniteui-angular-spreadsheet) -|Components|| -|:---|:---| -|Spreadsheet|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/spreadsheet-overview)| - -## Setup -From the root folder run: - -``` -npm install -``` - -## Create new Project with Ignite UI CLI -To get started with the Ignite UI CLI and Ignite UI for Angular: - -``` -npm i -g igniteui-cli -ig new --framework=angular -cd -ig add grid -ig start -``` - -## Adding IgniteUI for Angular to Existing Project - -Including the `igniteui-angular` and `igniteui-cli` packages to your project: - -``` -ng add igniteui-angular -``` - -After this operation you can use the Ignite UI CLI commands in your project, such as `ig` and `ig add`. -[Learn more](https://github.com/IgniteUI/igniteui-cli#usage) - -## Updating Existing Project - -Analyze your project for possible migrations: - -``` -ng update -``` - -If there are new versions available, update your packages: - -``` -ng update igniteui-angular -... -ng update igniteui-cli -``` - -## Building the Library -``` -// build the code -ng build igniteui-angular - -// build the css -npm run build:style - -// build them both -npm run build:lib -``` - -You can find the build ouput under `dist/igniteui-angular`. - -## Running the tests - -Running the tests in watch mode: - -``` -ng test igniteui-angular // or npm run test:lib:watch -``` - -Running the tests once with code coverage enabled: -``` -npm run test:lib -``` - -## Building the API Docs -The API docs are produced using TypeDoc and SassDoc. In order to build the docs, all you need to do is run: - -``` -npm run build:docs -``` - -The output of the API docs build is located under `dist/igniteui-angular/docs`. - -## Run Demos Application - -The repository includes a sample application featuring the showcasing the different components/directives. -In order to run the demo samples, build the library first and start the application. -``` -npm start -``` - -**NOTE**: Experimental demos are not always stable. - -## NPM Package - -You can include Ignite UI for Angular in your project as a dependency using the NPM package. - -`npm install igniteui-angular` - -## Contributing -[General Naming and Coding Guidelines for Ignite UI for Angular](https://github.com/IgniteUI/igniteui-angular/wiki/General-Naming-and-Coding--Guidelines-for-Ignite-UI-for-Angular) - -## Demo Apps & Documentation - -### List of Angular Demo Apps -- [Warehouse Picklist App](https://github.com/IgniteUI/warehouse-js-blocks) - Demonstrates using several Ignite UI for Angular widgets together to build a modern, mobile app. - -- [FinTech Grid App]( https://github.com/Infragistics/angular-samples/tree/master/Grid/FinJS) - The Ignite UI for Angular Grid component is able to handle thousands of updates per second, while keeping the grid responsive for any interaction that the user may undertake. This sample demonstrates the Angular Grid handling thousands of updates per second. - -- [FinTech Tree Grid App](https://github.com/Infragistics/angular-samples/tree/master/TreeGrid/FinJS) - The Ignite UI for Angular Tree Grid component is able to handle thousands of updates per second, while keeping the grid responsive for any interaction that the user may undertake. This sample demonstrates the Tree Grid handling thousands of updates per second. - -- [Crypto Portfolio App](https://github.com/IgniteUI/crypto-portfolio-app) - This is a web and mobile application, developed with Ignite UI for Angular components and styled with our one of a kind theming engine. - -- [Task Planner Application](https://github.com/IgniteUI/TaskPlanner) – Task Planner is an Angular web application. It provides an effective means for managing projects and related tasks. Thus, it loads data from the Web API endpoint, enabling the user to start managing - filtering and sorting tasks, editing tasks, adding new tasks. It shows nice UX UI perks like ability to Drag and Drop items from and to the List and Data Grid. - -- [Dock Manager with Data Analysis Tool](https://github.com/IgniteUI/DockManager-DataAnalysis) - The Data Analysis sample application provides users with the flexibility to customize the data visualization using one of several chart types. Built with Angular UI components, it showcases the Angular Data Grid integrated with an Angular Data Chart, Angular Pie Chart, and an Angular Category Chart, to provide an interactive and engaging visualization. The Dock Manager web component provides a windowing experience, allowing users to customize the layout and view, and make the data more accessible. - -- [COVID-19 Dashboard](https://github.com/IgniteUI/COVID-19-Dashboard) - This dynamic dashboard was built using Indigo.Design and Ignite UI for Angular leveraging timely reports data from CSSEGISandData/COVID-19 to create an useful and impactful visualization. Built in a matter of hours, it showcases the Ignite UI Category and Data Charts, Map and List components for Angular and the how easy it is to get those quickly configured and populated with data. - -- [Inventory Management App](https://github.com/IgniteUI/InventoryManagementApp) - The Inventory Management App consists of 2 pages: The Products Page and the Dashboard Page. The Products Page contains a grid with product information and includes a number of useful features - -### Angular apps with ASP.NET Core Web Application -If you consider Angular client side application with ASP.NET Core application you can check out our [ASP.NET-Core-Samples](https://github.com/IgniteUI/ASP.NET-Core-Samples) - -### Documentation -To get started with the Data Grid, use the steps in the [grid walk-through](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid). - -All help, related API documents and walk-throughs can be found for each control [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/general/getting-started). - - -## Roadmap -[Roadmap document](https://github.com/IgniteUI/igniteui-angular/blob/master/ROADMAP.md) - -## Support -Developer support is provided as part of the commercial, paid-for license via [Infragistics Forums](https://www.infragistics.com/community/forums/), or via Chat & Phone with a Priority Support license. To acquire a license for paid support or Priority Support, please visit this [page](https://www.infragistics.com/how-to-buy/product-pricing#developers). - -Community support for open source usage of this product is available at [StackOverflow](https://stackoverflow.com/questions/tagged/ignite-ui-angular). - -## License -This is a commercial product, requiring a valid paid-for license for commercial use. -This product is free to use for non-commercial educational use for students in K through 12 grades or University programs, and for educators to use in a classroom setting as examples / tools in their curriculum. -In order for us to verify your eligibility for free usage, please [register for trial](https://Infragistics.com/Angular) and open a support ticket with a request for free license. - -To acquire a license for commercial usage, please [register for trial](https://Infragistics.com/Angular) and refer to the purchasing options in the pricing section on the product page. - -© Copyright 2020 INFRAGISTICS. All Rights Reserved. -The Infragistics Ultimate license & copyright applies to this distribution. -For information on that license, please go to our website [https://www.infragistics.com/legal/license](https://www.infragistics.com/legal/license). - - - - +# Ignite UI for Angular - from Infragistics + +![Node.js CI](https://github.com/IgniteUI/igniteui-angular/workflows/Node.js%20CI/badge.svg) +[![Build Status](https://dev.azure.com/IgniteUI/igniteui-angular/_apis/build/status/IgniteUI.igniteui-angular)](https://dev.azure.com/IgniteUI/igniteui-angular/_build/latest?definitionId=3) +[![Coverage Status](https://coveralls.io/repos/github/IgniteUI/igniteui-angular/badge.svg?branch=master)](https://coveralls.io/github/IgniteUI/igniteui-angular?branch=master) +[![npm version](https://badge.fury.io/js/igniteui-angular.svg)](https://badge.fury.io/js/igniteui-angular) +[![Discord](https://img.shields.io/discord/836634487483269200?logo=discord&logoColor=ffffff)](https://discord.gg/39MjrTRqds) + +[Ignite UI for Angular](https://www.infragistics.com/products/ignite-ui-angular) is a complete set of Material-based UI Widgets, Components & Sketch UI kits, supporting directives for [Angular](https://angular.io/) by Infragistics. Ignite UI for Angular is designed to enable developers to build enterprise-ready, high-performance HTML5 & JavaScript apps for modern desktop browsers. With the use of all features, the world’s fastest Angular grid, 60+ real-time Angular charts, and more, you are empowered to engineer excellent mobile experiences and deliver progressive web apps (PWA’s) targeting Google's Angular framework. + +You can find source files under the [`src`](https://github.com/IgniteUI/igniteui-angular/tree/master/src) folder, including samples and tests. + + +### Angular Data Grid Overview + +The Ignite UI for [Angular Data Grid](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid) equips you with all the necessary features for manipulating and visualizing tabular data in a series of rows and columns with ease. You can find powerful grid elements for no-lag scrolling while rendering and going through millions of data points. + +Built for optimization and speed, our [Angular grid](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid) component lets you quickly bind data with very little code and allows you to implement a variety of events in order to tailor different behaviors. + +#### [View running Grid samples here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid) + +### Angular Charts & Graphs Overview + +Ignite UI for Angular arrives with an extensive library of data visualizations that enable stunning, interactive charts and dashboards for your modern web and mobile apps. All of them are designed to work flawlessly on every modern browser and provide complete touch as well as interactivity. Our comprehensive [Angular Charts](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/chart-overview) component supports more than 65 chart types that let you display all sorts of data representations and statistics. And with the rich and easy-to-use API, you can plot various types of charts. + +Some of the Angular chart types included are: [Polar chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/polar-chart), [Pie chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/pie-chart), [Donut chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/donut-chart), [Bubble chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/bubble-chart), [Area chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/area-chart), [Treemap chart](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/treemap-chart), and many others. And if you look for [Angular financial charts](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/stock-chart), with Ignite UI you can get the same features as the ones you come across with Google Finance and Yahoo Finance Charts. + +### Build Apps with Ignite UI for Angular faster using our [App Builder](https://www.infragistics.com/products/indigo-design/app-builder) +![5661 drag drop](https://user-images.githubusercontent.com/1472513/132676597-09eec222-42f7-40ff-bd0d-fe8b91fd0c1c.gif) +### Generate your Angular code projects using the [App Builder](https://www.infragistics.com/products/indigo-design/app-builder) +![0871 change-preview-code](https://user-images.githubusercontent.com/1472513/132676607-3851f308-416b-45d6-99bc-c34266b55c44.gif) + +### Current List of Components Include: + +|Components|Status|||Directives|Status||| +|:--|:--:|:--|:--|:--|:--:|:--|:--| +|accordion|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/accordion/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/accordion)| +|avatar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/avatar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/avatar)|autocomplete|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/autocomplete/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/autocomplete)| +|badge|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/badge/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/badge)|button|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/button/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button)| +|banner|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/banner/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/banner)|date time editor|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/date-time-editor/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date-time-editor)| +|bottom navigation|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tabs/bottom-nav/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabbar)|divider|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/button/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button)| +|button group|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/buttonGroup/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/button-group)|dragdrop|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/divider/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/divider)| +|calendar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/calendar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/calendar)|filter|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/filter/README-FILTER.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list)| +|card|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/card/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/card)|focus-trap|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/focus-trap/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog)| +|carousel|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/carousel/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/carousel)|forOf|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/for-of/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/for-of)| +|checkbox|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/checkbox/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/checkbox)|hint|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| +|chips|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/chips/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/chip)|input|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/input/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| +|circular progress|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/progressbar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/circular-progress)|label|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/label/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/label-input)| +|combo|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/combo/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/combo)|layout|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/layout/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/layout)| +|date picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date-picker)|mask|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/mask/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/mask)| +|date range picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/date-range-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/date-range-picker)|prefix|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| +|dialog|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/dialog/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/dialog)|radio-group|:white_check_mark:||[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio-button)| +|drop down|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/drop-down/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/drop-down)|ripple|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/ripple/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/ripple)| +|expansion panel|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/expansion-panel/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/expansion-panel)|suffix|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)| +|grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid)|text-highlight|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/directives/text-highlight/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/texthighlight)| +|hierarchical grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/hierarchical-grid/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/hierarchicalgrid/hierarchical-grid)|toggle|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/toggle/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toggle)| +|icon|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/icon/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/icon)|tooltip|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/directives/tooltip/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tooltip)| +|input group|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/input-group/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/input-group)|Others|Status|Docs|| +|linear progress|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/tree/master/projects/igniteui-angular/src/lib/progressbar)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear-progress)|Animations|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/animations/README.md)|| +|list|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/list/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/list)|dataUtil|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATAUTIL.md)|| +|month picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/calendar/month-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/month-picker)|dataContainer|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/data-operations/README-DATACONTAINER.md)|| +|navbar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navbar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navbar)|IgxGridState|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/state-persistence)|| +|navigation drawer|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/navigation-drawer/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer)||||| +|pivot grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/pivot-grid/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/pivotgrid/pivot-grid) +|radio|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/radio/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radio-button)||||| +|select|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/select/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/select)||||| +|simple-combo|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/simple-combo/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/simple-combo)||||| +|slider|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/slider/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/slider/slider)||||| +|snackbar|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/snackbar/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/snackbar)||||| +|stepper|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/stepper/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/stepper)| +|switch|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/switch/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/switch)||||| +|tabs|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tabs/tabs/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tabs)||||| +|time picker|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/time-picker/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/time-picker)||||| +|toast|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/toast/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/toast)||||| +|tree|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/tree/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/tree)||||| +|tree grid|:white_check_mark:|[Readme](https://github.com/IgniteUI/igniteui-angular/blob/master/projects/igniteui-angular/src/lib/grids/tree-grid/README.md)|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/treegrid/tree-grid)||||| + +### Components available in [igniteui-angular-charts](https://www.npmjs.com/package/igniteui-angular-charts) +|Components|| +|:---|:---| +|Bar Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/bar-chart)| +|Line Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/line-chart)| +|Financial Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/stock-chart)| +|Doughnut Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/donut-chart)| +|Pie Chart|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/charts/types/pie-chart)| + +### Components available in [igniteui-angular-gauges](https://www.npmjs.com/package/igniteui-angular-gauges) +|Components|| +|:---|:---| +|Bullet Graph|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/bullet-graph)| +|Linear Gauge|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/linear-gauge)| +|Radial Gauge|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/radial-gauge)| + +### Components available in [igniteui-angular-excel](https://www.npmjs.com/package/igniteui-angular-excel) +|Components|| +|:---|:---| +|Excel Library|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/excel-library)| + + +### Components available in [igniteui-angular-spreadsheet](https://www.npmjs.com/package/igniteui-angular-spreadsheet) +|Components|| +|:---|:---| +|Spreadsheet|[Docs](https://www.infragistics.com/products/ignite-ui-angular/angular/components/spreadsheet-overview)| + +## Setup +From the root folder run: + +``` +npm install +``` + +## Create new Project with Ignite UI CLI +To get started with the Ignite UI CLI and Ignite UI for Angular: + +``` +npm i -g igniteui-cli +ig new --framework=angular +cd +ig add grid +ig start +``` + +## Adding IgniteUI for Angular to Existing Project + +Including the `igniteui-angular` and `igniteui-cli` packages to your project: + +``` +ng add igniteui-angular +``` + +After this operation you can use the Ignite UI CLI commands in your project, such as `ig` and `ig add`. +[Learn more](https://github.com/IgniteUI/igniteui-cli#usage) + +## Updating Existing Project + +Analyze your project for possible migrations: + +``` +ng update +``` + +If there are new versions available, update your packages: + +``` +ng update igniteui-angular +... +ng update igniteui-cli +``` + +## Building the Library +``` +// build the code +ng build igniteui-angular + +// build the css +npm run build:style + +// build them both +npm run build:lib +``` + +You can find the build ouput under `dist/igniteui-angular`. + +## Running the tests + +Running the tests in watch mode: + +``` +ng test igniteui-angular // or npm run test:lib:watch +``` + +Running the tests once with code coverage enabled: +``` +npm run test:lib +``` + +## Building the API Docs +The API docs are produced using TypeDoc and SassDoc. In order to build the docs, all you need to do is run: + +``` +npm run build:docs +``` + +The output of the API docs build is located under `dist/igniteui-angular/docs`. + +## Run Demos Application + +The repository includes a sample application featuring the showcasing the different components/directives. +In order to run the demo samples, build the library first and start the application. +``` +npm start +``` + +**NOTE**: Experimental demos are not always stable. + +## NPM Package + +You can include Ignite UI for Angular in your project as a dependency using the NPM package. + +`npm install igniteui-angular` + +## Contributing +[General Naming and Coding Guidelines for Ignite UI for Angular](https://github.com/IgniteUI/igniteui-angular/wiki/General-Naming-and-Coding--Guidelines-for-Ignite-UI-for-Angular) + +## Demo Apps & Documentation + +### List of Angular Demo Apps +- [Warehouse Picklist App](https://github.com/IgniteUI/warehouse-js-blocks) - Demonstrates using several Ignite UI for Angular widgets together to build a modern, mobile app. + +- [FinTech Grid App]( https://github.com/Infragistics/angular-samples/tree/master/Grid/FinJS) - The Ignite UI for Angular Grid component is able to handle thousands of updates per second, while keeping the grid responsive for any interaction that the user may undertake. This sample demonstrates the Angular Grid handling thousands of updates per second. + +- [FinTech Tree Grid App](https://github.com/Infragistics/angular-samples/tree/master/TreeGrid/FinJS) - The Ignite UI for Angular Tree Grid component is able to handle thousands of updates per second, while keeping the grid responsive for any interaction that the user may undertake. This sample demonstrates the Tree Grid handling thousands of updates per second. + +- [Crypto Portfolio App](https://github.com/IgniteUI/crypto-portfolio-app) - This is a web and mobile application, developed with Ignite UI for Angular components and styled with our one of a kind theming engine. + +- [Task Planner Application](https://github.com/IgniteUI/TaskPlanner) – Task Planner is an Angular web application. It provides an effective means for managing projects and related tasks. Thus, it loads data from the Web API endpoint, enabling the user to start managing - filtering and sorting tasks, editing tasks, adding new tasks. It shows nice UX UI perks like ability to Drag and Drop items from and to the List and Data Grid. + +- [Dock Manager with Data Analysis Tool](https://github.com/IgniteUI/DockManager-DataAnalysis) - The Data Analysis sample application provides users with the flexibility to customize the data visualization using one of several chart types. Built with Angular UI components, it showcases the Angular Data Grid integrated with an Angular Data Chart, Angular Pie Chart, and an Angular Category Chart, to provide an interactive and engaging visualization. The Dock Manager web component provides a windowing experience, allowing users to customize the layout and view, and make the data more accessible. + +- [COVID-19 Dashboard](https://github.com/IgniteUI/COVID-19-Dashboard) - This dynamic dashboard was built using Indigo.Design and Ignite UI for Angular leveraging timely reports data from CSSEGISandData/COVID-19 to create an useful and impactful visualization. Built in a matter of hours, it showcases the Ignite UI Category and Data Charts, Map and List components for Angular and the how easy it is to get those quickly configured and populated with data. + +- [Inventory Management App](https://github.com/IgniteUI/InventoryManagementApp) - The Inventory Management App consists of 2 pages: The Products Page and the Dashboard Page. The Products Page contains a grid with product information and includes a number of useful features + +### Angular apps with ASP.NET Core Web Application +If you consider Angular client side application with ASP.NET Core application you can check out our [ASP.NET-Core-Samples](https://github.com/IgniteUI/ASP.NET-Core-Samples) + +### Documentation +To get started with the Data Grid, use the steps in the [grid walk-through](https://www.infragistics.com/products/ignite-ui-angular/angular/components/grid/grid). + +All help, related API documents and walk-throughs can be found for each control [here](https://www.infragistics.com/products/ignite-ui-angular/angular/components/general/getting-started). + + +## Roadmap +[Roadmap document](https://github.com/IgniteUI/igniteui-angular/blob/master/ROADMAP.md) + +## Support +Developer support is provided as part of the commercial, paid-for license via [Infragistics Forums](https://www.infragistics.com/community/forums/), or via Chat & Phone with a Priority Support license. To acquire a license for paid support or Priority Support, please visit this [page](https://www.infragistics.com/how-to-buy/product-pricing#developers). + +Community support for open source usage of this product is available at [StackOverflow](https://stackoverflow.com/questions/tagged/ignite-ui-angular). + +## License +This is a commercial product, requiring a valid paid-for license for commercial use. +This product is free to use for non-commercial educational use for students in K through 12 grades or University programs, and for educators to use in a classroom setting as examples / tools in their curriculum. +In order for us to verify your eligibility for free usage, please [register for trial](https://Infragistics.com/Angular) and open a support ticket with a request for free license. + +To acquire a license for commercial usage, please [register for trial](https://Infragistics.com/Angular) and refer to the purchasing options in the pricing section on the product page. + +© Copyright 2020 INFRAGISTICS. All Rights Reserved. +The Infragistics Ultimate license & copyright applies to this distribution. +For information on that license, please go to our website [https://www.infragistics.com/legal/license](https://www.infragistics.com/legal/license). + + + + diff --git a/projects/igniteui-angular/migrations/update-12_1_0/changes/classes.json b/projects/igniteui-angular/migrations/update-12_1_0/changes/classes.json index 8364bb4a435..510bfff0e00 100644 --- a/projects/igniteui-angular/migrations/update-12_1_0/changes/classes.json +++ b/projects/igniteui-angular/migrations/update-12_1_0/changes/classes.json @@ -1,28 +1,28 @@ -{ - "$schema": "../../common/schema/class.schema.json", - "changes": [{ - "name": "IgxHierarchicalGridCellComponent", - "replaceWith": "CellType" - }, - { - "name": "IgxGridCellComponent", - "replaceWith": "CellType" - }, - { - "name": "IgxTreeGridCellComponent", - "replaceWith": "CellType" - }, - { - "name": "IgxGridExpandableCellComponent", - "replaceWith": "CellType" - }, - { - "name": "IComboSelectionChangeEventArgs", - "replaceWith": "IComboSelectionChangingEventArgs" - }, - { - "name": "AutocompleteItemSelectionEventArgs", - "replaceWith": "AutocompleteSelectionChangingEventArgs" - } - ] -} +{ + "$schema": "../../common/schema/class.schema.json", + "changes": [{ + "name": "IgxHierarchicalGridCellComponent", + "replaceWith": "CellType" + }, + { + "name": "IgxGridCellComponent", + "replaceWith": "CellType" + }, + { + "name": "IgxTreeGridCellComponent", + "replaceWith": "CellType" + }, + { + "name": "IgxGridExpandableCellComponent", + "replaceWith": "CellType" + }, + { + "name": "IComboSelectionChangeEventArgs", + "replaceWith": "IComboSelectionChangingEventArgs" + }, + { + "name": "AutocompleteItemSelectionEventArgs", + "replaceWith": "AutocompleteSelectionChangingEventArgs" + } + ] +} diff --git a/projects/igniteui-angular/src/lib/carousel/carousel-base.ts b/projects/igniteui-angular/src/lib/carousel/carousel-base.ts index 2c1cea690cc..947dacaefc3 100644 --- a/projects/igniteui-angular/src/lib/carousel/carousel-base.ts +++ b/projects/igniteui-angular/src/lib/carousel/carousel-base.ts @@ -1,189 +1,189 @@ -import { AnimationBuilder, AnimationPlayer, AnimationReferenceMetadata, useAnimation } from '@angular/animations'; -import { ChangeDetectorRef, EventEmitter } from '@angular/core'; -import { fadeIn } from '../animations/fade'; -import { slideInLeft } from '../animations/slide'; -import { mkenum } from '../core/utils'; - -export enum Direction { NONE, NEXT, PREV } - -export const HorizontalAnimationType = mkenum({ - none: 'none', - slide: 'slide', - fade: 'fade' -}); -export type HorizontalAnimationType = (typeof HorizontalAnimationType)[keyof typeof HorizontalAnimationType]; - -export interface CarouselAnimationSettings { - enterAnimation: AnimationReferenceMetadata; - leaveAnimation: AnimationReferenceMetadata; -} - -/** @hidden */ -export interface IgxSlideComponentBase { - direction: Direction; - previous: boolean; -} - -/** @hidden */ -export abstract class IgxCarouselComponentBase { - /** @hidden */ - public animationType: HorizontalAnimationType = HorizontalAnimationType.slide; - - /** @hidden @internal */ - public enterAnimationDone = new EventEmitter(); - /** @hidden @internal */ - public leaveAnimationDone = new EventEmitter(); - - /** @hidden */ - protected currentItem: IgxSlideComponentBase; - /** @hidden */ - protected previousItem: IgxSlideComponentBase; - /** @hidden */ - protected enterAnimationPlayer?: AnimationPlayer; - /** @hidden */ - protected leaveAnimationPlayer?: AnimationPlayer; - /** @hidden */ - protected defaultAnimationDuration = 320; - /** @hidden */ - protected animationPosition = 0; - /** @hidden */ - protected newDuration = 0; - - constructor(private builder: AnimationBuilder, private cdr: ChangeDetectorRef) { - } - - /** @hidden */ - protected triggerAnimations() { - if (this.animationType !== HorizontalAnimationType.none) { - if (this.animationStarted(this.leaveAnimationPlayer) || this.animationStarted(this.enterAnimationPlayer)) { - requestAnimationFrame(() => { - this.resetAnimations(); - this.playAnimations(); - }); - } else { - this.playAnimations(); - } - } - } - - /** @hidden */ - protected animationStarted(animation: AnimationPlayer): boolean { - return animation && animation.hasStarted(); - } - - /** @hidden */ - protected playAnimations() { - this.playLeaveAnimation(); - this.playEnterAnimation(); - } - - private resetAnimations() { - if (this.animationStarted(this.leaveAnimationPlayer)) { - this.leaveAnimationPlayer.reset(); - this.leaveAnimationDone.emit(); - } - - if (this.animationStarted(this.enterAnimationPlayer)) { - this.enterAnimationPlayer.reset(); - this.enterAnimationDone.emit(); - this.cdr.markForCheck(); - } - } - - private getAnimation(): CarouselAnimationSettings { - let duration; - if (this.newDuration) { - duration = this.animationPosition ? this.animationPosition * this.newDuration : this.newDuration; - } else { - duration = this.animationPosition ? this.animationPosition * this.defaultAnimationDuration : this.defaultAnimationDuration; - } - - switch (this.animationType) { - case HorizontalAnimationType.slide: - const trans = this.animationPosition ? this.animationPosition * 100 : 100; - return { - enterAnimation: useAnimation(slideInLeft, - { - params: { - delay: '0s', - duration: `${duration}ms`, - endOpacity: 1, - startOpacity: 1, - fromPosition: `translateX(${this.currentItem.direction === 1 ? trans : -trans}%)`, - toPosition: 'translateX(0%)' - } - }), - leaveAnimation: useAnimation(slideInLeft, - { - params: { - delay: '0s', - duration: `${duration}ms`, - endOpacity: 1, - startOpacity: 1, - fromPosition: `translateX(0%)`, - toPosition: `translateX(${this.currentItem.direction === 1 ? -trans : trans}%)`, - } - }) - }; - case HorizontalAnimationType.fade: - return { - enterAnimation: useAnimation(fadeIn, - { params: { duration: `${duration}ms`, startOpacity: `${this.animationPosition}` } }), - leaveAnimation: null - }; - } - return { - enterAnimation: null, - leaveAnimation: null - }; - } - - private playEnterAnimation() { - const animation = this.getAnimation().enterAnimation; - if (!animation) { - return; - } - const animationBuilder = this.builder.build(animation); - - this.enterAnimationPlayer = animationBuilder.create(this.getCurrentElement()); - - this.enterAnimationPlayer.onDone(() => { - if (this.enterAnimationPlayer) { - this.enterAnimationPlayer.reset(); - this.enterAnimationPlayer = null; - } - this.animationPosition = 0; - this.newDuration = 0; - this.previousItem.previous = false; - this.enterAnimationDone.emit(); - this.cdr.markForCheck(); - }); - this.previousItem.previous = true; - this.enterAnimationPlayer.play(); - } - - private playLeaveAnimation() { - const animation = this.getAnimation().leaveAnimation; - if (!animation) { - return; - } - - const animationBuilder = this.builder.build(animation); - this.leaveAnimationPlayer = animationBuilder.create(this.getPreviousElement()); - - this.leaveAnimationPlayer.onDone(() => { - if (this.leaveAnimationPlayer) { - this.leaveAnimationPlayer.reset(); - this.leaveAnimationPlayer = null; - } - this.animationPosition = 0; - this.newDuration = 0; - this.leaveAnimationDone.emit(); - }); - this.leaveAnimationPlayer.play(); - } - - protected abstract getPreviousElement(): HTMLElement; - - protected abstract getCurrentElement(): HTMLElement; -} +import { AnimationBuilder, AnimationPlayer, AnimationReferenceMetadata, useAnimation } from '@angular/animations'; +import { ChangeDetectorRef, EventEmitter } from '@angular/core'; +import { fadeIn } from '../animations/fade'; +import { slideInLeft } from '../animations/slide'; +import { mkenum } from '../core/utils'; + +export enum Direction { NONE, NEXT, PREV } + +export const HorizontalAnimationType = mkenum({ + none: 'none', + slide: 'slide', + fade: 'fade' +}); +export type HorizontalAnimationType = (typeof HorizontalAnimationType)[keyof typeof HorizontalAnimationType]; + +export interface CarouselAnimationSettings { + enterAnimation: AnimationReferenceMetadata; + leaveAnimation: AnimationReferenceMetadata; +} + +/** @hidden */ +export interface IgxSlideComponentBase { + direction: Direction; + previous: boolean; +} + +/** @hidden */ +export abstract class IgxCarouselComponentBase { + /** @hidden */ + public animationType: HorizontalAnimationType = HorizontalAnimationType.slide; + + /** @hidden @internal */ + public enterAnimationDone = new EventEmitter(); + /** @hidden @internal */ + public leaveAnimationDone = new EventEmitter(); + + /** @hidden */ + protected currentItem: IgxSlideComponentBase; + /** @hidden */ + protected previousItem: IgxSlideComponentBase; + /** @hidden */ + protected enterAnimationPlayer?: AnimationPlayer; + /** @hidden */ + protected leaveAnimationPlayer?: AnimationPlayer; + /** @hidden */ + protected defaultAnimationDuration = 320; + /** @hidden */ + protected animationPosition = 0; + /** @hidden */ + protected newDuration = 0; + + constructor(private builder: AnimationBuilder, private cdr: ChangeDetectorRef) { + } + + /** @hidden */ + protected triggerAnimations() { + if (this.animationType !== HorizontalAnimationType.none) { + if (this.animationStarted(this.leaveAnimationPlayer) || this.animationStarted(this.enterAnimationPlayer)) { + requestAnimationFrame(() => { + this.resetAnimations(); + this.playAnimations(); + }); + } else { + this.playAnimations(); + } + } + } + + /** @hidden */ + protected animationStarted(animation: AnimationPlayer): boolean { + return animation && animation.hasStarted(); + } + + /** @hidden */ + protected playAnimations() { + this.playLeaveAnimation(); + this.playEnterAnimation(); + } + + private resetAnimations() { + if (this.animationStarted(this.leaveAnimationPlayer)) { + this.leaveAnimationPlayer.reset(); + this.leaveAnimationDone.emit(); + } + + if (this.animationStarted(this.enterAnimationPlayer)) { + this.enterAnimationPlayer.reset(); + this.enterAnimationDone.emit(); + this.cdr.markForCheck(); + } + } + + private getAnimation(): CarouselAnimationSettings { + let duration; + if (this.newDuration) { + duration = this.animationPosition ? this.animationPosition * this.newDuration : this.newDuration; + } else { + duration = this.animationPosition ? this.animationPosition * this.defaultAnimationDuration : this.defaultAnimationDuration; + } + + switch (this.animationType) { + case HorizontalAnimationType.slide: + const trans = this.animationPosition ? this.animationPosition * 100 : 100; + return { + enterAnimation: useAnimation(slideInLeft, + { + params: { + delay: '0s', + duration: `${duration}ms`, + endOpacity: 1, + startOpacity: 1, + fromPosition: `translateX(${this.currentItem.direction === 1 ? trans : -trans}%)`, + toPosition: 'translateX(0%)' + } + }), + leaveAnimation: useAnimation(slideInLeft, + { + params: { + delay: '0s', + duration: `${duration}ms`, + endOpacity: 1, + startOpacity: 1, + fromPosition: `translateX(0%)`, + toPosition: `translateX(${this.currentItem.direction === 1 ? -trans : trans}%)`, + } + }) + }; + case HorizontalAnimationType.fade: + return { + enterAnimation: useAnimation(fadeIn, + { params: { duration: `${duration}ms`, startOpacity: `${this.animationPosition}` } }), + leaveAnimation: null + }; + } + return { + enterAnimation: null, + leaveAnimation: null + }; + } + + private playEnterAnimation() { + const animation = this.getAnimation().enterAnimation; + if (!animation) { + return; + } + const animationBuilder = this.builder.build(animation); + + this.enterAnimationPlayer = animationBuilder.create(this.getCurrentElement()); + + this.enterAnimationPlayer.onDone(() => { + if (this.enterAnimationPlayer) { + this.enterAnimationPlayer.reset(); + this.enterAnimationPlayer = null; + } + this.animationPosition = 0; + this.newDuration = 0; + this.previousItem.previous = false; + this.enterAnimationDone.emit(); + this.cdr.markForCheck(); + }); + this.previousItem.previous = true; + this.enterAnimationPlayer.play(); + } + + private playLeaveAnimation() { + const animation = this.getAnimation().leaveAnimation; + if (!animation) { + return; + } + + const animationBuilder = this.builder.build(animation); + this.leaveAnimationPlayer = animationBuilder.create(this.getPreviousElement()); + + this.leaveAnimationPlayer.onDone(() => { + if (this.leaveAnimationPlayer) { + this.leaveAnimationPlayer.reset(); + this.leaveAnimationPlayer = null; + } + this.animationPosition = 0; + this.newDuration = 0; + this.leaveAnimationDone.emit(); + }); + this.leaveAnimationPlayer.play(); + } + + protected abstract getPreviousElement(): HTMLElement; + + protected abstract getCurrentElement(): HTMLElement; +} diff --git a/projects/igniteui-angular/src/lib/carousel/public_api.ts b/projects/igniteui-angular/src/lib/carousel/public_api.ts index 4e82234d664..619ce8843f6 100644 --- a/projects/igniteui-angular/src/lib/carousel/public_api.ts +++ b/projects/igniteui-angular/src/lib/carousel/public_api.ts @@ -1,4 +1,4 @@ -export * from './carousel-base'; -export * from './carousel.component'; -export * from './slide.component'; -export * from './carousel.directives'; +export * from './carousel-base'; +export * from './carousel.component'; +export * from './slide.component'; +export * from './carousel.directives'; diff --git a/projects/igniteui-angular/src/lib/date-common/calendar-container/calendar-container.component.ts b/projects/igniteui-angular/src/lib/date-common/calendar-container/calendar-container.component.ts index c033a290dd6..63ef36a3e75 100644 --- a/projects/igniteui-angular/src/lib/date-common/calendar-container/calendar-container.component.ts +++ b/projects/igniteui-angular/src/lib/date-common/calendar-container/calendar-container.component.ts @@ -54,14 +54,14 @@ export class IgxCalendarContainerComponent { } /** @hidden */ -@NgModule({ - declarations: [IgxCalendarContainerComponent], - imports: [ - CommonModule, - IgxButtonModule, - IgxRippleModule, - IgxCalendarModule - ], - exports: [IgxCalendarContainerComponent] +@NgModule({ + declarations: [IgxCalendarContainerComponent], + imports: [ + CommonModule, + IgxButtonModule, + IgxRippleModule, + IgxCalendarModule + ], + exports: [IgxCalendarContainerComponent] }) export class IgxCalendarContainerModule { } diff --git a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts index 8fe07384e6c..e39d2a3a38c 100644 --- a/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts +++ b/projects/igniteui-angular/src/lib/directives/for-of/for_of.directive.ts @@ -1804,17 +1804,17 @@ export class IgxGridForOfDirective extends IgxForOfDirective implements On /** * @hidden */ -@NgModule({ - declarations: [ - IgxForOfDirective, - IgxGridForOfDirective, - DisplayContainerComponent, - VirtualHelperComponent, - HVirtualHelperComponent, - VirtualHelperBaseDirective - ], - exports: [IgxForOfDirective, IgxGridForOfDirective], - imports: [IgxScrollInertiaModule, CommonModule] +@NgModule({ + declarations: [ + IgxForOfDirective, + IgxGridForOfDirective, + DisplayContainerComponent, + VirtualHelperComponent, + HVirtualHelperComponent, + VirtualHelperBaseDirective + ], + exports: [IgxForOfDirective, IgxGridForOfDirective], + imports: [IgxScrollInertiaModule, CommonModule] }) export class IgxForOfModule { diff --git a/projects/igniteui-angular/src/lib/grids/columns/column.module.ts b/projects/igniteui-angular/src/lib/grids/columns/column.module.ts index 8f1e93fb6fc..6984c832816 100644 --- a/projects/igniteui-angular/src/lib/grids/columns/column.module.ts +++ b/projects/igniteui-angular/src/lib/grids/columns/column.module.ts @@ -12,30 +12,30 @@ import { IgxSummaryTemplateDirective } from './templates.directive'; -@NgModule({ - declarations: [ - IgxFilterCellTemplateDirective, - IgxSummaryTemplateDirective, - IgxCellTemplateDirective, - IgxCellHeaderTemplateDirective, - IgxCellFooterTemplateDirective, - IgxCellEditorTemplateDirective, - IgxCollapsibleIndicatorTemplateDirective, - IgxColumnComponent, - IgxColumnGroupComponent, - IgxColumnLayoutComponent - ], - exports: [ - IgxFilterCellTemplateDirective, - IgxSummaryTemplateDirective, - IgxCellTemplateDirective, - IgxCellHeaderTemplateDirective, - IgxCellFooterTemplateDirective, - IgxCellEditorTemplateDirective, - IgxCollapsibleIndicatorTemplateDirective, - IgxColumnComponent, - IgxColumnGroupComponent, - IgxColumnLayoutComponent - ] +@NgModule({ + declarations: [ + IgxFilterCellTemplateDirective, + IgxSummaryTemplateDirective, + IgxCellTemplateDirective, + IgxCellHeaderTemplateDirective, + IgxCellFooterTemplateDirective, + IgxCellEditorTemplateDirective, + IgxCollapsibleIndicatorTemplateDirective, + IgxColumnComponent, + IgxColumnGroupComponent, + IgxColumnLayoutComponent + ], + exports: [ + IgxFilterCellTemplateDirective, + IgxSummaryTemplateDirective, + IgxCellTemplateDirective, + IgxCellHeaderTemplateDirective, + IgxCellFooterTemplateDirective, + IgxCellEditorTemplateDirective, + IgxCollapsibleIndicatorTemplateDirective, + IgxColumnComponent, + IgxColumnGroupComponent, + IgxColumnLayoutComponent + ] }) export class IgxGridColumnModule {} diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.html b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.html index 53962038668..3771b6d6605 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.html +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.html @@ -1,28 +1,28 @@ -
-

{{ esf.column.header || esf.column.field }}

-
- - - -
-
+
+

{{ esf.column.header || esf.column.field }}

+
+ + + +
+
diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.ts index 4072a4761f2..608e6990c95 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/excel-style-header.component.ts @@ -1,49 +1,49 @@ -import { Component, Input } from '@angular/core'; -import { BaseFilteringComponent } from './base-filtering.component'; - -/** - * A component used for presenting Excel style header UI. - */ -@Component({ - selector: 'igx-excel-style-header', - templateUrl: './excel-style-header.component.html' -}) -export class IgxExcelStyleHeaderComponent { - /** - * Sets whether the column pinning icon should be shown in the header. - * Default value is `false`. - * - * @example - * ```html - * - * ``` - */ - @Input() - public showPinning: boolean; - - /** - * Sets whether the column selecting icon should be shown in the header. - * Default value is `false`. - * - * @example - * ```html - * - * ``` - */ - @Input() - public showSelecting: boolean; - - /** - * Sets whether the column hiding icon should be shown in the header. - * Default value is `false`. - * - * @example - * ```html - * - * ``` - */ - @Input() - public showHiding: boolean; - - constructor(public esf: BaseFilteringComponent) { } -} +import { Component, Input } from '@angular/core'; +import { BaseFilteringComponent } from './base-filtering.component'; + +/** + * A component used for presenting Excel style header UI. + */ +@Component({ + selector: 'igx-excel-style-header', + templateUrl: './excel-style-header.component.html' +}) +export class IgxExcelStyleHeaderComponent { + /** + * Sets whether the column pinning icon should be shown in the header. + * Default value is `false`. + * + * @example + * ```html + * + * ``` + */ + @Input() + public showPinning: boolean; + + /** + * Sets whether the column selecting icon should be shown in the header. + * Default value is `false`. + * + * @example + * ```html + * + * ``` + */ + @Input() + public showSelecting: boolean; + + /** + * Sets whether the column hiding icon should be shown in the header. + * Default value is `false`. + * + * @example + * ```html + * + * ``` + */ + @Input() + public showHiding: boolean; + + constructor(public esf: BaseFilteringComponent) { } +} diff --git a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/public_api.ts b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/public_api.ts index 2726dafafa6..4de549833cf 100644 --- a/projects/igniteui-angular/src/lib/grids/filtering/excel-style/public_api.ts +++ b/projects/igniteui-angular/src/lib/grids/filtering/excel-style/public_api.ts @@ -1,11 +1,11 @@ -export * from './excel-style-clear-filters.component'; -export * from './excel-style-conditional-filter.component'; -export * from './excel-style-header.component'; -export * from './excel-style-hiding.component'; -export * from './excel-style-moving.component'; -export * from './excel-style-pinning.component'; -export * from './excel-style-search.component'; -export * from './excel-style-selecting.component'; -export * from './excel-style-sorting.component'; -export * from './grid.excel-style-filtering.component'; -export * from './excel-style-date-expression.component'; +export * from './excel-style-clear-filters.component'; +export * from './excel-style-conditional-filter.component'; +export * from './excel-style-header.component'; +export * from './excel-style-hiding.component'; +export * from './excel-style-moving.component'; +export * from './excel-style-pinning.component'; +export * from './excel-style-search.component'; +export * from './excel-style-selecting.component'; +export * from './excel-style-sorting.component'; +export * from './grid.excel-style-filtering.component'; +export * from './excel-style-date-expression.component'; diff --git a/projects/igniteui-angular/src/lib/grids/grid-common.module.ts b/projects/igniteui-angular/src/lib/grids/grid-common.module.ts index 5599a24a64e..cb7af853cbf 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-common.module.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-common.module.ts @@ -45,80 +45,80 @@ import { IgxGroupByMetaPipe } from './grouping/group-by-area.directive'; /** * @hidden */ -@NgModule({ - declarations: [ - IgxRowDirective, - IgxGridCellComponent, - IgxRowAddTextDirective, - IgxRowEditTemplateDirective, - IgxRowEditActionsDirective, - IgxRowEditTextDirective, - IgxRowEditTabStopDirective, - IgxGridBodyDirective, - IgxGridFooterComponent, - IgxAdvancedFilteringDialogComponent, - IgxRowExpandedIndicatorDirective, - IgxRowCollapsedIndicatorDirective, - IgxHeaderExpandIndicatorDirective, - IgxHeaderCollapseIndicatorDirective, - IgxExcelStyleHeaderIconDirective, - IgxSortAscendingHeaderIconDirective, - IgxSortDescendingHeaderIconDirective, - IgxSortHeaderIconDirective, - IgxGroupAreaDropDirective, - IgxGroupByMetaPipe - ], - exports: [ - IgxGridCellComponent, - IgxRowAddTextDirective, - IgxRowEditTemplateDirective, - IgxRowEditActionsDirective, - IgxRowEditTextDirective, - IgxRowEditTabStopDirective, - IgxGridBodyDirective, - IgxColumnActionsModule, - IgxGridColumnModule, - IgxGridHeadersModule, - IgxGridPipesModule, - IgxGridFilteringModule, - IgxGridExcelStyleFilteringModule, - IgxRowDragModule, - IgxPaginatorModule, - IgxGridFooterComponent, - IgxGridResizingModule, - IgxColumnMovingModule, - IgxGridSelectionModule, - IgxGridSummaryModule, - IgxGridToolbarModule, - IgxAdvancedFilteringDialogComponent, - IgxGridSharedModules, - IgxRowExpandedIndicatorDirective, - IgxRowCollapsedIndicatorDirective, - IgxHeaderExpandIndicatorDirective, - IgxHeaderCollapseIndicatorDirective, - IgxExcelStyleHeaderIconDirective, - IgxSortAscendingHeaderIconDirective, - IgxSortDescendingHeaderIconDirective, - IgxSortHeaderIconDirective, - IgxGroupAreaDropDirective, - IgxGroupByMetaPipe - ], - imports: [ - IgxGridColumnModule, - IgxGridHeadersModule, - IgxColumnMovingModule, - IgxGridResizingModule, - IgxGridSelectionModule, - IgxGridSummaryModule, - IgxGridToolbarModule, - IgxColumnActionsModule, - IgxGridPipesModule, - IgxGridFilteringModule, - IgxGridExcelStyleFilteringModule, - IgxRowDragModule, - IgxPaginatorModule, - IgxGridSharedModules, - IgxChipsModule - ] +@NgModule({ + declarations: [ + IgxRowDirective, + IgxGridCellComponent, + IgxRowAddTextDirective, + IgxRowEditTemplateDirective, + IgxRowEditActionsDirective, + IgxRowEditTextDirective, + IgxRowEditTabStopDirective, + IgxGridBodyDirective, + IgxGridFooterComponent, + IgxAdvancedFilteringDialogComponent, + IgxRowExpandedIndicatorDirective, + IgxRowCollapsedIndicatorDirective, + IgxHeaderExpandIndicatorDirective, + IgxHeaderCollapseIndicatorDirective, + IgxExcelStyleHeaderIconDirective, + IgxSortAscendingHeaderIconDirective, + IgxSortDescendingHeaderIconDirective, + IgxSortHeaderIconDirective, + IgxGroupAreaDropDirective, + IgxGroupByMetaPipe + ], + exports: [ + IgxGridCellComponent, + IgxRowAddTextDirective, + IgxRowEditTemplateDirective, + IgxRowEditActionsDirective, + IgxRowEditTextDirective, + IgxRowEditTabStopDirective, + IgxGridBodyDirective, + IgxColumnActionsModule, + IgxGridColumnModule, + IgxGridHeadersModule, + IgxGridPipesModule, + IgxGridFilteringModule, + IgxGridExcelStyleFilteringModule, + IgxRowDragModule, + IgxPaginatorModule, + IgxGridFooterComponent, + IgxGridResizingModule, + IgxColumnMovingModule, + IgxGridSelectionModule, + IgxGridSummaryModule, + IgxGridToolbarModule, + IgxAdvancedFilteringDialogComponent, + IgxGridSharedModules, + IgxRowExpandedIndicatorDirective, + IgxRowCollapsedIndicatorDirective, + IgxHeaderExpandIndicatorDirective, + IgxHeaderCollapseIndicatorDirective, + IgxExcelStyleHeaderIconDirective, + IgxSortAscendingHeaderIconDirective, + IgxSortDescendingHeaderIconDirective, + IgxSortHeaderIconDirective, + IgxGroupAreaDropDirective, + IgxGroupByMetaPipe + ], + imports: [ + IgxGridColumnModule, + IgxGridHeadersModule, + IgxColumnMovingModule, + IgxGridResizingModule, + IgxGridSelectionModule, + IgxGridSummaryModule, + IgxGridToolbarModule, + IgxColumnActionsModule, + IgxGridPipesModule, + IgxGridFilteringModule, + IgxGridExcelStyleFilteringModule, + IgxRowDragModule, + IgxPaginatorModule, + IgxGridSharedModules, + IgxChipsModule + ] }) export class IgxGridCommonModule { } diff --git a/projects/igniteui-angular/src/lib/grids/grid-public-cell.ts b/projects/igniteui-angular/src/lib/grids/grid-public-cell.ts index 0ce31d5228a..1319fe4d48e 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-public-cell.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-public-cell.ts @@ -1,279 +1,279 @@ -import { CellType, ColumnType, GridType, RowType } from './common/grid.interface'; -import { ISelectionNode } from './common/types'; -import { resolveNestedPath } from '../core/utils'; - -export class IgxGridCell implements CellType { - - /** - * Returns the grid containing the cell. - * - * @memberof IgxGridCell - */ - public grid: GridType; - private _row: RowType; - private _rowIndex: number; - private _column: ColumnType; - private _columnField: string; - - /** - * @hidden - */ - constructor( - grid: GridType, - row: number | RowType, - column: string | ColumnType) { - this.grid = grid; - if (typeof row === 'number') { - this._rowIndex = row; - } else { - this._row = row; - this._rowIndex = row.index; - } - if (typeof column === 'string') { - this._columnField = column; - } else { - this._column = column; - } - } - - /** - * Returns the row containing the cell. - * ```typescript - * let row = this.cell.row; - * ``` - * - * @memberof IgxGridCell - */ - public get row(): RowType { - return this._row || this.grid.createRow(this._rowIndex); - } - - /** - * Returns the column of the cell. - * ```typescript - * let column = this.cell.column; - * ``` - * - * @memberof IgxGridCell - */ - public get column(): ColumnType { - return this._column || this.grid.getColumnByName(this._columnField); - } - - /** - * Gets the current edit value while a cell is in edit mode. - * ```typescript - * let editValue = this.cell.editValue; - * ``` - * - * @memberof IgxGridCell - */ - public get editValue(): any { - if (this.isCellInEditMode()) { - return this.grid.crudService.cell.editValue; - } - } - - /** - * Sets the current edit value while a cell is in edit mode. - * Only for cell editing mode. - * ```typescript - * this.cell.editValue = value; - * ``` - * - * @memberof IgxGridCell - */ - public set editValue(value: any) { - if (this.isCellInEditMode()) { - this.grid.crudService.cell.editValue = value; - } - } - - /** - * Returns whether the cell is editable.. - * - * @memberof IgxGridCell - */ - public get editable(): boolean { - return this.column.editable && !this.row?.disabled; - } - - /** - * Gets the width of the cell. - * ```typescript - * let cellWidth = this.cell.width; - * ``` - * - * @memberof IgxGridCell - */ - public get width(): string { - return this.column.width; - } - - /** - * Returns the cell value. - * - * @memberof IgxGridCell - */ - public get value(): any { - // will return undefined for a column layout, because getCellByColumnVisibleIndex may return the column layout at that index. - // getCellByColumnVisibleIndex is deprecated and will be removed in future version - return this.column.field ? - this.column.hasNestedPath ? resolveNestedPath(this.row?.data, this.column.field) : this.row?.data[this.column.field] - : undefined; - } - - /** - * Updates the cell value. - * - * @memberof IgxGridCell - */ - public set value(val: any) { - this.update(val); - } - - /** - * Gets the cell id. - * A cell in the grid is identified by: - * - rowID - primaryKey data value or the whole rowData, if the primaryKey is omitted. - * - rowIndex - the row index - * - columnID - column index - * - * ```typescript - * let cellID = cell.id; - * ``` - * - * @memberof IgxGridCell - */ - public get id(): any { - const primaryKey = this.grid.primaryKey; - const rowID = primaryKey ? this.row?.data[primaryKey] : this.row?.data; - return { rowID, columnID: this.column.index, rowIndex: this._rowIndex || this.row?.index }; - } - - /** - * Returns if the row is currently in edit mode. - * - * @memberof IgxGridCell - */ - public get editMode(): boolean { - return this.isCellInEditMode(); - } - - /** - * Starts/ends edit mode for the cell. - * - * ```typescript - * cell.editMode = !cell.editMode; - * ``` - * - * @memberof IgxGridCell - */ - public set editMode(value: boolean) { - const isInEditMode = this.isCellInEditMode(); - if (!this.row || this.row?.deleted || isInEditMode === value) { - return; - } - if (this.editable && value) { - this.endEdit(); - // TODO possibly define similar method in gridAPI, which does not emit event - this.grid.crudService.enterEditMode(this); - } else { - this.grid.crudService.endCellEdit(); - } - this.grid.notifyChanges(); - } - - /** - * Gets whether the cell is selected. - * ```typescript - * let isSelected = this.cell.selected; - * ``` - * - * - * @memberof IgxGridCell - */ - public get selected(): boolean { - return this.grid.selectionService.selected(this.selectionNode); - } - - /** - * Selects/deselects the cell. - * ```typescript - * this.cell.selected = true. - * ``` - * - * - * @memberof IgxGridCell - */ - public set selected(val: boolean) { - const node = this.selectionNode; - if (val) { - this.grid.selectionService.add(node); - } else { - this.grid.selectionService.remove(node); - } - this.grid.notifyChanges(); - } - - public get active() { - const node = this.grid.navigation.activeNode; - return node ? node.row === this.row?.index && node.column === this.column.visibleIndex : false; - } - - - /** - * Updates the cell value. - * - * ```typescript - * cell.update(newValue); - * ``` - * - * @memberof IgxGridCell - */ - public update(val: any): void { - if (this.row?.deleted) { - return; - } - - this.endEdit(); - - const cell = this.isCellInEditMode() ? this.grid.crudService.cell : this.grid.crudService.createCell(this); - cell.editValue = val; - this.grid.gridAPI.update_cell(cell); - this.grid.crudService.endCellEdit(); - this.grid.notifyChanges(); - } - - protected get selectionNode(): ISelectionNode { - return { - row: this.row?.index, - column: this.column.columnLayoutChild ? this.column.parent.visibleIndex : this.column.visibleIndex, - layout: this.column.columnLayoutChild ? { - rowStart: this.column.rowStart, - colStart: this.column.colStart, - rowEnd: this.column.rowEnd, - colEnd: this.column.colEnd, - columnVisibleIndex: this.column.visibleIndex - } : null - }; - } - - private isCellInEditMode(): boolean { - if (this.grid.crudService.cellInEditMode) { - const cellInEditMode = this.grid.crudService.cell.id; - const isCurrentCell = cellInEditMode.rowID === this.id.rowID && - cellInEditMode.rowIndex === this.id.rowIndex && - cellInEditMode.columnID === this.id.columnID; - return isCurrentCell; - } - return false; - } - - private endEdit(): void { - if (!this.isCellInEditMode()) { - this.grid.gridAPI.update_cell(this.grid.crudService.cell); - this.grid.crudService.endCellEdit(); - } - } -} +import { CellType, ColumnType, GridType, RowType } from './common/grid.interface'; +import { ISelectionNode } from './common/types'; +import { resolveNestedPath } from '../core/utils'; + +export class IgxGridCell implements CellType { + + /** + * Returns the grid containing the cell. + * + * @memberof IgxGridCell + */ + public grid: GridType; + private _row: RowType; + private _rowIndex: number; + private _column: ColumnType; + private _columnField: string; + + /** + * @hidden + */ + constructor( + grid: GridType, + row: number | RowType, + column: string | ColumnType) { + this.grid = grid; + if (typeof row === 'number') { + this._rowIndex = row; + } else { + this._row = row; + this._rowIndex = row.index; + } + if (typeof column === 'string') { + this._columnField = column; + } else { + this._column = column; + } + } + + /** + * Returns the row containing the cell. + * ```typescript + * let row = this.cell.row; + * ``` + * + * @memberof IgxGridCell + */ + public get row(): RowType { + return this._row || this.grid.createRow(this._rowIndex); + } + + /** + * Returns the column of the cell. + * ```typescript + * let column = this.cell.column; + * ``` + * + * @memberof IgxGridCell + */ + public get column(): ColumnType { + return this._column || this.grid.getColumnByName(this._columnField); + } + + /** + * Gets the current edit value while a cell is in edit mode. + * ```typescript + * let editValue = this.cell.editValue; + * ``` + * + * @memberof IgxGridCell + */ + public get editValue(): any { + if (this.isCellInEditMode()) { + return this.grid.crudService.cell.editValue; + } + } + + /** + * Sets the current edit value while a cell is in edit mode. + * Only for cell editing mode. + * ```typescript + * this.cell.editValue = value; + * ``` + * + * @memberof IgxGridCell + */ + public set editValue(value: any) { + if (this.isCellInEditMode()) { + this.grid.crudService.cell.editValue = value; + } + } + + /** + * Returns whether the cell is editable.. + * + * @memberof IgxGridCell + */ + public get editable(): boolean { + return this.column.editable && !this.row?.disabled; + } + + /** + * Gets the width of the cell. + * ```typescript + * let cellWidth = this.cell.width; + * ``` + * + * @memberof IgxGridCell + */ + public get width(): string { + return this.column.width; + } + + /** + * Returns the cell value. + * + * @memberof IgxGridCell + */ + public get value(): any { + // will return undefined for a column layout, because getCellByColumnVisibleIndex may return the column layout at that index. + // getCellByColumnVisibleIndex is deprecated and will be removed in future version + return this.column.field ? + this.column.hasNestedPath ? resolveNestedPath(this.row?.data, this.column.field) : this.row?.data[this.column.field] + : undefined; + } + + /** + * Updates the cell value. + * + * @memberof IgxGridCell + */ + public set value(val: any) { + this.update(val); + } + + /** + * Gets the cell id. + * A cell in the grid is identified by: + * - rowID - primaryKey data value or the whole rowData, if the primaryKey is omitted. + * - rowIndex - the row index + * - columnID - column index + * + * ```typescript + * let cellID = cell.id; + * ``` + * + * @memberof IgxGridCell + */ + public get id(): any { + const primaryKey = this.grid.primaryKey; + const rowID = primaryKey ? this.row?.data[primaryKey] : this.row?.data; + return { rowID, columnID: this.column.index, rowIndex: this._rowIndex || this.row?.index }; + } + + /** + * Returns if the row is currently in edit mode. + * + * @memberof IgxGridCell + */ + public get editMode(): boolean { + return this.isCellInEditMode(); + } + + /** + * Starts/ends edit mode for the cell. + * + * ```typescript + * cell.editMode = !cell.editMode; + * ``` + * + * @memberof IgxGridCell + */ + public set editMode(value: boolean) { + const isInEditMode = this.isCellInEditMode(); + if (!this.row || this.row?.deleted || isInEditMode === value) { + return; + } + if (this.editable && value) { + this.endEdit(); + // TODO possibly define similar method in gridAPI, which does not emit event + this.grid.crudService.enterEditMode(this); + } else { + this.grid.crudService.endCellEdit(); + } + this.grid.notifyChanges(); + } + + /** + * Gets whether the cell is selected. + * ```typescript + * let isSelected = this.cell.selected; + * ``` + * + * + * @memberof IgxGridCell + */ + public get selected(): boolean { + return this.grid.selectionService.selected(this.selectionNode); + } + + /** + * Selects/deselects the cell. + * ```typescript + * this.cell.selected = true. + * ``` + * + * + * @memberof IgxGridCell + */ + public set selected(val: boolean) { + const node = this.selectionNode; + if (val) { + this.grid.selectionService.add(node); + } else { + this.grid.selectionService.remove(node); + } + this.grid.notifyChanges(); + } + + public get active() { + const node = this.grid.navigation.activeNode; + return node ? node.row === this.row?.index && node.column === this.column.visibleIndex : false; + } + + + /** + * Updates the cell value. + * + * ```typescript + * cell.update(newValue); + * ``` + * + * @memberof IgxGridCell + */ + public update(val: any): void { + if (this.row?.deleted) { + return; + } + + this.endEdit(); + + const cell = this.isCellInEditMode() ? this.grid.crudService.cell : this.grid.crudService.createCell(this); + cell.editValue = val; + this.grid.gridAPI.update_cell(cell); + this.grid.crudService.endCellEdit(); + this.grid.notifyChanges(); + } + + protected get selectionNode(): ISelectionNode { + return { + row: this.row?.index, + column: this.column.columnLayoutChild ? this.column.parent.visibleIndex : this.column.visibleIndex, + layout: this.column.columnLayoutChild ? { + rowStart: this.column.rowStart, + colStart: this.column.colStart, + rowEnd: this.column.rowEnd, + colEnd: this.column.colEnd, + columnVisibleIndex: this.column.visibleIndex + } : null + }; + } + + private isCellInEditMode(): boolean { + if (this.grid.crudService.cellInEditMode) { + const cellInEditMode = this.grid.crudService.cell.id; + const isCurrentCell = cellInEditMode.rowID === this.id.rowID && + cellInEditMode.rowIndex === this.id.rowIndex && + cellInEditMode.columnID === this.id.columnID; + return isCurrentCell; + } + return false; + } + + private endEdit(): void { + if (!this.isCellInEditMode()) { + this.grid.gridAPI.update_cell(this.grid.crudService.cell); + this.grid.crudService.endCellEdit(); + } + } +} diff --git a/projects/igniteui-angular/src/lib/grids/grid-public-row.ts b/projects/igniteui-angular/src/lib/grids/grid-public-row.ts index 41955d5d0ba..f74dbec12fd 100644 --- a/projects/igniteui-angular/src/lib/grids/grid-public-row.ts +++ b/projects/igniteui-angular/src/lib/grids/grid-public-row.ts @@ -1,789 +1,789 @@ -import { IGroupByRecord } from '../data-operations/groupby-record.interface'; -import { IgxAddRow, IgxEditRow } from './common/crud.service'; -import { GridInstanceType, GridSummaryCalculationMode, GridSummaryPosition } from './common/enums'; -import { IgxGridCell } from './grid-public-cell'; -import { IgxSummaryResult } from './summaries/grid-summary'; -import { ITreeGridRecord } from './tree-grid/tree-grid.interfaces'; -import mergeWith from 'lodash.mergewith'; -import { CellType, GridServiceType, GridType, RowType } from './common/grid.interface'; - -abstract class BaseRow implements RowType { - public index: number; - /** - * The grid that contains the row. - */ - public grid: GridType; - protected _data?: any; - - /** - * Returns the view index calculated per the grid page. - */ - public get viewIndex(): number { - return this.index + ((this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0)); - } - - /** - * Gets the row key. - * A row in the grid is identified either by: - * - primaryKey data value, - * - the whole rowData, if the primaryKey is omitted. - * - * ```typescript - * let rowKey = row.key; - * ``` - */ - public get key(): any { - const data = this._data ?? this.grid.dataView[this.index]; - const primaryKey = this.grid.primaryKey; - return primaryKey ? data[primaryKey] : data; - } - - /** - * Gets if this represents add row UI - * - * ```typescript - * let isAddRow = row.addRowUI; - * ``` - */ - public get addRowUI(): boolean { - return !!this.grid.crudService.row && - this.grid.crudService.row.getClassName() === IgxAddRow.name && - this.grid.crudService.row.id === this.key; - } - - /** - * The data record that populates the row. - * - * ```typescript - * let rowData = row.data; - * ``` - */ - public get data(): any { - if (this.inEditMode) { - return mergeWith(this.grid.dataCloneStrategy.clone(this._data ?? this.grid.dataView[this.index]), - this.grid.transactions.getAggregatedValue(this.key, false), - (objValue, srcValue) => { - if (Array.isArray(srcValue)) { - return objValue = srcValue; - } - }); - } - return this._data ?? this.grid.dataView[this.index]; - } - - /** - * Returns if the row is currently in edit mode. - */ - public get inEditMode(): boolean { - if (this.grid.rowEditable) { - const editRowState = this.grid.crudService.row; - return (editRowState && editRowState.id === this.key) || false; - } else { - return false; - } - } - - /** - * Gets whether the row is pinned. - * Default value is `false`. - * ```typescript - * const isPinned = row.pinned; - * ``` - */ - public get pinned(): boolean { - return this.grid.isRecordPinned(this.data); - } - - /** - * Sets whether the row is pinned. - * Default value is `false`. - * ```typescript - * row.pinned = !row.pinned; - * ``` - */ - public set pinned(val: boolean) { - if (val) { - this.pin(); - } else { - this.unpin(); - } - } - - /** - * Gets the row expanded/collapsed state. - * - * ```typescript - * const isExpanded = row.expanded; - * ``` - */ - public get expanded(): boolean { - return this.grid.gridAPI.get_row_expansion_state(this.data); - } - - /** - * Expands/collapses the row. - * - * ```typescript - * row.expanded = true; - * ``` - */ - public set expanded(val: boolean) { - this.grid.gridAPI.set_row_expansion_state(this.key, val); - } - - /** - * Gets whether the row is selected. - * Default value is `false`. - * ```typescript - * row.selected = true; - * ``` - */ - public get selected(): boolean { - return this.grid.selectionService.isRowSelected(this.key); - } - - /** - * Sets whether the row is selected. - * Default value is `false`. - * ```typescript - * row.selected = !row.selected; - * ``` - */ - public set selected(val: boolean) { - if (val) { - this.grid.selectionService.selectRowsWithNoEvent([this.key]); - } else { - this.grid.selectionService.deselectRowsWithNoEvent([this.key]); - } - this.grid.cdr.markForCheck(); - } - - /** - * Returns if the row is in delete state. - */ - public get deleted(): boolean { - return this.grid.gridAPI.row_deleted_transaction(this.key); - } - - /** - * Returns if the row has child rows. Always return false for IgxGridRow. - */ - public get hasChildren(): boolean { - return false; - } - - public get disabled(): boolean { - return this.grid.isGhostRecord(this.data); - } - - /** - * Gets the rendered cells in the row component. - */ - public get cells(): CellType[] { - const res: CellType[] = []; - this.grid.columnList.forEach(col => { - const cell: CellType = new IgxGridCell(this.grid, this.index, col.field); - res.push(cell); - }); - return res; - } - - /** - * Pins the specified row. - * This method emits `onRowPinning` event. - * - * ```typescript - * // pin the selected row from the grid - * this.grid.selectedRows[0].pin(); - * ``` - */ - public pin(): boolean { - return this.grid.pinRow(this.key, this.index); - } - - /** - * Unpins the specified row. - * This method emits `onRowPinning` event. - * - * ```typescript - * // unpin the selected row from the grid - * this.grid.selectedRows[0].unpin(); - * ``` - */ - public unpin(): boolean { - return this.grid.unpinRow(this.key); - } - - /** - * Updates the specified row object and the data source record with the passed value. - * - * ```typescript - * // update the second selected row's value - * let newValue = "Apple"; - * this.grid.selectedRows[1].update(newValue); - * ``` - */ - public update(value: any): void { - const crudService = this.grid.crudService; - if (crudService.cellInEditMode && crudService.cell.id.rowID === this.key) { - this.grid.transactions.endPending(false); - } - const row = new IgxEditRow(this.key, this.index, this.data, this.grid); - this.grid.gridAPI.update_row(row, value); - this.grid.notifyChanges(); - } - - /** - * Removes the specified row from the grid's data source. - * This method emits `onRowDeleted` event. - * - * ```typescript - * // delete the third selected row from the grid - * this.grid.selectedRows[2].delete(); - * ``` - */ - public delete(): void { - this.grid.deleteRowById(this.key); - } -} - -export class IgxGridRow extends BaseRow implements RowType { - /** - * @hidden - */ - constructor( - public grid: GridType, - public index: number, data?: any - ) { - super(); - this._data = data && data.addRow && data.recordRef ? data.recordRef : data; - } - - /** - * Returns the view index calculated per the grid page. - */ - public get viewIndex(): number { - if (this.grid.paginator) { - const precedingDetailRows = []; - const precedingGroupRows = []; - const firstRow = this.grid.dataView[0]; - const hasDetailRows = this.grid.expansionStates.size; - const hasGroupedRows = this.grid.groupingExpressions.length; - let precedingSummaryRows = 0; - const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow); - - // from groupingFlatResult, resolve two other collections: - // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages - // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages - if (hasDetailRows || hasGroupedRows) { - this.grid.groupingFlatResult.forEach((r, ind) => { - const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r; - if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) { - precedingGroupRows.push(r); - } - if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && !this.grid.isGroupByRecord(r)) { - precedingDetailRows.push(r); - } - }); - } - - if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { - // if firstRow is a child of the last item in precedingGroupRows, - // then summaryRow for this given groupedRecord is rendered after firstRow, - // i.e. need to decrease firstRowInd to account for the above. - precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length; - if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length && - precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) { - precedingSummaryRows += -1; - } - } - - return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index; - } else { - return this.index; - } - } - - /** - * Returns the parent row, if grid is grouped. - */ - public get parent(): RowType { - let parent: IgxGroupByRow; - if (!this.grid.groupingExpressions.length) { - return undefined; - } - - let i = this.index - 1; - while (i >= 0 && !parent) { - const rec = this.grid.dataView[i]; - if (this.grid.isGroupByRecord(rec)) { - parent = new IgxGroupByRow(this.grid, i, rec); - } - i--; - } - return parent; - } -} - -export class IgxTreeGridRow extends BaseRow implements RowType { - /** - * @hidden - */ - constructor( - public grid: GridType, - public index: number, data?: any, private _treeRow?: ITreeGridRecord - ) { - super(); - this._data = data && data.addRow && data.recordRef ? data.recordRef : data; - } - - /** - * Returns the view index calculated per the grid page. - */ - public get viewIndex(): number { - if (this.grid.hasSummarizedColumns && ((this.grid.paginator?.page || 0) > 0)) { - if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { - const firstRowIndex = this.grid.processedExpandedFlatData.indexOf(this.grid.dataView[0].data); - // firstRowIndex is based on data result after all pipes triggered, excluding summary pipe - const precedingSummaryRows = this.grid.summaryPosition === GridSummaryPosition.bottom ? - this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) : - this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) + 1; - // there is a summary row for each root record, so we calculate how many root records are rendered before the current row - return firstRowIndex + precedingSummaryRows + this.index; - } - } - return this.index + ((this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0)); - } - - /** - * The data passed to the row component. - * - * ```typescript - * let selectedRowData = this.grid.selectedRows[0].data; - * ``` - */ - public get data(): any { - if (this.inEditMode) { - return mergeWith(this.grid.dataCloneStrategy.clone(this._data ?? this.grid.dataView[this.index]), - this.grid.transactions.getAggregatedValue(this.key, false), - (objValue, srcValue) => { - if (Array.isArray(srcValue)) { - return objValue = srcValue; - } - }); - } - const rec = this.grid.dataView[this.index]; - return this._data ? this._data : this.grid.isTreeRow(rec) ? rec.data : rec; - } - - /** - * Returns the child rows. - */ - public get children(): RowType[] { - const children: IgxTreeGridRow[] = []; - if (this.treeRow.expanded) { - this.treeRow.children.forEach((rec, i) => { - const row = new IgxTreeGridRow(this.grid, this.index + 1 + i, rec.data); - children.push(row); - }); - } - return children; - } - - /** - * Returns the parent row. - */ - public get parent(): RowType { - const row = this.grid.getRowByKey(this.treeRow.parent?.key); - return row; - } - - /** - * Returns true if child rows exist. Always return false for IgxGridRow. - */ - public get hasChildren(): boolean { - if (this.treeRow.children) { - return this.treeRow.children.length > 0; - } else { - return false; - } - } - - /** - * The `ITreeGridRecord` with metadata about the row in the context of the tree grid. - * - * ```typescript - * const rowParent = this.treeGrid.getRowByKey(1).treeRow.parent; - * ``` - */ - public get treeRow(): ITreeGridRecord { - return this._treeRow ?? this.grid.records.get(this.key); - } - - /** - * Gets whether the row is pinned. - * - * ```typescript - * let isPinned = row.pinned; - * ``` - */ - public get pinned(): boolean { - return this.grid.isRecordPinned(this); - } - - /** - * Sets whether the row is pinned. - * Default value is `false`. - * ```typescript - * row.pinned = !row.pinned; - * ``` - */ - public set pinned(val: boolean) { - if (val) { - this.pin(); - } else { - this.unpin(); - } - } - - /** - * Gets whether the row is expanded. - * - * ```typescript - * let esExpanded = row.expanded; - * ``` - */ - public get expanded(): boolean { - return this.grid.gridAPI.get_row_expansion_state(this.treeRow); - } - - /** - * Expands/collapses the row. - * - * ```typescript - * row.expanded = true; - * ``` - */ - public set expanded(val: boolean) { - this.grid.gridAPI.set_row_expansion_state(this.key, val); - } - - public get disabled(): boolean { - // TODO cell - return this.grid.isGhostRecord(this.data) ? this.treeRow.isFilteredOutParent === undefined : false; - } - - private getRootParent(row: ITreeGridRecord): ITreeGridRecord { - while (row.parent) { - row = row.parent; - } - return row; - } -} - -export class IgxHierarchicalGridRow extends BaseRow implements RowType { - /** - * @hidden - */ - constructor( - public grid: GridType, - public index: number, data?: any - ) { - super(); - this._data = data && data.addRow && data.recordRef ? data.recordRef : data; - } - - /** - * Returns true if row islands exist. - */ - public get hasChildren(): boolean { - return !!this.grid.childLayoutKeys.length; - } - - /** - * Returns the view index calculated per the grid page. - */ - public get viewIndex() { - const firstRowInd = this.grid.filteredSortedData.indexOf(this.grid.dataView[0]); - const expandedRows = this.grid.filteredSortedData.filter((rec, ind) => { - const rowID = this.grid.primaryKey ? rec[this.grid.primaryKey] : rec; - return this.grid.expansionStates.get(rowID) && ind < firstRowInd; - }); - return firstRowInd + expandedRows.length + this.index; - } - - /** - * Gets the rendered cells in the row component. - */ - public get cells(): CellType[] { - const res: CellType[] = []; - this.grid.columnList.forEach(col => { - const cell: CellType = new IgxGridCell(this.grid, this.index, col.field); - res.push(cell); - }); - return res; - } -} - -export class IgxGroupByRow implements RowType { - /** - * Returns the row index. - */ - public index: number; - - /** - * The grid that contains the row. - */ - public grid: GridType; - - /** - * Returns always true, because this is in instance of an IgxGroupByRow. - */ - public isGroupByRow: boolean; - - /** - * The IGroupByRecord object, representing the group record, if the row is a GroupByRow. - */ - public get groupRow(): IGroupByRecord { - return this._groupRow ? this._groupRow : this.grid.dataView[this.index]; - } - - /** - * Returns the child rows. - */ - public get children(): RowType[] { - const children: IgxGridRow[] = []; - this.groupRow.records.forEach((rec, i) => { - const row = new IgxGridRow(this.grid, this.index + 1 + i, rec); - children.push(row); - }); - return children; - } - - /** - * Returns the view index calculated per the grid page. - */ - public get viewIndex(): number { - if (this.grid.page) { - const precedingDetailRows = []; - const precedingGroupRows = []; - const firstRow = this.grid.dataView[0]; - const hasDetailRows = this.grid.expansionStates.size; - const hasGroupedRows = this.grid.groupingExpressions.length; - let precedingSummaryRows = 0; - const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow); - - // from groupingFlatResult, resolve two other collections: - // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages - // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages - if (hasDetailRows || hasGroupedRows) { - this.grid.groupingFlatResult.forEach((r, ind) => { - const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r; - if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) { - precedingGroupRows.push(r); - } - if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && !this.grid.isGroupByRecord(r)) { - precedingDetailRows.push(r); - } - }); - } - - if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { - // if firstRow is a child of the last item in precedingGroupRows, - // then summaryRow for this given groupedRecord is rendered after firstRow, - // i.e. need to decrease firstRowInd to account for the above. - precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length; - if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length && - precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) { - precedingSummaryRows += -1; - } - } - - return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index; - } else { - return this.index; - } - } - - /** - * @hidden - */ - constructor(grid: GridType, index: number, private _groupRow?: IGroupByRecord) { - this.grid = grid; - this.index = index; - this.isGroupByRow = true; - } - - /** - * Gets whether the row is selected. - * Default value is `false`. - * ```typescript - * row.selected = true; - * ``` - */ - public get selected(): boolean { - return this.children.every(row => row.selected); - } - - /** - * Sets whether the row is selected. - * Default value is `false`. - * ```typescript - * row.selected = !row.selected; - * ``` - */ - public set selected(val: boolean) { - if (val) { - this.children.forEach(row => { - this.grid.selectionService.selectRowsWithNoEvent([row.key]); - }); - } else { - this.children.forEach(row => { - this.grid.selectionService.deselectRowsWithNoEvent([row.key]); - }); - } - this.grid.cdr.markForCheck(); - } - - /** - * Gets/sets whether the group row is expanded. - * ```typescript - * const groupRowExpanded = groupRow.expanded; - * ``` - */ - public get expanded(): boolean { - return this.grid.isExpandedGroup(this.groupRow); - } - - public set expanded(value: boolean) { - this.gridAPI.set_grouprow_expansion_state(this.groupRow, value); - } - - public isActive(): boolean { - return this.grid.navigation.activeNode ? this.grid.navigation.activeNode.row === this.index : false; - } - - /** - * Toggles the group row expanded/collapsed state. - * ```typescript - * groupRow.toggle() - * ``` - */ - public toggle(): void { - this.grid.toggleGroup(this.groupRow); - } - - private get gridAPI(): GridServiceType { - return this.grid.gridAPI as GridServiceType; - } -} - -export class IgxSummaryRow implements RowType { - /** - * Returns the row index. - */ - public index: number; - - /** - * The grid that contains the row. - */ - public grid: GridType; - - /** - * Returns always true, because this is in instance of an IgxGroupByRow. - */ - public isSummaryRow: boolean; - - - /** - * Returns the curent grid type - */ - private gridType: GridInstanceType; - - /** - * The IGroupByRecord object, representing the group record, if the row is a GroupByRow. - */ - public get summaries(): Map { - return this._summaries ? this._summaries : this.grid.dataView[this.index].summaries; - } - - /** - * Returns the view index calculated per the grid page. - */ - public get viewIndex(): number { - if (this.grid.hasSummarizedColumns && this.grid.page > 0) { - if (this.gridType === GridInstanceType.Grid) { - if (this.grid.page) { - const precedingDetailRows = []; - const precedingGroupRows = []; - const firstRow = this.grid.dataView[0]; - const hasDetailRows = this.grid.expansionStates.size; - const hasGroupedRows = this.grid.groupingExpressions.length; - let precedingSummaryRows = 0; - const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow); - - // from groupingFlatResult, resolve two other collections: - // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages - // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages - if (hasDetailRows || hasGroupedRows) { - this.grid.groupingFlatResult.forEach((r, ind) => { - const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r; - if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) { - precedingGroupRows.push(r); - } - if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && - !this.grid.isGroupByRecord(r)) { - precedingDetailRows.push(r); - } - }); - } - - if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { - // if firstRow is a child of the last item in precedingGroupRows, - // then summaryRow for this given groupedRecord is rendered after firstRow, - // i.e. need to decrease firstRowInd to account for the above. - precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length; - if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length && - precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) { - precedingSummaryRows += -1; - } - } - - return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index; - } else { - return this.index; - } - } else if (this.gridType === GridInstanceType.TreeGrid) { - if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { - const firstRowIndex = this.grid.processedExpandedFlatData.indexOf(this.grid.dataView[0].data); - const precedingSummaryRows = this.grid.summaryPosition === GridSummaryPosition.bottom ? - this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) : - this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) + 1; - return firstRowIndex + precedingSummaryRows + this.index; - } - } - } - - return this.index + ((this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0)); - } - - /** - * @hidden - */ - constructor( - grid: GridType, - index: number, private _summaries?: Map, type?: GridInstanceType - ) { - this.grid = grid; - this.index = index; - this.isSummaryRow = true; - this.gridType = type; - } - - private getRootParent(row: ITreeGridRecord): ITreeGridRecord { - while (row.parent) { - row = row.parent; - } - return row; - } -} +import { IGroupByRecord } from '../data-operations/groupby-record.interface'; +import { IgxAddRow, IgxEditRow } from './common/crud.service'; +import { GridInstanceType, GridSummaryCalculationMode, GridSummaryPosition } from './common/enums'; +import { IgxGridCell } from './grid-public-cell'; +import { IgxSummaryResult } from './summaries/grid-summary'; +import { ITreeGridRecord } from './tree-grid/tree-grid.interfaces'; +import mergeWith from 'lodash.mergewith'; +import { CellType, GridServiceType, GridType, RowType } from './common/grid.interface'; + +abstract class BaseRow implements RowType { + public index: number; + /** + * The grid that contains the row. + */ + public grid: GridType; + protected _data?: any; + + /** + * Returns the view index calculated per the grid page. + */ + public get viewIndex(): number { + return this.index + ((this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0)); + } + + /** + * Gets the row key. + * A row in the grid is identified either by: + * - primaryKey data value, + * - the whole rowData, if the primaryKey is omitted. + * + * ```typescript + * let rowKey = row.key; + * ``` + */ + public get key(): any { + const data = this._data ?? this.grid.dataView[this.index]; + const primaryKey = this.grid.primaryKey; + return primaryKey ? data[primaryKey] : data; + } + + /** + * Gets if this represents add row UI + * + * ```typescript + * let isAddRow = row.addRowUI; + * ``` + */ + public get addRowUI(): boolean { + return !!this.grid.crudService.row && + this.grid.crudService.row.getClassName() === IgxAddRow.name && + this.grid.crudService.row.id === this.key; + } + + /** + * The data record that populates the row. + * + * ```typescript + * let rowData = row.data; + * ``` + */ + public get data(): any { + if (this.inEditMode) { + return mergeWith(this.grid.dataCloneStrategy.clone(this._data ?? this.grid.dataView[this.index]), + this.grid.transactions.getAggregatedValue(this.key, false), + (objValue, srcValue) => { + if (Array.isArray(srcValue)) { + return objValue = srcValue; + } + }); + } + return this._data ?? this.grid.dataView[this.index]; + } + + /** + * Returns if the row is currently in edit mode. + */ + public get inEditMode(): boolean { + if (this.grid.rowEditable) { + const editRowState = this.grid.crudService.row; + return (editRowState && editRowState.id === this.key) || false; + } else { + return false; + } + } + + /** + * Gets whether the row is pinned. + * Default value is `false`. + * ```typescript + * const isPinned = row.pinned; + * ``` + */ + public get pinned(): boolean { + return this.grid.isRecordPinned(this.data); + } + + /** + * Sets whether the row is pinned. + * Default value is `false`. + * ```typescript + * row.pinned = !row.pinned; + * ``` + */ + public set pinned(val: boolean) { + if (val) { + this.pin(); + } else { + this.unpin(); + } + } + + /** + * Gets the row expanded/collapsed state. + * + * ```typescript + * const isExpanded = row.expanded; + * ``` + */ + public get expanded(): boolean { + return this.grid.gridAPI.get_row_expansion_state(this.data); + } + + /** + * Expands/collapses the row. + * + * ```typescript + * row.expanded = true; + * ``` + */ + public set expanded(val: boolean) { + this.grid.gridAPI.set_row_expansion_state(this.key, val); + } + + /** + * Gets whether the row is selected. + * Default value is `false`. + * ```typescript + * row.selected = true; + * ``` + */ + public get selected(): boolean { + return this.grid.selectionService.isRowSelected(this.key); + } + + /** + * Sets whether the row is selected. + * Default value is `false`. + * ```typescript + * row.selected = !row.selected; + * ``` + */ + public set selected(val: boolean) { + if (val) { + this.grid.selectionService.selectRowsWithNoEvent([this.key]); + } else { + this.grid.selectionService.deselectRowsWithNoEvent([this.key]); + } + this.grid.cdr.markForCheck(); + } + + /** + * Returns if the row is in delete state. + */ + public get deleted(): boolean { + return this.grid.gridAPI.row_deleted_transaction(this.key); + } + + /** + * Returns if the row has child rows. Always return false for IgxGridRow. + */ + public get hasChildren(): boolean { + return false; + } + + public get disabled(): boolean { + return this.grid.isGhostRecord(this.data); + } + + /** + * Gets the rendered cells in the row component. + */ + public get cells(): CellType[] { + const res: CellType[] = []; + this.grid.columnList.forEach(col => { + const cell: CellType = new IgxGridCell(this.grid, this.index, col.field); + res.push(cell); + }); + return res; + } + + /** + * Pins the specified row. + * This method emits `onRowPinning` event. + * + * ```typescript + * // pin the selected row from the grid + * this.grid.selectedRows[0].pin(); + * ``` + */ + public pin(): boolean { + return this.grid.pinRow(this.key, this.index); + } + + /** + * Unpins the specified row. + * This method emits `onRowPinning` event. + * + * ```typescript + * // unpin the selected row from the grid + * this.grid.selectedRows[0].unpin(); + * ``` + */ + public unpin(): boolean { + return this.grid.unpinRow(this.key); + } + + /** + * Updates the specified row object and the data source record with the passed value. + * + * ```typescript + * // update the second selected row's value + * let newValue = "Apple"; + * this.grid.selectedRows[1].update(newValue); + * ``` + */ + public update(value: any): void { + const crudService = this.grid.crudService; + if (crudService.cellInEditMode && crudService.cell.id.rowID === this.key) { + this.grid.transactions.endPending(false); + } + const row = new IgxEditRow(this.key, this.index, this.data, this.grid); + this.grid.gridAPI.update_row(row, value); + this.grid.notifyChanges(); + } + + /** + * Removes the specified row from the grid's data source. + * This method emits `onRowDeleted` event. + * + * ```typescript + * // delete the third selected row from the grid + * this.grid.selectedRows[2].delete(); + * ``` + */ + public delete(): void { + this.grid.deleteRowById(this.key); + } +} + +export class IgxGridRow extends BaseRow implements RowType { + /** + * @hidden + */ + constructor( + public grid: GridType, + public index: number, data?: any + ) { + super(); + this._data = data && data.addRow && data.recordRef ? data.recordRef : data; + } + + /** + * Returns the view index calculated per the grid page. + */ + public get viewIndex(): number { + if (this.grid.paginator) { + const precedingDetailRows = []; + const precedingGroupRows = []; + const firstRow = this.grid.dataView[0]; + const hasDetailRows = this.grid.expansionStates.size; + const hasGroupedRows = this.grid.groupingExpressions.length; + let precedingSummaryRows = 0; + const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow); + + // from groupingFlatResult, resolve two other collections: + // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages + // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages + if (hasDetailRows || hasGroupedRows) { + this.grid.groupingFlatResult.forEach((r, ind) => { + const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r; + if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) { + precedingGroupRows.push(r); + } + if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && !this.grid.isGroupByRecord(r)) { + precedingDetailRows.push(r); + } + }); + } + + if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { + // if firstRow is a child of the last item in precedingGroupRows, + // then summaryRow for this given groupedRecord is rendered after firstRow, + // i.e. need to decrease firstRowInd to account for the above. + precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length; + if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length && + precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) { + precedingSummaryRows += -1; + } + } + + return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index; + } else { + return this.index; + } + } + + /** + * Returns the parent row, if grid is grouped. + */ + public get parent(): RowType { + let parent: IgxGroupByRow; + if (!this.grid.groupingExpressions.length) { + return undefined; + } + + let i = this.index - 1; + while (i >= 0 && !parent) { + const rec = this.grid.dataView[i]; + if (this.grid.isGroupByRecord(rec)) { + parent = new IgxGroupByRow(this.grid, i, rec); + } + i--; + } + return parent; + } +} + +export class IgxTreeGridRow extends BaseRow implements RowType { + /** + * @hidden + */ + constructor( + public grid: GridType, + public index: number, data?: any, private _treeRow?: ITreeGridRecord + ) { + super(); + this._data = data && data.addRow && data.recordRef ? data.recordRef : data; + } + + /** + * Returns the view index calculated per the grid page. + */ + public get viewIndex(): number { + if (this.grid.hasSummarizedColumns && ((this.grid.paginator?.page || 0) > 0)) { + if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { + const firstRowIndex = this.grid.processedExpandedFlatData.indexOf(this.grid.dataView[0].data); + // firstRowIndex is based on data result after all pipes triggered, excluding summary pipe + const precedingSummaryRows = this.grid.summaryPosition === GridSummaryPosition.bottom ? + this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) : + this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) + 1; + // there is a summary row for each root record, so we calculate how many root records are rendered before the current row + return firstRowIndex + precedingSummaryRows + this.index; + } + } + return this.index + ((this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0)); + } + + /** + * The data passed to the row component. + * + * ```typescript + * let selectedRowData = this.grid.selectedRows[0].data; + * ``` + */ + public get data(): any { + if (this.inEditMode) { + return mergeWith(this.grid.dataCloneStrategy.clone(this._data ?? this.grid.dataView[this.index]), + this.grid.transactions.getAggregatedValue(this.key, false), + (objValue, srcValue) => { + if (Array.isArray(srcValue)) { + return objValue = srcValue; + } + }); + } + const rec = this.grid.dataView[this.index]; + return this._data ? this._data : this.grid.isTreeRow(rec) ? rec.data : rec; + } + + /** + * Returns the child rows. + */ + public get children(): RowType[] { + const children: IgxTreeGridRow[] = []; + if (this.treeRow.expanded) { + this.treeRow.children.forEach((rec, i) => { + const row = new IgxTreeGridRow(this.grid, this.index + 1 + i, rec.data); + children.push(row); + }); + } + return children; + } + + /** + * Returns the parent row. + */ + public get parent(): RowType { + const row = this.grid.getRowByKey(this.treeRow.parent?.key); + return row; + } + + /** + * Returns true if child rows exist. Always return false for IgxGridRow. + */ + public get hasChildren(): boolean { + if (this.treeRow.children) { + return this.treeRow.children.length > 0; + } else { + return false; + } + } + + /** + * The `ITreeGridRecord` with metadata about the row in the context of the tree grid. + * + * ```typescript + * const rowParent = this.treeGrid.getRowByKey(1).treeRow.parent; + * ``` + */ + public get treeRow(): ITreeGridRecord { + return this._treeRow ?? this.grid.records.get(this.key); + } + + /** + * Gets whether the row is pinned. + * + * ```typescript + * let isPinned = row.pinned; + * ``` + */ + public get pinned(): boolean { + return this.grid.isRecordPinned(this); + } + + /** + * Sets whether the row is pinned. + * Default value is `false`. + * ```typescript + * row.pinned = !row.pinned; + * ``` + */ + public set pinned(val: boolean) { + if (val) { + this.pin(); + } else { + this.unpin(); + } + } + + /** + * Gets whether the row is expanded. + * + * ```typescript + * let esExpanded = row.expanded; + * ``` + */ + public get expanded(): boolean { + return this.grid.gridAPI.get_row_expansion_state(this.treeRow); + } + + /** + * Expands/collapses the row. + * + * ```typescript + * row.expanded = true; + * ``` + */ + public set expanded(val: boolean) { + this.grid.gridAPI.set_row_expansion_state(this.key, val); + } + + public get disabled(): boolean { + // TODO cell + return this.grid.isGhostRecord(this.data) ? this.treeRow.isFilteredOutParent === undefined : false; + } + + private getRootParent(row: ITreeGridRecord): ITreeGridRecord { + while (row.parent) { + row = row.parent; + } + return row; + } +} + +export class IgxHierarchicalGridRow extends BaseRow implements RowType { + /** + * @hidden + */ + constructor( + public grid: GridType, + public index: number, data?: any + ) { + super(); + this._data = data && data.addRow && data.recordRef ? data.recordRef : data; + } + + /** + * Returns true if row islands exist. + */ + public get hasChildren(): boolean { + return !!this.grid.childLayoutKeys.length; + } + + /** + * Returns the view index calculated per the grid page. + */ + public get viewIndex() { + const firstRowInd = this.grid.filteredSortedData.indexOf(this.grid.dataView[0]); + const expandedRows = this.grid.filteredSortedData.filter((rec, ind) => { + const rowID = this.grid.primaryKey ? rec[this.grid.primaryKey] : rec; + return this.grid.expansionStates.get(rowID) && ind < firstRowInd; + }); + return firstRowInd + expandedRows.length + this.index; + } + + /** + * Gets the rendered cells in the row component. + */ + public get cells(): CellType[] { + const res: CellType[] = []; + this.grid.columnList.forEach(col => { + const cell: CellType = new IgxGridCell(this.grid, this.index, col.field); + res.push(cell); + }); + return res; + } +} + +export class IgxGroupByRow implements RowType { + /** + * Returns the row index. + */ + public index: number; + + /** + * The grid that contains the row. + */ + public grid: GridType; + + /** + * Returns always true, because this is in instance of an IgxGroupByRow. + */ + public isGroupByRow: boolean; + + /** + * The IGroupByRecord object, representing the group record, if the row is a GroupByRow. + */ + public get groupRow(): IGroupByRecord { + return this._groupRow ? this._groupRow : this.grid.dataView[this.index]; + } + + /** + * Returns the child rows. + */ + public get children(): RowType[] { + const children: IgxGridRow[] = []; + this.groupRow.records.forEach((rec, i) => { + const row = new IgxGridRow(this.grid, this.index + 1 + i, rec); + children.push(row); + }); + return children; + } + + /** + * Returns the view index calculated per the grid page. + */ + public get viewIndex(): number { + if (this.grid.page) { + const precedingDetailRows = []; + const precedingGroupRows = []; + const firstRow = this.grid.dataView[0]; + const hasDetailRows = this.grid.expansionStates.size; + const hasGroupedRows = this.grid.groupingExpressions.length; + let precedingSummaryRows = 0; + const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow); + + // from groupingFlatResult, resolve two other collections: + // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages + // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages + if (hasDetailRows || hasGroupedRows) { + this.grid.groupingFlatResult.forEach((r, ind) => { + const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r; + if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) { + precedingGroupRows.push(r); + } + if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && !this.grid.isGroupByRecord(r)) { + precedingDetailRows.push(r); + } + }); + } + + if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { + // if firstRow is a child of the last item in precedingGroupRows, + // then summaryRow for this given groupedRecord is rendered after firstRow, + // i.e. need to decrease firstRowInd to account for the above. + precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length; + if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length && + precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) { + precedingSummaryRows += -1; + } + } + + return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index; + } else { + return this.index; + } + } + + /** + * @hidden + */ + constructor(grid: GridType, index: number, private _groupRow?: IGroupByRecord) { + this.grid = grid; + this.index = index; + this.isGroupByRow = true; + } + + /** + * Gets whether the row is selected. + * Default value is `false`. + * ```typescript + * row.selected = true; + * ``` + */ + public get selected(): boolean { + return this.children.every(row => row.selected); + } + + /** + * Sets whether the row is selected. + * Default value is `false`. + * ```typescript + * row.selected = !row.selected; + * ``` + */ + public set selected(val: boolean) { + if (val) { + this.children.forEach(row => { + this.grid.selectionService.selectRowsWithNoEvent([row.key]); + }); + } else { + this.children.forEach(row => { + this.grid.selectionService.deselectRowsWithNoEvent([row.key]); + }); + } + this.grid.cdr.markForCheck(); + } + + /** + * Gets/sets whether the group row is expanded. + * ```typescript + * const groupRowExpanded = groupRow.expanded; + * ``` + */ + public get expanded(): boolean { + return this.grid.isExpandedGroup(this.groupRow); + } + + public set expanded(value: boolean) { + this.gridAPI.set_grouprow_expansion_state(this.groupRow, value); + } + + public isActive(): boolean { + return this.grid.navigation.activeNode ? this.grid.navigation.activeNode.row === this.index : false; + } + + /** + * Toggles the group row expanded/collapsed state. + * ```typescript + * groupRow.toggle() + * ``` + */ + public toggle(): void { + this.grid.toggleGroup(this.groupRow); + } + + private get gridAPI(): GridServiceType { + return this.grid.gridAPI as GridServiceType; + } +} + +export class IgxSummaryRow implements RowType { + /** + * Returns the row index. + */ + public index: number; + + /** + * The grid that contains the row. + */ + public grid: GridType; + + /** + * Returns always true, because this is in instance of an IgxGroupByRow. + */ + public isSummaryRow: boolean; + + + /** + * Returns the curent grid type + */ + private gridType: GridInstanceType; + + /** + * The IGroupByRecord object, representing the group record, if the row is a GroupByRow. + */ + public get summaries(): Map { + return this._summaries ? this._summaries : this.grid.dataView[this.index].summaries; + } + + /** + * Returns the view index calculated per the grid page. + */ + public get viewIndex(): number { + if (this.grid.hasSummarizedColumns && this.grid.page > 0) { + if (this.gridType === GridInstanceType.Grid) { + if (this.grid.page) { + const precedingDetailRows = []; + const precedingGroupRows = []; + const firstRow = this.grid.dataView[0]; + const hasDetailRows = this.grid.expansionStates.size; + const hasGroupedRows = this.grid.groupingExpressions.length; + let precedingSummaryRows = 0; + const firstRowInd = this.grid.groupingFlatResult.indexOf(firstRow); + + // from groupingFlatResult, resolve two other collections: + // precedingGroupedRows -> use it to resolve summaryRow for each group in previous pages + // precedingDetailRows -> ise it to resolve the detail row for each expanded grid row in previous pages + if (hasDetailRows || hasGroupedRows) { + this.grid.groupingFlatResult.forEach((r, ind) => { + const rowID = this.grid.primaryKey ? r[this.grid.primaryKey] : r; + if (hasGroupedRows && ind < firstRowInd && this.grid.isGroupByRecord(r)) { + precedingGroupRows.push(r); + } + if (this.grid.expansionStates.get(rowID) && ind < firstRowInd && + !this.grid.isGroupByRecord(r)) { + precedingDetailRows.push(r); + } + }); + } + + if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { + // if firstRow is a child of the last item in precedingGroupRows, + // then summaryRow for this given groupedRecord is rendered after firstRow, + // i.e. need to decrease firstRowInd to account for the above. + precedingSummaryRows = precedingGroupRows.filter(gr => this.grid.isExpandedGroup(gr)).length; + if (this.grid.summaryPosition === GridSummaryPosition.bottom && precedingGroupRows.length && + precedingGroupRows[precedingGroupRows.length - 1].records.indexOf(firstRow) > -1) { + precedingSummaryRows += -1; + } + } + + return precedingDetailRows.length + precedingSummaryRows + firstRowInd + this.index; + } else { + return this.index; + } + } else if (this.gridType === GridInstanceType.TreeGrid) { + if (this.grid.summaryCalculationMode !== GridSummaryCalculationMode.rootLevelOnly) { + const firstRowIndex = this.grid.processedExpandedFlatData.indexOf(this.grid.dataView[0].data); + const precedingSummaryRows = this.grid.summaryPosition === GridSummaryPosition.bottom ? + this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) : + this.grid.rootRecords.indexOf(this.getRootParent(this.grid.dataView[0])) + 1; + return firstRowIndex + precedingSummaryRows + this.index; + } + } + } + + return this.index + ((this.grid.paginator?.page || 0) * (this.grid.paginator?.perPage || 0)); + } + + /** + * @hidden + */ + constructor( + grid: GridType, + index: number, private _summaries?: Map, type?: GridInstanceType + ) { + this.grid = grid; + this.index = index; + this.isSummaryRow = true; + this.gridType = type; + } + + private getRootParent(row: ITreeGridRecord): ITreeGridRecord { + while (row.parent) { + row = row.parent; + } + return row; + } +} diff --git a/projects/igniteui-angular/src/lib/grids/grouping/group-by-area.directive.ts b/projects/igniteui-angular/src/lib/grids/grouping/group-by-area.directive.ts index a7a5c7d0565..2904deda203 100644 --- a/projects/igniteui-angular/src/lib/grids/grouping/group-by-area.directive.ts +++ b/projects/igniteui-angular/src/lib/grids/grouping/group-by-area.directive.ts @@ -1,194 +1,194 @@ -import { - Directive, - ElementRef, - EventEmitter, - HostBinding, - Input, - Output, - Pipe, - PipeTransform, - QueryList, - TemplateRef, - ViewChildren -} from '@angular/core'; -import { IChipsAreaReorderEventArgs, IgxChipComponent } from '../../chips/public_api'; -import { DisplayDensity } from '../../core/displayDensity'; -import { PlatformUtil } from '../../core/utils'; -import { IGroupingExpression } from '../../data-operations/grouping-expression.interface'; -import { SortingDirection } from '../../data-operations/sorting-strategy'; -import { GridType } from '../common/grid.interface'; -import { IgxColumnMovingDragDirective } from '../moving/moving.drag.directive'; - -/** - * An internal component representing a base group-by drop area. - * - * @hidden @internal - */ - @Directive() -export abstract class IgxGroupByAreaDirective { - /** - * The drop area template if provided by the parent grid. - * Otherwise, uses the default internal one. - */ - @Input() - public dropAreaTemplate: TemplateRef; - - @Input() - public density: DisplayDensity = DisplayDensity.comfortable; - - @HostBinding('class.igx-grid-grouparea') - public defaultClass = true; - - @HostBinding('class.igx-grid-grouparea--cosy') - public get cosyStyle() { - return this.density === 'cosy'; - } - - @HostBinding('class.igx-grid-grouparea--compact') - public get compactStyle() { - return this.density === 'compact'; - } - - /** The parent grid containing the component. */ - @Input() - public grid: GridType; - - /** - * The group-by expressions provided by the parent grid. - */ - @Input() - public get expressions(): IGroupingExpression[] { - return this._expressions; - } - - public set expressions(value: IGroupingExpression[]) { - this._expressions = value; - this.chipExpressions = this._expressions; - this.expressionsChanged(); - this.expressionsChange.emit(this._expressions); - } - - /** - * The default message for the default drop area template. - * Obviously, if another template is provided, this is ignored. - */ - @Input() - public get dropAreaMessage(): string { - return this._dropAreaMessage ?? this.grid.resourceStrings.igx_grid_groupByArea_message; - } - - public set dropAreaMessage(value: string) { - this._dropAreaMessage = value; - } - - @Output() - public expressionsChange = new EventEmitter(); - - @ViewChildren(IgxChipComponent) - public chips: QueryList; - - public chipExpressions: IGroupingExpression[]; - - /** The native DOM element. Used in sizing calculations. */ - public get nativeElement() { - return this.ref.nativeElement; - } - - private _expressions: IGroupingExpression[] = []; - private _dropAreaMessage: string; - - constructor(private ref: ElementRef, protected platform: PlatformUtil) { } - - - public get dropAreaVisible(): boolean { - return (this.grid.columnInDrag && this.grid.columnInDrag.groupable) || - !this.expressions.length; - } - - public handleKeyDown(id: string, event: KeyboardEvent) { - if (this.platform.isActivationKey(event)) { - this.updateSorting(id); - } - } - - public handleClick(id: string) { - if (!this.grid.getColumnByName(id).groupable) { - return; - } - this.updateSorting(id); - } - - public onDragDrop(event) { - const drag: IgxColumnMovingDragDirective = event.detail.owner; - if (drag instanceof IgxColumnMovingDragDirective) { - const column = drag.column; - if (!this.grid.columnList.find(c => c === column)) { - return; - } - - const isGrouped = this.expressions.findIndex((item) => item.fieldName === column.field) !== -1; - if (column.groupable && !isGrouped && !column.columnGroup && !!column.field) { - const groupingExpression = { - fieldName: column.field, - dir: SortingDirection.Asc, - ignoreCase: column.sortingIgnoreCase, - strategy: column.sortStrategy, - groupingComparer: column.groupingComparer - }; - - this.groupBy(groupingExpression); - } - } - } - - protected getReorderedExpressions(chipsArray: IgxChipComponent[]) { - const newExpressions = []; - - chipsArray.forEach(chip => { - const expr = this.expressions.find(item => item.fieldName === chip.id); - - // disallow changing order if there are columns with groupable: false - if (!this.grid.getColumnByName(expr.fieldName)?.groupable) { - return; - } - - newExpressions.push(expr); - }); - - return newExpressions; - } - - protected updateSorting(id: string) { - const expr = this.grid.sortingExpressions.find(e => e.fieldName === id); - expr.dir = 3 - expr.dir; - this.grid.sort(expr); - } - - protected expressionsChanged() { - } - - public abstract handleReorder(event: IChipsAreaReorderEventArgs); - - public abstract handleMoveEnd(); - - public abstract groupBy(expression: IGroupingExpression); - - public abstract clearGrouping(name: string); - -} - -/** - * A pipe to circumvent the use of getters/methods just to get some additional - * information from the grouping expression and pass it to the chip representing - * that expression. - * - * @hidden @internal - */ -@Pipe({ name: 'igxGroupByMeta' }) -export class IgxGroupByMetaPipe implements PipeTransform { - - public transform(key: string, grid: GridType) { - const column = grid.getColumnByName(key); - return { groupable: column.groupable, title: column.header || key }; - } -} +import { + Directive, + ElementRef, + EventEmitter, + HostBinding, + Input, + Output, + Pipe, + PipeTransform, + QueryList, + TemplateRef, + ViewChildren +} from '@angular/core'; +import { IChipsAreaReorderEventArgs, IgxChipComponent } from '../../chips/public_api'; +import { DisplayDensity } from '../../core/displayDensity'; +import { PlatformUtil } from '../../core/utils'; +import { IGroupingExpression } from '../../data-operations/grouping-expression.interface'; +import { SortingDirection } from '../../data-operations/sorting-strategy'; +import { GridType } from '../common/grid.interface'; +import { IgxColumnMovingDragDirective } from '../moving/moving.drag.directive'; + +/** + * An internal component representing a base group-by drop area. + * + * @hidden @internal + */ + @Directive() +export abstract class IgxGroupByAreaDirective { + /** + * The drop area template if provided by the parent grid. + * Otherwise, uses the default internal one. + */ + @Input() + public dropAreaTemplate: TemplateRef; + + @Input() + public density: DisplayDensity = DisplayDensity.comfortable; + + @HostBinding('class.igx-grid-grouparea') + public defaultClass = true; + + @HostBinding('class.igx-grid-grouparea--cosy') + public get cosyStyle() { + return this.density === 'cosy'; + } + + @HostBinding('class.igx-grid-grouparea--compact') + public get compactStyle() { + return this.density === 'compact'; + } + + /** The parent grid containing the component. */ + @Input() + public grid: GridType; + + /** + * The group-by expressions provided by the parent grid. + */ + @Input() + public get expressions(): IGroupingExpression[] { + return this._expressions; + } + + public set expressions(value: IGroupingExpression[]) { + this._expressions = value; + this.chipExpressions = this._expressions; + this.expressionsChanged(); + this.expressionsChange.emit(this._expressions); + } + + /** + * The default message for the default drop area template. + * Obviously, if another template is provided, this is ignored. + */ + @Input() + public get dropAreaMessage(): string { + return this._dropAreaMessage ?? this.grid.resourceStrings.igx_grid_groupByArea_message; + } + + public set dropAreaMessage(value: string) { + this._dropAreaMessage = value; + } + + @Output() + public expressionsChange = new EventEmitter(); + + @ViewChildren(IgxChipComponent) + public chips: QueryList; + + public chipExpressions: IGroupingExpression[]; + + /** The native DOM element. Used in sizing calculations. */ + public get nativeElement() { + return this.ref.nativeElement; + } + + private _expressions: IGroupingExpression[] = []; + private _dropAreaMessage: string; + + constructor(private ref: ElementRef, protected platform: PlatformUtil) { } + + + public get dropAreaVisible(): boolean { + return (this.grid.columnInDrag && this.grid.columnInDrag.groupable) || + !this.expressions.length; + } + + public handleKeyDown(id: string, event: KeyboardEvent) { + if (this.platform.isActivationKey(event)) { + this.updateSorting(id); + } + } + + public handleClick(id: string) { + if (!this.grid.getColumnByName(id).groupable) { + return; + } + this.updateSorting(id); + } + + public onDragDrop(event) { + const drag: IgxColumnMovingDragDirective = event.detail.owner; + if (drag instanceof IgxColumnMovingDragDirective) { + const column = drag.column; + if (!this.grid.columnList.find(c => c === column)) { + return; + } + + const isGrouped = this.expressions.findIndex((item) => item.fieldName === column.field) !== -1; + if (column.groupable && !isGrouped && !column.columnGroup && !!column.field) { + const groupingExpression = { + fieldName: column.field, + dir: SortingDirection.Asc, + ignoreCase: column.sortingIgnoreCase, + strategy: column.sortStrategy, + groupingComparer: column.groupingComparer + }; + + this.groupBy(groupingExpression); + } + } + } + + protected getReorderedExpressions(chipsArray: IgxChipComponent[]) { + const newExpressions = []; + + chipsArray.forEach(chip => { + const expr = this.expressions.find(item => item.fieldName === chip.id); + + // disallow changing order if there are columns with groupable: false + if (!this.grid.getColumnByName(expr.fieldName)?.groupable) { + return; + } + + newExpressions.push(expr); + }); + + return newExpressions; + } + + protected updateSorting(id: string) { + const expr = this.grid.sortingExpressions.find(e => e.fieldName === id); + expr.dir = 3 - expr.dir; + this.grid.sort(expr); + } + + protected expressionsChanged() { + } + + public abstract handleReorder(event: IChipsAreaReorderEventArgs); + + public abstract handleMoveEnd(); + + public abstract groupBy(expression: IGroupingExpression); + + public abstract clearGrouping(name: string); + +} + +/** + * A pipe to circumvent the use of getters/methods just to get some additional + * information from the grouping expression and pass it to the chip representing + * that expression. + * + * @hidden @internal + */ +@Pipe({ name: 'igxGroupByMeta' }) +export class IgxGroupByMetaPipe implements PipeTransform { + + public transform(key: string, grid: GridType) { + const column = grid.getColumnByName(key); + return { groupable: column.groupable, title: column.header || key }; + } +} diff --git a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts index 20a98556ab0..38d9f90859e 100644 --- a/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts +++ b/projects/igniteui-angular/src/lib/grids/hierarchical-grid/hierarchical-grid.module.ts @@ -1,36 +1,36 @@ -import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { IgxGridModule } from '../grid/grid.module'; -import { IgxChildGridRowComponent, IgxHierarchicalGridComponent } from './hierarchical-grid.component'; -import { IgxHierarchicalRowComponent } from './hierarchical-row.component'; -import { IgxGridHierarchicalPipe, IgxGridHierarchicalPagingPipe } from './hierarchical-grid.pipes'; -import { IgxRowIslandComponent } from './row-island.component'; -import { IgxHierarchicalGridCellComponent } from './hierarchical-cell.component'; - -/** - * @hidden - */ -@NgModule({ - declarations: [ - IgxHierarchicalGridComponent, - IgxHierarchicalRowComponent, - IgxRowIslandComponent, - IgxChildGridRowComponent, - IgxHierarchicalGridCellComponent, - IgxGridHierarchicalPipe, - IgxGridHierarchicalPagingPipe - ], - exports: [ - IgxGridModule, - IgxHierarchicalGridComponent, - IgxHierarchicalRowComponent, - IgxHierarchicalGridCellComponent, - IgxRowIslandComponent, - IgxChildGridRowComponent - ], - imports: [ - IgxGridModule, - ], - schemas: [CUSTOM_ELEMENTS_SCHEMA] -}) -export class IgxHierarchicalGridModule { -} +import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { IgxGridModule } from '../grid/grid.module'; +import { IgxChildGridRowComponent, IgxHierarchicalGridComponent } from './hierarchical-grid.component'; +import { IgxHierarchicalRowComponent } from './hierarchical-row.component'; +import { IgxGridHierarchicalPipe, IgxGridHierarchicalPagingPipe } from './hierarchical-grid.pipes'; +import { IgxRowIslandComponent } from './row-island.component'; +import { IgxHierarchicalGridCellComponent } from './hierarchical-cell.component'; + +/** + * @hidden + */ +@NgModule({ + declarations: [ + IgxHierarchicalGridComponent, + IgxHierarchicalRowComponent, + IgxRowIslandComponent, + IgxChildGridRowComponent, + IgxHierarchicalGridCellComponent, + IgxGridHierarchicalPipe, + IgxGridHierarchicalPagingPipe + ], + exports: [ + IgxGridModule, + IgxHierarchicalGridComponent, + IgxHierarchicalRowComponent, + IgxHierarchicalGridCellComponent, + IgxRowIslandComponent, + IgxChildGridRowComponent + ], + imports: [ + IgxGridModule, + ], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +export class IgxHierarchicalGridModule { +} diff --git a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.filtering.strategy.ts b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.filtering.strategy.ts index 53bb92a75f7..117d427e8e7 100644 --- a/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.filtering.strategy.ts +++ b/projects/igniteui-angular/src/lib/grids/tree-grid/tree-grid.filtering.strategy.ts @@ -1,171 +1,171 @@ -import { parseDate, resolveNestedPath } from '../../core/utils'; -import { DataUtil } from '../../data-operations/data-util'; -import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; -import { BaseFilteringStrategy, IgxFilterItem } from '../../data-operations/filtering-strategy'; -import { SortingDirection } from '../../data-operations/sorting-strategy'; -import { ColumnType, GridType } from '../common/grid.interface'; -import { IgxTreeGridAPIService } from './tree-grid-api.service'; -import { ITreeGridRecord } from './tree-grid.interfaces'; - -export class TreeGridFilteringStrategy extends BaseFilteringStrategy { - - constructor(public hierarchicalFilterFields?: string[]) { - super(); - } - - public filter(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, - advancedExpressionsTree?: IFilteringExpressionsTree, grid?: GridType): ITreeGridRecord[] { - return this.filterImpl(data, expressionsTree, advancedExpressionsTree, undefined, grid); - } - - protected getFieldValue(rec: any, fieldName: string, isDate: boolean = false, isTime: boolean = false, grid?: GridType): any { - const column = grid?.getColumnByName(fieldName); - const hierarchicalRecord = rec as ITreeGridRecord; - let value = this.isHierarchicalFilterField(fieldName) ? - this.getHierarchicalFieldValue(hierarchicalRecord, fieldName) : - resolveNestedPath(hierarchicalRecord.data, fieldName); - - value = column?.formatter && this.shouldFormatFilterValues(column) ? - column.formatter(value, rec.data) : - value && (isDate || isTime) ? parseDate(value) : value; - - return value; - } - - private getHierarchicalFieldValue(record: ITreeGridRecord, field: string) { - const value = resolveNestedPath(record.data, field); - - return record.parent ? - `${this.getHierarchicalFieldValue(record.parent, field)}${value ? `.[${value}]` : ''}` : - `[${value}]`; - } - - private filterImpl(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, - advancedExpressionsTree: IFilteringExpressionsTree, parent: ITreeGridRecord, grid?: GridType): ITreeGridRecord[] { - let i: number; - let rec: ITreeGridRecord; - const len = data.length; - const res: ITreeGridRecord[] = []; - if ((FilteringExpressionsTree.empty(expressionsTree) && FilteringExpressionsTree.empty(advancedExpressionsTree)) || !len) { - return data; - } - for (i = 0; i < len; i++) { - rec = DataUtil.cloneTreeGridRecord(data[i]); - rec.parent = parent; - if (rec.children) { - const filteredChildren = this.filterImpl(rec.children, expressionsTree, advancedExpressionsTree, rec, grid); - rec.children = filteredChildren.length > 0 ? filteredChildren : null; - } - - if (this.matchRecord(rec, expressionsTree, grid) && this.matchRecord(rec, advancedExpressionsTree, grid)) { - res.push(rec); - } else if (rec.children && rec.children.length > 0) { - rec.isFilteredOutParent = true; - res.push(rec); - } - } - return res; - } - - private isHierarchicalFilterField(field: string) { - return this.hierarchicalFilterFields && this.hierarchicalFilterFields.indexOf(field) !== -1; - } - - public getFilterItems(column: ColumnType, tree: IFilteringExpressionsTree): Promise { - if (!this.isHierarchicalFilterField(column.field)) { - return super.getFilterItems(column, tree); - } - - let data = (column.grid.gridAPI as IgxTreeGridAPIService).filterTreeDataByExpressions(tree); - data = DataUtil.treeGridSort( - data, - [{ fieldName: column.field, dir: SortingDirection.Asc, ignoreCase: column.sortingIgnoreCase }], - column.grid.sortStrategy, - null, - column.grid); - - const items = this.getHierarchicalFilterItems(data, column); - - - return Promise.resolve(items); - } - - private getHierarchicalFilterItems(records: ITreeGridRecord[], column: ColumnType, parent?: IgxFilterItem): IgxFilterItem[] { - return records?.map(record => { - let value = resolveNestedPath(record.data, column.field); - const applyFormatter = column.formatter && this.shouldFormatFilterValues(column); - - value = applyFormatter ? - column.formatter(value, record.data) : - value; - - const hierarchicalValue = parent ? - (value || value === 0) ? `${parent.value}.[${value}]` : value : - `[${value}]`; - - const filterItem: IgxFilterItem = { value: hierarchicalValue }; - filterItem.label = this.getFilterItemLabel(column, value, !applyFormatter, record.data); - filterItem.children = this.getHierarchicalFilterItems(record.children, column, filterItem); - return filterItem; - }); - } -} - -export class TreeGridFormattedValuesFilteringStrategy extends TreeGridFilteringStrategy { - /** - * Creates a new instance of FormattedValuesFilteringStrategy. - * - * @param fields An array of column field names that should be formatted. - * If omitted the values of all columns which has formatter will be formatted. - */ - constructor(private fields?: string[]) { - super(); - } - - protected shouldFormatFilterValues(column: ColumnType): boolean { - return !this.fields || this.fields.length === 0 || this.fields.some(f => f === column.field); - } -} - -export class TreeGridMatchingRecordsOnlyFilteringStrategy extends TreeGridFilteringStrategy { - public filter(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, - advancedExpressionsTree?: IFilteringExpressionsTree, grid?: GridType): ITreeGridRecord[] { - return this.filterImplementation(data, expressionsTree, advancedExpressionsTree, undefined, grid); - } - - private filterImplementation(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, - advancedExpressionsTree: IFilteringExpressionsTree, parent: ITreeGridRecord, grid?: GridType): ITreeGridRecord[] { - let i: number; - let rec: ITreeGridRecord; - const len = data.length; - const res: ITreeGridRecord[] = []; - if ((FilteringExpressionsTree.empty(expressionsTree) && FilteringExpressionsTree.empty(advancedExpressionsTree)) || !len) { - return data; - } - for (i = 0; i < len; i++) { - rec = DataUtil.cloneTreeGridRecord(data[i]); - rec.parent = parent; - if (rec.children) { - const filteredChildren = this.filterImplementation(rec.children, expressionsTree, advancedExpressionsTree, rec, grid); - rec.children = filteredChildren.length > 0 ? filteredChildren : null; - } - if (this.matchRecord(rec, expressionsTree, grid) && this.matchRecord(rec, advancedExpressionsTree, grid)) { - res.push(rec); - } else if (rec.children && rec.children.length > 0) { - rec = this.setCorrectLevelToFilteredRecords(rec); - res.push(...rec.children); - } - } - return res; - } - - private setCorrectLevelToFilteredRecords(rec: ITreeGridRecord): ITreeGridRecord { - if (rec.children && rec.children.length > 0) { - rec.children.map(child => { - child.level = child.level - 1; - return this.setCorrectLevelToFilteredRecords(child); - }); - } - return rec; - } -} +import { parseDate, resolveNestedPath } from '../../core/utils'; +import { DataUtil } from '../../data-operations/data-util'; +import { FilteringExpressionsTree, IFilteringExpressionsTree } from '../../data-operations/filtering-expressions-tree'; +import { BaseFilteringStrategy, IgxFilterItem } from '../../data-operations/filtering-strategy'; +import { SortingDirection } from '../../data-operations/sorting-strategy'; +import { ColumnType, GridType } from '../common/grid.interface'; +import { IgxTreeGridAPIService } from './tree-grid-api.service'; +import { ITreeGridRecord } from './tree-grid.interfaces'; + +export class TreeGridFilteringStrategy extends BaseFilteringStrategy { + + constructor(public hierarchicalFilterFields?: string[]) { + super(); + } + + public filter(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, + advancedExpressionsTree?: IFilteringExpressionsTree, grid?: GridType): ITreeGridRecord[] { + return this.filterImpl(data, expressionsTree, advancedExpressionsTree, undefined, grid); + } + + protected getFieldValue(rec: any, fieldName: string, isDate: boolean = false, isTime: boolean = false, grid?: GridType): any { + const column = grid?.getColumnByName(fieldName); + const hierarchicalRecord = rec as ITreeGridRecord; + let value = this.isHierarchicalFilterField(fieldName) ? + this.getHierarchicalFieldValue(hierarchicalRecord, fieldName) : + resolveNestedPath(hierarchicalRecord.data, fieldName); + + value = column?.formatter && this.shouldFormatFilterValues(column) ? + column.formatter(value, rec.data) : + value && (isDate || isTime) ? parseDate(value) : value; + + return value; + } + + private getHierarchicalFieldValue(record: ITreeGridRecord, field: string) { + const value = resolveNestedPath(record.data, field); + + return record.parent ? + `${this.getHierarchicalFieldValue(record.parent, field)}${value ? `.[${value}]` : ''}` : + `[${value}]`; + } + + private filterImpl(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, + advancedExpressionsTree: IFilteringExpressionsTree, parent: ITreeGridRecord, grid?: GridType): ITreeGridRecord[] { + let i: number; + let rec: ITreeGridRecord; + const len = data.length; + const res: ITreeGridRecord[] = []; + if ((FilteringExpressionsTree.empty(expressionsTree) && FilteringExpressionsTree.empty(advancedExpressionsTree)) || !len) { + return data; + } + for (i = 0; i < len; i++) { + rec = DataUtil.cloneTreeGridRecord(data[i]); + rec.parent = parent; + if (rec.children) { + const filteredChildren = this.filterImpl(rec.children, expressionsTree, advancedExpressionsTree, rec, grid); + rec.children = filteredChildren.length > 0 ? filteredChildren : null; + } + + if (this.matchRecord(rec, expressionsTree, grid) && this.matchRecord(rec, advancedExpressionsTree, grid)) { + res.push(rec); + } else if (rec.children && rec.children.length > 0) { + rec.isFilteredOutParent = true; + res.push(rec); + } + } + return res; + } + + private isHierarchicalFilterField(field: string) { + return this.hierarchicalFilterFields && this.hierarchicalFilterFields.indexOf(field) !== -1; + } + + public getFilterItems(column: ColumnType, tree: IFilteringExpressionsTree): Promise { + if (!this.isHierarchicalFilterField(column.field)) { + return super.getFilterItems(column, tree); + } + + let data = (column.grid.gridAPI as IgxTreeGridAPIService).filterTreeDataByExpressions(tree); + data = DataUtil.treeGridSort( + data, + [{ fieldName: column.field, dir: SortingDirection.Asc, ignoreCase: column.sortingIgnoreCase }], + column.grid.sortStrategy, + null, + column.grid); + + const items = this.getHierarchicalFilterItems(data, column); + + + return Promise.resolve(items); + } + + private getHierarchicalFilterItems(records: ITreeGridRecord[], column: ColumnType, parent?: IgxFilterItem): IgxFilterItem[] { + return records?.map(record => { + let value = resolveNestedPath(record.data, column.field); + const applyFormatter = column.formatter && this.shouldFormatFilterValues(column); + + value = applyFormatter ? + column.formatter(value, record.data) : + value; + + const hierarchicalValue = parent ? + (value || value === 0) ? `${parent.value}.[${value}]` : value : + `[${value}]`; + + const filterItem: IgxFilterItem = { value: hierarchicalValue }; + filterItem.label = this.getFilterItemLabel(column, value, !applyFormatter, record.data); + filterItem.children = this.getHierarchicalFilterItems(record.children, column, filterItem); + return filterItem; + }); + } +} + +export class TreeGridFormattedValuesFilteringStrategy extends TreeGridFilteringStrategy { + /** + * Creates a new instance of FormattedValuesFilteringStrategy. + * + * @param fields An array of column field names that should be formatted. + * If omitted the values of all columns which has formatter will be formatted. + */ + constructor(private fields?: string[]) { + super(); + } + + protected shouldFormatFilterValues(column: ColumnType): boolean { + return !this.fields || this.fields.length === 0 || this.fields.some(f => f === column.field); + } +} + +export class TreeGridMatchingRecordsOnlyFilteringStrategy extends TreeGridFilteringStrategy { + public filter(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, + advancedExpressionsTree?: IFilteringExpressionsTree, grid?: GridType): ITreeGridRecord[] { + return this.filterImplementation(data, expressionsTree, advancedExpressionsTree, undefined, grid); + } + + private filterImplementation(data: ITreeGridRecord[], expressionsTree: IFilteringExpressionsTree, + advancedExpressionsTree: IFilteringExpressionsTree, parent: ITreeGridRecord, grid?: GridType): ITreeGridRecord[] { + let i: number; + let rec: ITreeGridRecord; + const len = data.length; + const res: ITreeGridRecord[] = []; + if ((FilteringExpressionsTree.empty(expressionsTree) && FilteringExpressionsTree.empty(advancedExpressionsTree)) || !len) { + return data; + } + for (i = 0; i < len; i++) { + rec = DataUtil.cloneTreeGridRecord(data[i]); + rec.parent = parent; + if (rec.children) { + const filteredChildren = this.filterImplementation(rec.children, expressionsTree, advancedExpressionsTree, rec, grid); + rec.children = filteredChildren.length > 0 ? filteredChildren : null; + } + if (this.matchRecord(rec, expressionsTree, grid) && this.matchRecord(rec, advancedExpressionsTree, grid)) { + res.push(rec); + } else if (rec.children && rec.children.length > 0) { + rec = this.setCorrectLevelToFilteredRecords(rec); + res.push(...rec.children); + } + } + return res; + } + + private setCorrectLevelToFilteredRecords(rec: ITreeGridRecord): ITreeGridRecord { + if (rec.children && rec.children.length > 0) { + rec.children.map(child => { + child.level = child.level - 1; + return this.setCorrectLevelToFilteredRecords(child); + }); + } + return rec; + } +} diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.html b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.html index 34c3cd3b46d..266b965252c 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.html +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.html @@ -1 +1 @@ - + diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.ts index e1ef3a1fdb4..cf37c6cfa77 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-content.component.ts @@ -1,14 +1,14 @@ -import { Component, HostBinding } from '@angular/core'; -import { IgxTabContentDirective } from '../tab-content.directive'; -import { IgxTabContentBase } from '../tabs.base'; - -@Component({ - selector: 'igx-bottom-nav-content', - templateUrl: 'bottom-nav-content.component.html', - providers: [{ provide: IgxTabContentBase, useExisting: IgxBottomNavContentComponent }] -}) -export class IgxBottomNavContentComponent extends IgxTabContentDirective { - /** @hidden */ - @HostBinding('class.igx-bottom-nav__panel') - public defaultClass = true; -} +import { Component, HostBinding } from '@angular/core'; +import { IgxTabContentDirective } from '../tab-content.directive'; +import { IgxTabContentBase } from '../tabs.base'; + +@Component({ + selector: 'igx-bottom-nav-content', + templateUrl: 'bottom-nav-content.component.html', + providers: [{ provide: IgxTabContentBase, useExisting: IgxBottomNavContentComponent }] +}) +export class IgxBottomNavContentComponent extends IgxTabContentDirective { + /** @hidden */ + @HostBinding('class.igx-bottom-nav__panel') + public defaultClass = true; +} diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.html b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.html index b391af18dca..6dbc7430638 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.html +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.html @@ -1 +1 @@ - + diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.ts index 529b8076027..1483be7568a 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-header.component.ts @@ -1,29 +1,29 @@ -import { Component, HostBinding } from '@angular/core'; -import { IgxTabHeaderDirective } from '../tab-header.directive'; -import { IgxTabHeaderBase } from '../tabs.base'; - -@Component({ - selector: 'igx-bottom-nav-header', - templateUrl: 'bottom-nav-header.component.html', - providers: [{ provide: IgxTabHeaderBase, useExisting: IgxBottomNavHeaderComponent }] -}) -export class IgxBottomNavHeaderComponent extends IgxTabHeaderDirective { - - /** @hidden */ - @HostBinding('class.igx-bottom-nav__menu-item--selected') - public get cssClassSelected(): boolean { - return this.tab.selected; - } - - /** @hidden */ - @HostBinding('class.igx-bottom-nav__menu-item--disabled') - public get cssClassDisabled(): boolean { - return this.tab.disabled; - } - - /** @hidden */ - @HostBinding('class.igx-bottom-nav__menu-item') - public get cssClass(): boolean { - return (!this.tab.disabled && !this.tab.selected); - } -} +import { Component, HostBinding } from '@angular/core'; +import { IgxTabHeaderDirective } from '../tab-header.directive'; +import { IgxTabHeaderBase } from '../tabs.base'; + +@Component({ + selector: 'igx-bottom-nav-header', + templateUrl: 'bottom-nav-header.component.html', + providers: [{ provide: IgxTabHeaderBase, useExisting: IgxBottomNavHeaderComponent }] +}) +export class IgxBottomNavHeaderComponent extends IgxTabHeaderDirective { + + /** @hidden */ + @HostBinding('class.igx-bottom-nav__menu-item--selected') + public get cssClassSelected(): boolean { + return this.tab.selected; + } + + /** @hidden */ + @HostBinding('class.igx-bottom-nav__menu-item--disabled') + public get cssClassDisabled(): boolean { + return this.tab.disabled; + } + + /** @hidden */ + @HostBinding('class.igx-bottom-nav__menu-item') + public get cssClass(): boolean { + return (!this.tab.disabled && !this.tab.selected); + } +} diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.html b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.html index ca97d87f8ba..24c573d1d00 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.html +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.html @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.ts index b7b22f5338e..5adf87ab26b 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav-item.component.ts @@ -1,10 +1,10 @@ -import { Component } from '@angular/core'; -import { IgxTabItemDirective } from '../tab-item.directive'; - -@Component({ - selector: 'igx-bottom-nav-item', - templateUrl: 'bottom-nav-item.component.html', - providers: [{ provide: IgxTabItemDirective, useExisting: IgxBottomNavItemComponent }] -}) -export class IgxBottomNavItemComponent extends IgxTabItemDirective { -} +import { Component } from '@angular/core'; +import { IgxTabItemDirective } from '../tab-item.directive'; + +@Component({ + selector: 'igx-bottom-nav-item', + templateUrl: 'bottom-nav-item.component.html', + providers: [{ provide: IgxTabItemDirective, useExisting: IgxBottomNavItemComponent }] +}) +export class IgxBottomNavItemComponent extends IgxTabItemDirective { +} diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.html b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.html index 0f6adba3c7e..e74a4b4d214 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.html +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.html @@ -1,14 +1,14 @@ - - - - -
- - - -
+ + + + +
+ + + +
diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.ts index 5cae503827c..99e3094cf32 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.component.ts @@ -1,55 +1,55 @@ -import { Component } from '@angular/core'; -import { IgxTabsBase } from '../tabs.base'; -import { IgxTabsDirective } from '../tabs.directive'; - - -/** @hidden */ -let NEXT_BOTTOM_NAV_ITEM_ID = 0; - -/** - * Bottom Navigation component enables the user to navigate among a number of contents displayed in a single view. - * - * @igxModule IgxBottomNavModule - * - * @igxTheme igx-bottom-nav-theme - * - * @igxKeywords bottom navigation - * - * @igxGroup Layouts - * - * @remarks - * The Ignite UI for Angular Bottom Navigation component enables the user to navigate among a number of contents - * displayed in a single view. The navigation through the contents is accomplished with the tab buttons located at bottom. - * - * @example - * ```html - * - * - * - * folder - * Tab 1 - * - * - * Content 1 - * - * - * ... - * - * ``` - */ -@Component({ - selector: 'igx-bottom-nav', - templateUrl: 'bottom-nav.component.html', - providers: [{ provide: IgxTabsBase, useExisting: IgxBottomNavComponent }] -}) -export class IgxBottomNavComponent extends IgxTabsDirective { - /** @hidden */ - protected _disableAnimation = true; - /** @hidden */ - protected componentName = 'igx-bottom-nav'; - - /** @hidden */ - protected getNextTabId() { - return NEXT_BOTTOM_NAV_ITEM_ID++; - } -} +import { Component } from '@angular/core'; +import { IgxTabsBase } from '../tabs.base'; +import { IgxTabsDirective } from '../tabs.directive'; + + +/** @hidden */ +let NEXT_BOTTOM_NAV_ITEM_ID = 0; + +/** + * Bottom Navigation component enables the user to navigate among a number of contents displayed in a single view. + * + * @igxModule IgxBottomNavModule + * + * @igxTheme igx-bottom-nav-theme + * + * @igxKeywords bottom navigation + * + * @igxGroup Layouts + * + * @remarks + * The Ignite UI for Angular Bottom Navigation component enables the user to navigate among a number of contents + * displayed in a single view. The navigation through the contents is accomplished with the tab buttons located at bottom. + * + * @example + * ```html + * + * + * + * folder + * Tab 1 + * + * + * Content 1 + * + * + * ... + * + * ``` + */ +@Component({ + selector: 'igx-bottom-nav', + templateUrl: 'bottom-nav.component.html', + providers: [{ provide: IgxTabsBase, useExisting: IgxBottomNavComponent }] +}) +export class IgxBottomNavComponent extends IgxTabsDirective { + /** @hidden */ + protected _disableAnimation = true; + /** @hidden */ + protected componentName = 'igx-bottom-nav'; + + /** @hidden */ + protected getNextTabId() { + return NEXT_BOTTOM_NAV_ITEM_ID++; + } +} diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.directives.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.directives.ts index 853d63c8129..88753b40db1 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.directives.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.directives.ts @@ -1,11 +1,11 @@ -import { Directive } from '@angular/core'; - -@Directive({ - selector: 'igx-bottom-nav-header-label,[igxBottomNavHeaderLabel]' -}) -export class IgxBottomNavHeaderLabelDirective { } - -@Directive({ - selector: 'igx-bottom-nav-header-icon,[igxBottomNavHeaderIcon]' -}) -export class IgxBottomNavHeaderIconDirective { } +import { Directive } from '@angular/core'; + +@Directive({ + selector: 'igx-bottom-nav-header-label,[igxBottomNavHeaderLabel]' +}) +export class IgxBottomNavHeaderLabelDirective { } + +@Directive({ + selector: 'igx-bottom-nav-header-icon,[igxBottomNavHeaderIcon]' +}) +export class IgxBottomNavHeaderIconDirective { } diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.module.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.module.ts index 2bf85ff52b5..d8153c19e6c 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.module.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/bottom-nav.module.ts @@ -1,32 +1,32 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { IgxRippleModule } from '../../directives/ripple/ripple.directive'; -import { IgxIconModule } from '../../icon/public_api'; -import { IgxBottomNavHeaderComponent } from './bottom-nav-header.component'; -import { IgxBottomNavHeaderIconDirective, IgxBottomNavHeaderLabelDirective } from './bottom-nav.directives'; -import { IgxBottomNavItemComponent } from './bottom-nav-item.component'; -import { IgxBottomNavContentComponent } from './bottom-nav-content.component'; -import { IgxBottomNavComponent } from './bottom-nav.component'; - -/** @hidden */ -@NgModule({ - declarations: [ - IgxBottomNavComponent, - IgxBottomNavItemComponent, - IgxBottomNavHeaderComponent, - IgxBottomNavContentComponent, - IgxBottomNavHeaderLabelDirective, - IgxBottomNavHeaderIconDirective - ], - exports: [ - IgxBottomNavComponent, - IgxBottomNavItemComponent, - IgxBottomNavHeaderComponent, - IgxBottomNavContentComponent, - IgxBottomNavHeaderLabelDirective, - IgxBottomNavHeaderIconDirective - ], - imports: [CommonModule, IgxIconModule, IgxRippleModule] -}) -export class IgxBottomNavModule { -} +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { IgxRippleModule } from '../../directives/ripple/ripple.directive'; +import { IgxIconModule } from '../../icon/public_api'; +import { IgxBottomNavHeaderComponent } from './bottom-nav-header.component'; +import { IgxBottomNavHeaderIconDirective, IgxBottomNavHeaderLabelDirective } from './bottom-nav.directives'; +import { IgxBottomNavItemComponent } from './bottom-nav-item.component'; +import { IgxBottomNavContentComponent } from './bottom-nav-content.component'; +import { IgxBottomNavComponent } from './bottom-nav.component'; + +/** @hidden */ +@NgModule({ + declarations: [ + IgxBottomNavComponent, + IgxBottomNavItemComponent, + IgxBottomNavHeaderComponent, + IgxBottomNavContentComponent, + IgxBottomNavHeaderLabelDirective, + IgxBottomNavHeaderIconDirective + ], + exports: [ + IgxBottomNavComponent, + IgxBottomNavItemComponent, + IgxBottomNavHeaderComponent, + IgxBottomNavContentComponent, + IgxBottomNavHeaderLabelDirective, + IgxBottomNavHeaderIconDirective + ], + imports: [CommonModule, IgxIconModule, IgxRippleModule] +}) +export class IgxBottomNavModule { +} diff --git a/projects/igniteui-angular/src/lib/tabs/bottom-nav/public_api.ts b/projects/igniteui-angular/src/lib/tabs/bottom-nav/public_api.ts index 938fffe0783..26da287fa68 100644 --- a/projects/igniteui-angular/src/lib/tabs/bottom-nav/public_api.ts +++ b/projects/igniteui-angular/src/lib/tabs/bottom-nav/public_api.ts @@ -1,6 +1,6 @@ -export * from './bottom-nav.component'; -export * from './bottom-nav-item.component'; -export * from './bottom-nav-header.component'; -export * from './bottom-nav.directives'; -export * from './bottom-nav-content.component'; -export * from './bottom-nav.module'; +export * from './bottom-nav.component'; +export * from './bottom-nav-item.component'; +export * from './bottom-nav-header.component'; +export * from './bottom-nav.directives'; +export * from './bottom-nav-content.component'; +export * from './bottom-nav.module'; diff --git a/projects/igniteui-angular/src/lib/tabs/public_api.ts b/projects/igniteui-angular/src/lib/tabs/public_api.ts index c9f50327016..5bf7b73ba74 100644 --- a/projects/igniteui-angular/src/lib/tabs/public_api.ts +++ b/projects/igniteui-angular/src/lib/tabs/public_api.ts @@ -1,4 +1,4 @@ -export * from './tab-header.directive'; -export * from './tab-item.directive'; -export * from './tab-content.directive'; -export * from './tabs.directive'; +export * from './tab-header.directive'; +export * from './tab-item.directive'; +export * from './tab-content.directive'; +export * from './tabs.directive'; diff --git a/projects/igniteui-angular/src/lib/tabs/tab-content.directive.ts b/projects/igniteui-angular/src/lib/tabs/tab-content.directive.ts index 405677d8596..e4900076129 100644 --- a/projects/igniteui-angular/src/lib/tabs/tab-content.directive.ts +++ b/projects/igniteui-angular/src/lib/tabs/tab-content.directive.ts @@ -1,32 +1,32 @@ -import { Directive, ElementRef, HostBinding } from '@angular/core'; -import { IgxTabItemDirective } from './tab-item.directive'; -import { IgxTabContentBase } from './tabs.base'; - -@Directive() -export abstract class IgxTabContentDirective implements IgxTabContentBase { - - /** @hidden */ - @HostBinding('attr.role') - public role = 'tabpanel'; - - /** @hidden */ - constructor(public tab: IgxTabItemDirective, private elementRef: ElementRef) { - } - - /** @hidden */ - @HostBinding('attr.tabindex') - public get tabIndex() { - return this.tab.selected ? 0 : -1; - } - - /** @hidden */ - @HostBinding('style.z-index') - public get zIndex() { - return this.tab.selected ? 'auto' : -1; - } - - /** @hidden */ - public get nativeElement() { - return this.elementRef.nativeElement; - }; -} +import { Directive, ElementRef, HostBinding } from '@angular/core'; +import { IgxTabItemDirective } from './tab-item.directive'; +import { IgxTabContentBase } from './tabs.base'; + +@Directive() +export abstract class IgxTabContentDirective implements IgxTabContentBase { + + /** @hidden */ + @HostBinding('attr.role') + public role = 'tabpanel'; + + /** @hidden */ + constructor(public tab: IgxTabItemDirective, private elementRef: ElementRef) { + } + + /** @hidden */ + @HostBinding('attr.tabindex') + public get tabIndex() { + return this.tab.selected ? 0 : -1; + } + + /** @hidden */ + @HostBinding('style.z-index') + public get zIndex() { + return this.tab.selected ? 'auto' : -1; + } + + /** @hidden */ + public get nativeElement() { + return this.elementRef.nativeElement; + }; +} diff --git a/projects/igniteui-angular/src/lib/tabs/tab-header.directive.ts b/projects/igniteui-angular/src/lib/tabs/tab-header.directive.ts index 77fb6d54426..ab5236beebf 100644 --- a/projects/igniteui-angular/src/lib/tabs/tab-header.directive.ts +++ b/projects/igniteui-angular/src/lib/tabs/tab-header.directive.ts @@ -1,52 +1,52 @@ - -import { Directive, ElementRef, HostBinding, HostListener } from '@angular/core'; -import { PlatformUtil } from '../core/utils'; -import { IgxTabItemDirective } from './tab-item.directive'; -import { IgxTabHeaderBase, IgxTabsBase } from './tabs.base'; - -@Directive() -export abstract class IgxTabHeaderDirective implements IgxTabHeaderBase { - - /** @hidden */ - @HostBinding('attr.role') - public role = 'tab'; - - /** @hidden */ - constructor( - protected tabs: IgxTabsBase, - public tab: IgxTabItemDirective, - private elementRef: ElementRef, - protected platform: PlatformUtil - ) { } - - /** @hidden */ - @HostBinding('attr.tabindex') - public get tabIndex() { - return this.tab.selected ? 0 : -1; - } - - /** @hidden */ - @HostBinding('attr.aria-selected') - public get ariaSelected() { - return this.tab.selected; - } - - /** @hidden */ - @HostBinding('attr.aria-disabled') - public get ariaDisabled() { - return this.tab.disabled; - } - - /** @hidden */ - @HostListener('click') - public onClick() { - if (this.tab.panelComponent) { - this.tabs.selectTab(this.tab, true); - } - } - - /** @hidden */ - public get nativeElement() { - return this.elementRef.nativeElement; - }; -} + +import { Directive, ElementRef, HostBinding, HostListener } from '@angular/core'; +import { PlatformUtil } from '../core/utils'; +import { IgxTabItemDirective } from './tab-item.directive'; +import { IgxTabHeaderBase, IgxTabsBase } from './tabs.base'; + +@Directive() +export abstract class IgxTabHeaderDirective implements IgxTabHeaderBase { + + /** @hidden */ + @HostBinding('attr.role') + public role = 'tab'; + + /** @hidden */ + constructor( + protected tabs: IgxTabsBase, + public tab: IgxTabItemDirective, + private elementRef: ElementRef, + protected platform: PlatformUtil + ) { } + + /** @hidden */ + @HostBinding('attr.tabindex') + public get tabIndex() { + return this.tab.selected ? 0 : -1; + } + + /** @hidden */ + @HostBinding('attr.aria-selected') + public get ariaSelected() { + return this.tab.selected; + } + + /** @hidden */ + @HostBinding('attr.aria-disabled') + public get ariaDisabled() { + return this.tab.disabled; + } + + /** @hidden */ + @HostListener('click') + public onClick() { + if (this.tab.panelComponent) { + this.tabs.selectTab(this.tab, true); + } + } + + /** @hidden */ + public get nativeElement() { + return this.elementRef.nativeElement; + }; +} diff --git a/projects/igniteui-angular/src/lib/tabs/tab-item.directive.ts b/projects/igniteui-angular/src/lib/tabs/tab-item.directive.ts index b65f50a5aeb..e6e34cf5974 100644 --- a/projects/igniteui-angular/src/lib/tabs/tab-item.directive.ts +++ b/projects/igniteui-angular/src/lib/tabs/tab-item.directive.ts @@ -1,62 +1,62 @@ -import { ContentChild, Directive, EventEmitter, Input, Output, TemplateRef, ViewChild } from '@angular/core'; -import { Direction, IgxSlideComponentBase } from '../carousel/carousel-base'; -import { IgxTabHeaderBase, IgxTabItemBase, IgxTabContentBase, IgxTabsBase } from './tabs.base'; - -@Directive() -export abstract class IgxTabItemDirective implements IgxTabItemBase, IgxSlideComponentBase { - - /** @hidden */ - @ContentChild(IgxTabHeaderBase) - public headerComponent: IgxTabHeaderBase; - - /** @hidden */ - @ContentChild(IgxTabContentBase) - public panelComponent: IgxTabContentBase; - - /** @hidden */ - @ViewChild('headerTemplate', { static: true }) - public headerTemplate: TemplateRef; - - /** @hidden */ - @ViewChild('panelTemplate', { static: true }) - public panelTemplate: TemplateRef; - - /** - * Output to enable support for two-way binding on [(selected)] - */ - @Output() - public selectedChange = new EventEmitter(); - - /** - * An @Input property that allows you to enable/disable the item. - */ - @Input() - public disabled = false; - - /** @hidden */ - public direction = Direction.NONE; - /** @hidden */ - public previous: boolean; - - private _selected = false; - - /** - * An @Input property which determines whether an item is selected. - */ - @Input() - public get selected(): boolean { - return this._selected; - }; - - public set selected(value: boolean) { - if (this._selected !== value) { - this._selected = value; - this.tabs.selectTab(this, this._selected); - this.selectedChange.emit(this._selected); - } - } - - /** @hidden */ - constructor(private tabs: IgxTabsBase) { - } -} +import { ContentChild, Directive, EventEmitter, Input, Output, TemplateRef, ViewChild } from '@angular/core'; +import { Direction, IgxSlideComponentBase } from '../carousel/carousel-base'; +import { IgxTabHeaderBase, IgxTabItemBase, IgxTabContentBase, IgxTabsBase } from './tabs.base'; + +@Directive() +export abstract class IgxTabItemDirective implements IgxTabItemBase, IgxSlideComponentBase { + + /** @hidden */ + @ContentChild(IgxTabHeaderBase) + public headerComponent: IgxTabHeaderBase; + + /** @hidden */ + @ContentChild(IgxTabContentBase) + public panelComponent: IgxTabContentBase; + + /** @hidden */ + @ViewChild('headerTemplate', { static: true }) + public headerTemplate: TemplateRef; + + /** @hidden */ + @ViewChild('panelTemplate', { static: true }) + public panelTemplate: TemplateRef; + + /** + * Output to enable support for two-way binding on [(selected)] + */ + @Output() + public selectedChange = new EventEmitter(); + + /** + * An @Input property that allows you to enable/disable the item. + */ + @Input() + public disabled = false; + + /** @hidden */ + public direction = Direction.NONE; + /** @hidden */ + public previous: boolean; + + private _selected = false; + + /** + * An @Input property which determines whether an item is selected. + */ + @Input() + public get selected(): boolean { + return this._selected; + }; + + public set selected(value: boolean) { + if (this._selected !== value) { + this._selected = value; + this.tabs.selectTab(this, this._selected); + this.selectedChange.emit(this._selected); + } + } + + /** @hidden */ + constructor(private tabs: IgxTabsBase) { + } +} diff --git a/projects/igniteui-angular/src/lib/tabs/tabs.base.ts b/projects/igniteui-angular/src/lib/tabs/tabs.base.ts index 472ceb0dc1c..87b3775869e 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs.base.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs.base.ts @@ -1,29 +1,29 @@ -import { QueryList, TemplateRef } from '@angular/core'; - -/** @hidden */ -export abstract class IgxTabsBase { - public items: QueryList; - public selectedIndex: number; - public abstract selectTab(tab: IgxTabItemBase, selected: boolean); -} - -/** @hidden */ -export abstract class IgxTabItemBase { - public disabled: boolean; - public selected: boolean; - public headerTemplate: TemplateRef; - public panelTemplate: TemplateRef; - public headerComponent: IgxTabHeaderBase; - public panelComponent: IgxTabContentBase; -} - -/** @hidden */ -export abstract class IgxTabHeaderBase { - public nativeElement: HTMLElement; -} - -/** @hidden */ -export abstract class IgxTabContentBase { - public nativeElement: HTMLElement; -} - +import { QueryList, TemplateRef } from '@angular/core'; + +/** @hidden */ +export abstract class IgxTabsBase { + public items: QueryList; + public selectedIndex: number; + public abstract selectTab(tab: IgxTabItemBase, selected: boolean); +} + +/** @hidden */ +export abstract class IgxTabItemBase { + public disabled: boolean; + public selected: boolean; + public headerTemplate: TemplateRef; + public panelTemplate: TemplateRef; + public headerComponent: IgxTabHeaderBase; + public panelComponent: IgxTabContentBase; +} + +/** @hidden */ +export abstract class IgxTabHeaderBase { + public nativeElement: HTMLElement; +} + +/** @hidden */ +export abstract class IgxTabContentBase { + public nativeElement: HTMLElement; +} + diff --git a/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts b/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts index ed0b821ee5c..3bb95b0159d 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs.directive.ts @@ -1,316 +1,316 @@ -import { AnimationBuilder } from '@angular/animations'; -import { - AfterViewInit, ChangeDetectorRef, ContentChildren, Directive, EventEmitter, - Input, OnDestroy, Output, QueryList -} from '@angular/core'; -import { Subscription } from 'rxjs'; -import { Direction, IgxCarouselComponentBase } from '../carousel/carousel-base'; -import { IBaseEventArgs } from '../core/utils'; -import { IgxDirectionality } from '../services/direction/directionality'; -import { IgxTabItemDirective } from './tab-item.directive'; -import { IgxTabContentBase, IgxTabsBase } from './tabs.base'; - -export interface ITabsBaseEventArgs extends IBaseEventArgs { - readonly owner: IgxTabsDirective; -} - -export interface ITabsSelectedIndexChangingEventArgs extends ITabsBaseEventArgs { - cancel: boolean; - readonly oldIndex: number; - newIndex: number; -} - -export interface ITabsSelectedItemChangeEventArgs extends ITabsBaseEventArgs { - readonly oldItem: IgxTabItemDirective; - readonly newItem: IgxTabItemDirective; -} - -@Directive() -export abstract class IgxTabsDirective extends IgxCarouselComponentBase implements IgxTabsBase, AfterViewInit, OnDestroy { - - /** - * An @Input property that gets/sets the index of the selected item. - * Default value is 0 if contents are defined otherwise defaults to -1. - */ - @Input() - public get selectedIndex(): number { - return this._selectedIndex; - } - - public set selectedIndex(value: number) { - if (this._selectedIndex !== value) { - let newIndex = value; - const oldIndex = this._selectedIndex; - const args: ITabsSelectedIndexChangingEventArgs = { - owner: this, - cancel: false, - oldIndex, - newIndex - }; - this.selectedIndexChanging.emit(args); - - if (!args.cancel) { - newIndex = args.newIndex; - this._selectedIndex = newIndex; - this.selectedIndexChange.emit(this._selectedIndex); - } - - this.updateSelectedTabs(oldIndex); - } - } - - /** - * Enables/disables the transition animation of the contents. - */ - @Input() - public get disableAnimation() { - return this._disableAnimation; - } - - public set disableAnimation(value: boolean) { - this._disableAnimation = value; - } - - /** - * Output to enable support for two-way binding on [(selectedIndex)] - */ - @Output() - public selectedIndexChange = new EventEmitter(); - - /** - * Emitted when the selected index is about to change. - */ - @Output() - public selectedIndexChanging = new EventEmitter(); - - /** - * Emitted when the selected item is changed. - */ - @Output() - public selectedItemChange = new EventEmitter(); - - /** - * Returns the items. - */ - @ContentChildren(IgxTabItemDirective) - public items: QueryList; - - /** - * Gets the selected item. - */ - public get selectedItem(): IgxTabItemDirective { - return this.items && this.selectedIndex >= 0 && this.selectedIndex < this.items.length ? - this.items.get(this.selectedIndex) : null; - } - - /** @hidden */ - @ContentChildren(IgxTabContentBase, { descendants: true }) - public panels: QueryList; - - /** @hidden */ - protected _disableAnimation = false; - /** @hidden */ - protected currentItem: IgxTabItemDirective; - /** @hidden */ - protected previousItem: IgxTabItemDirective; - /** @hidden */ - protected componentName: string; - - private _selectedIndex = -1; - private _itemChanges$: Subscription; - - /** @hidden */ - constructor(builder: AnimationBuilder, cdr: ChangeDetectorRef, public dir: IgxDirectionality) { - super(builder, cdr); - } - - /** @hidden */ - public ngAfterViewInit(): void { - if (this._selectedIndex === -1) { - const hasSelectedTab = this.items.some((tab, i) => { - if (tab.selected) { - this._selectedIndex = i; - } - return tab.selected; - }); - - if (!hasSelectedTab && this.hasPanels) { - this._selectedIndex = 0; - } - } - - // Use promise to avoid expression changed after check error - Promise.resolve().then(() => { - this.updateSelectedTabs(null, false); - }); - - this._itemChanges$ = this.items.changes.subscribe(() => { - this.onItemChanges(); - }); - - this.setAttributes(); - } - - /** @hidden */ - public ngOnDestroy(): void { - if (this._itemChanges$) { - this._itemChanges$.unsubscribe(); - } - } - - /** @hidden */ - public selectTab(tab: IgxTabItemDirective, selected: boolean): void { - if (!this.items) { - return; - } - - const tabs = this.items.toArray(); - - if (selected) { - const index = tabs.indexOf(tab); - if (index > -1) { - this.selectedIndex = index; - } - } else { - if (tabs.every(t => !t.selected)) { - this.selectedIndex = -1; - } - } - } - - /** @hidden */ - protected getPreviousElement(): HTMLElement { - return this.previousItem.panelComponent.nativeElement; - } - - /** @hidden */ - protected getCurrentElement(): HTMLElement { - return this.currentItem.panelComponent.nativeElement; - } - - /** @hidden */ - protected scrollTabHeaderIntoView() { - } - - /** @hidden */ - protected onItemChanges() { - this.setAttributes(); - - // Check if there is selected tab - let selectedIndex = -1; - this.items.some((tab, i) => { - if (tab.selected) { - selectedIndex = i; - } - return tab.selected; - }); - - if (selectedIndex >= 0) { - // Set the selected index to the tab that has selected=true - Promise.resolve().then(() => { - this.selectedIndex = selectedIndex; - }); - } else { - if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) { - // Select the tab on the same index the previous selected tab was - Promise.resolve().then(() => { - this.updateSelectedTabs(null); - }); - } else if (this.selectedIndex >= this.items.length) { - // Select the last tab - Promise.resolve().then(() => { - this.selectedIndex = this.items.length - 1; - }); - } - } - } - - private setAttributes() { - this.items.forEach(item => { - if (item.panelComponent && !item.headerComponent.nativeElement.getAttribute('id')) { - const id = this.getNextTabId(); - const tabHeaderId = `${this.componentName}-header-${id}`; - const tabPanelId = `${this.componentName}-content-${id}`; - - this.setHeaderAttribute(item, 'id', tabHeaderId); - this.setHeaderAttribute(item, 'aria-controls', tabPanelId); - this.setPanelAttribute(item, 'id', tabPanelId); - this.setPanelAttribute(item, 'aria-labelledby', tabHeaderId); - } - }); - } - - private setHeaderAttribute(item: IgxTabItemDirective, attrName: string, value: string) { - item.headerComponent.nativeElement.setAttribute(attrName, value); - } - - private setPanelAttribute(item: IgxTabItemDirective, attrName: string, value: string) { - item.panelComponent.nativeElement.setAttribute(attrName, value); - } - - private get hasPanels() { - return this.panels && this.panels.length; - } - - private updateSelectedTabs(oldSelectedIndex: number, raiseEvent = true) { - if (!this.items) { - return; - } - - let newTab: IgxTabItemDirective; - const oldTab = this.currentItem; - - // First select the new tab - if (this._selectedIndex >= 0 && this._selectedIndex < this.items.length) { - newTab = this.items.get(this._selectedIndex); - newTab.selected = true; - } - // Then unselect the other tabs - this.items.forEach((tab, i) => { - if (i !== this._selectedIndex) { - tab.selected = false; - } - }); - - if (this._selectedIndex !== oldSelectedIndex) { - this.scrollTabHeaderIntoView(); - this.triggerPanelAnimations(oldSelectedIndex); - - if (raiseEvent && newTab !== oldTab) { - this.selectedItemChange.emit({ - owner: this, - newItem: newTab, - oldItem: oldTab - }); - } - } - } - - private triggerPanelAnimations(oldSelectedIndex: number) { - const item = this.items.get(this._selectedIndex); - - if (item && - !this.disableAnimation && - this.hasPanels && - this.currentItem && - !this.currentItem.selected) { - item.direction = (!this.dir.rtl && this._selectedIndex > oldSelectedIndex) || - (this.dir.rtl && this._selectedIndex < oldSelectedIndex) - ? Direction.NEXT : Direction.PREV; - - if (this.previousItem && this.previousItem.previous) { - this.previousItem.previous = false; - } - this.currentItem.direction = item.direction; - - this.previousItem = this.currentItem; - this.currentItem = item; - this.triggerAnimations(); - } else { - this.currentItem = item; - } - } - - /** @hidden */ - protected abstract getNextTabId(); -} +import { AnimationBuilder } from '@angular/animations'; +import { + AfterViewInit, ChangeDetectorRef, ContentChildren, Directive, EventEmitter, + Input, OnDestroy, Output, QueryList +} from '@angular/core'; +import { Subscription } from 'rxjs'; +import { Direction, IgxCarouselComponentBase } from '../carousel/carousel-base'; +import { IBaseEventArgs } from '../core/utils'; +import { IgxDirectionality } from '../services/direction/directionality'; +import { IgxTabItemDirective } from './tab-item.directive'; +import { IgxTabContentBase, IgxTabsBase } from './tabs.base'; + +export interface ITabsBaseEventArgs extends IBaseEventArgs { + readonly owner: IgxTabsDirective; +} + +export interface ITabsSelectedIndexChangingEventArgs extends ITabsBaseEventArgs { + cancel: boolean; + readonly oldIndex: number; + newIndex: number; +} + +export interface ITabsSelectedItemChangeEventArgs extends ITabsBaseEventArgs { + readonly oldItem: IgxTabItemDirective; + readonly newItem: IgxTabItemDirective; +} + +@Directive() +export abstract class IgxTabsDirective extends IgxCarouselComponentBase implements IgxTabsBase, AfterViewInit, OnDestroy { + + /** + * An @Input property that gets/sets the index of the selected item. + * Default value is 0 if contents are defined otherwise defaults to -1. + */ + @Input() + public get selectedIndex(): number { + return this._selectedIndex; + } + + public set selectedIndex(value: number) { + if (this._selectedIndex !== value) { + let newIndex = value; + const oldIndex = this._selectedIndex; + const args: ITabsSelectedIndexChangingEventArgs = { + owner: this, + cancel: false, + oldIndex, + newIndex + }; + this.selectedIndexChanging.emit(args); + + if (!args.cancel) { + newIndex = args.newIndex; + this._selectedIndex = newIndex; + this.selectedIndexChange.emit(this._selectedIndex); + } + + this.updateSelectedTabs(oldIndex); + } + } + + /** + * Enables/disables the transition animation of the contents. + */ + @Input() + public get disableAnimation() { + return this._disableAnimation; + } + + public set disableAnimation(value: boolean) { + this._disableAnimation = value; + } + + /** + * Output to enable support for two-way binding on [(selectedIndex)] + */ + @Output() + public selectedIndexChange = new EventEmitter(); + + /** + * Emitted when the selected index is about to change. + */ + @Output() + public selectedIndexChanging = new EventEmitter(); + + /** + * Emitted when the selected item is changed. + */ + @Output() + public selectedItemChange = new EventEmitter(); + + /** + * Returns the items. + */ + @ContentChildren(IgxTabItemDirective) + public items: QueryList; + + /** + * Gets the selected item. + */ + public get selectedItem(): IgxTabItemDirective { + return this.items && this.selectedIndex >= 0 && this.selectedIndex < this.items.length ? + this.items.get(this.selectedIndex) : null; + } + + /** @hidden */ + @ContentChildren(IgxTabContentBase, { descendants: true }) + public panels: QueryList; + + /** @hidden */ + protected _disableAnimation = false; + /** @hidden */ + protected currentItem: IgxTabItemDirective; + /** @hidden */ + protected previousItem: IgxTabItemDirective; + /** @hidden */ + protected componentName: string; + + private _selectedIndex = -1; + private _itemChanges$: Subscription; + + /** @hidden */ + constructor(builder: AnimationBuilder, cdr: ChangeDetectorRef, public dir: IgxDirectionality) { + super(builder, cdr); + } + + /** @hidden */ + public ngAfterViewInit(): void { + if (this._selectedIndex === -1) { + const hasSelectedTab = this.items.some((tab, i) => { + if (tab.selected) { + this._selectedIndex = i; + } + return tab.selected; + }); + + if (!hasSelectedTab && this.hasPanels) { + this._selectedIndex = 0; + } + } + + // Use promise to avoid expression changed after check error + Promise.resolve().then(() => { + this.updateSelectedTabs(null, false); + }); + + this._itemChanges$ = this.items.changes.subscribe(() => { + this.onItemChanges(); + }); + + this.setAttributes(); + } + + /** @hidden */ + public ngOnDestroy(): void { + if (this._itemChanges$) { + this._itemChanges$.unsubscribe(); + } + } + + /** @hidden */ + public selectTab(tab: IgxTabItemDirective, selected: boolean): void { + if (!this.items) { + return; + } + + const tabs = this.items.toArray(); + + if (selected) { + const index = tabs.indexOf(tab); + if (index > -1) { + this.selectedIndex = index; + } + } else { + if (tabs.every(t => !t.selected)) { + this.selectedIndex = -1; + } + } + } + + /** @hidden */ + protected getPreviousElement(): HTMLElement { + return this.previousItem.panelComponent.nativeElement; + } + + /** @hidden */ + protected getCurrentElement(): HTMLElement { + return this.currentItem.panelComponent.nativeElement; + } + + /** @hidden */ + protected scrollTabHeaderIntoView() { + } + + /** @hidden */ + protected onItemChanges() { + this.setAttributes(); + + // Check if there is selected tab + let selectedIndex = -1; + this.items.some((tab, i) => { + if (tab.selected) { + selectedIndex = i; + } + return tab.selected; + }); + + if (selectedIndex >= 0) { + // Set the selected index to the tab that has selected=true + Promise.resolve().then(() => { + this.selectedIndex = selectedIndex; + }); + } else { + if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) { + // Select the tab on the same index the previous selected tab was + Promise.resolve().then(() => { + this.updateSelectedTabs(null); + }); + } else if (this.selectedIndex >= this.items.length) { + // Select the last tab + Promise.resolve().then(() => { + this.selectedIndex = this.items.length - 1; + }); + } + } + } + + private setAttributes() { + this.items.forEach(item => { + if (item.panelComponent && !item.headerComponent.nativeElement.getAttribute('id')) { + const id = this.getNextTabId(); + const tabHeaderId = `${this.componentName}-header-${id}`; + const tabPanelId = `${this.componentName}-content-${id}`; + + this.setHeaderAttribute(item, 'id', tabHeaderId); + this.setHeaderAttribute(item, 'aria-controls', tabPanelId); + this.setPanelAttribute(item, 'id', tabPanelId); + this.setPanelAttribute(item, 'aria-labelledby', tabHeaderId); + } + }); + } + + private setHeaderAttribute(item: IgxTabItemDirective, attrName: string, value: string) { + item.headerComponent.nativeElement.setAttribute(attrName, value); + } + + private setPanelAttribute(item: IgxTabItemDirective, attrName: string, value: string) { + item.panelComponent.nativeElement.setAttribute(attrName, value); + } + + private get hasPanels() { + return this.panels && this.panels.length; + } + + private updateSelectedTabs(oldSelectedIndex: number, raiseEvent = true) { + if (!this.items) { + return; + } + + let newTab: IgxTabItemDirective; + const oldTab = this.currentItem; + + // First select the new tab + if (this._selectedIndex >= 0 && this._selectedIndex < this.items.length) { + newTab = this.items.get(this._selectedIndex); + newTab.selected = true; + } + // Then unselect the other tabs + this.items.forEach((tab, i) => { + if (i !== this._selectedIndex) { + tab.selected = false; + } + }); + + if (this._selectedIndex !== oldSelectedIndex) { + this.scrollTabHeaderIntoView(); + this.triggerPanelAnimations(oldSelectedIndex); + + if (raiseEvent && newTab !== oldTab) { + this.selectedItemChange.emit({ + owner: this, + newItem: newTab, + oldItem: oldTab + }); + } + } + } + + private triggerPanelAnimations(oldSelectedIndex: number) { + const item = this.items.get(this._selectedIndex); + + if (item && + !this.disableAnimation && + this.hasPanels && + this.currentItem && + !this.currentItem.selected) { + item.direction = (!this.dir.rtl && this._selectedIndex > oldSelectedIndex) || + (this.dir.rtl && this._selectedIndex < oldSelectedIndex) + ? Direction.NEXT : Direction.PREV; + + if (this.previousItem && this.previousItem.previous) { + this.previousItem.previous = false; + } + this.currentItem.direction = item.direction; + + this.previousItem = this.currentItem; + this.currentItem = item; + this.triggerAnimations(); + } else { + this.currentItem = item; + } + } + + /** @hidden */ + protected abstract getNextTabId(); +} diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/public_api.ts b/projects/igniteui-angular/src/lib/tabs/tabs/public_api.ts index b4d539f9416..451005b04e3 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/public_api.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/public_api.ts @@ -1,6 +1,6 @@ -export * from './tabs.component'; -export * from './tab-item.component'; -export * from './tab-header.component'; -export * from './tabs.directives'; -export * from './tab-content.component'; -export * from './tabs.module'; +export * from './tabs.component'; +export * from './tab-item.component'; +export * from './tab-header.component'; +export * from './tabs.directives'; +export * from './tab-content.component'; +export * from './tabs.module'; diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.html b/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.html index 34c3cd3b46d..266b965252c 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.html +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.html @@ -1 +1 @@ - + diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.ts index 6766bf43405..8a80e259cac 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-content.component.ts @@ -1,14 +1,14 @@ -import { Component, HostBinding } from '@angular/core'; -import { IgxTabContentDirective } from '../tab-content.directive'; -import { IgxTabContentBase } from '../tabs.base'; - -@Component({ - selector: 'igx-tab-content', - templateUrl: 'tab-content.component.html', - providers: [{ provide: IgxTabContentBase, useExisting: IgxTabContentComponent }] -}) -export class IgxTabContentComponent extends IgxTabContentDirective { - /** @hidden */ - @HostBinding('class.igx-tabs__panel') - public cssClass = true; -} +import { Component, HostBinding } from '@angular/core'; +import { IgxTabContentDirective } from '../tab-content.directive'; +import { IgxTabContentBase } from '../tabs.base'; + +@Component({ + selector: 'igx-tab-content', + templateUrl: 'tab-content.component.html', + providers: [{ provide: IgxTabContentBase, useExisting: IgxTabContentComponent }] +}) +export class IgxTabContentComponent extends IgxTabContentDirective { + /** @hidden */ + @HostBinding('class.igx-tabs__panel') + public cssClass = true; +} diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.html b/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.html index 9140367f51a..832c9fd7d13 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.html +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.html @@ -1,7 +1,7 @@ - - -
- -
- - + + +
+ +
+ + diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts index b52a867fda8..f3deb0106d5 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-header.component.ts @@ -1,134 +1,134 @@ -import { AfterViewInit, Component, ElementRef, HostBinding, HostListener, NgZone, OnDestroy } from '@angular/core'; -import { IgxTabItemDirective } from '../tab-item.directive'; -import { IgxTabHeaderDirective } from '../tab-header.directive'; -import { IgxTabHeaderBase } from '../tabs.base'; -import { IgxTabsComponent } from './tabs.component'; -import { getResizeObserver } from '../../core/utils'; -import { PlatformUtil } from '../../core/utils'; -import { IgxDirectionality } from '../../services/direction/directionality'; - -@Component({ - selector: 'igx-tab-header', - templateUrl: 'tab-header.component.html', - providers: [{ provide: IgxTabHeaderBase, useExisting: IgxTabHeaderComponent }] -}) -export class IgxTabHeaderComponent extends IgxTabHeaderDirective implements AfterViewInit, OnDestroy { - - /** @hidden @internal */ - @HostBinding('class.igx-tabs__header-item--selected') - public get provideCssClassSelected(): boolean { - return this.tab.selected; - } - - /** @hidden @internal */ - @HostBinding('class.igx-tabs__header-item--disabled') - public get provideCssClassDisabled(): boolean { - return this.tab.disabled; - } - - /** @hidden @internal */ - @HostBinding('class.igx-tabs__header-item') - public cssClass = true; - - private _resizeObserver: ResizeObserver; - - /** @hidden @internal */ - constructor( - protected tabs: IgxTabsComponent, - tab: IgxTabItemDirective, - elementRef: ElementRef, - protected platform: PlatformUtil, - private ngZone: NgZone, - private dir: IgxDirectionality - ) { - super(tabs, tab, elementRef, platform); - } - - /** @hidden @internal */ - @HostListener('keydown', ['$event']) - public keyDown(event: KeyboardEvent) { - let unsupportedKey = false; - const itemsArray = this.tabs.items.toArray(); - const previousIndex = itemsArray.indexOf(this.tab); - let newIndex = previousIndex; - const hasDisabledItems = itemsArray.some((item) => item.disabled); - switch (event.key) { - case this.platform.KEYMAP.ARROW_RIGHT: - newIndex = this.getNewSelectionIndex(newIndex, itemsArray, event.key, hasDisabledItems); - break; - case this.platform.KEYMAP.ARROW_LEFT: - newIndex = this.getNewSelectionIndex(newIndex, itemsArray, event.key, hasDisabledItems); - break; - case this.platform.KEYMAP.HOME: - event.preventDefault(); - newIndex = 0; - while (itemsArray[newIndex].disabled && newIndex < itemsArray.length) { - newIndex = newIndex === itemsArray.length - 1 ? 0 : newIndex + 1; - } - break; - case this.platform.KEYMAP.END: - event.preventDefault(); - newIndex = itemsArray.length - 1; - while (hasDisabledItems && itemsArray[newIndex].disabled && newIndex > 0) { - newIndex = newIndex === 0 ? itemsArray.length - 1 : newIndex - 1; - } - break; - case this.platform.KEYMAP.ENTER: - if (!this.tab.panelComponent) { - this.nativeElement.click(); - } - unsupportedKey = true; - break; - case this.platform.KEYMAP.SPACE: - event.preventDefault(); - if (!this.tab.panelComponent) { - this.nativeElement.click(); - } - unsupportedKey = true; - break; - default: - unsupportedKey = true; - break; - } - - if (!unsupportedKey) { - itemsArray[newIndex].headerComponent.nativeElement.focus({preventScroll:true}); - if (this.tab.panelComponent) { - this.tabs.selectedIndex = newIndex; - } - } - } - - /** @hidden @internal */ - public ngAfterViewInit(): void { - this.ngZone.runOutsideAngular(() => { - this._resizeObserver = new (getResizeObserver())(() => { - this.tabs.realignSelectedIndicator(); - }); - this._resizeObserver.observe(this.nativeElement); - }); - } - - /** @hidden @internal */ - public ngOnDestroy(): void { - this.ngZone.runOutsideAngular(() => { - this._resizeObserver?.disconnect(); - }); - } - - private getNewSelectionIndex(newIndex: number, itemsArray: any[], key: string, hasDisabledItems: boolean): number { - if ((key === this.platform.KEYMAP.ARROW_RIGHT && !this.dir.rtl) || (key === this.platform.KEYMAP.ARROW_LEFT && this.dir.rtl)) { - newIndex = newIndex === itemsArray.length - 1 ? 0 : newIndex + 1; - while (hasDisabledItems && itemsArray[newIndex].disabled && newIndex < itemsArray.length) { - newIndex = newIndex === itemsArray.length - 1 ? 0 : newIndex + 1; - } - } else { - newIndex = newIndex === 0 ? itemsArray.length - 1 : newIndex - 1; - while (hasDisabledItems && itemsArray[newIndex].disabled && newIndex >= 0) { - newIndex = newIndex === 0 ? itemsArray.length - 1 : newIndex - 1; - } - } - return newIndex; - } -} - +import { AfterViewInit, Component, ElementRef, HostBinding, HostListener, NgZone, OnDestroy } from '@angular/core'; +import { IgxTabItemDirective } from '../tab-item.directive'; +import { IgxTabHeaderDirective } from '../tab-header.directive'; +import { IgxTabHeaderBase } from '../tabs.base'; +import { IgxTabsComponent } from './tabs.component'; +import { getResizeObserver } from '../../core/utils'; +import { PlatformUtil } from '../../core/utils'; +import { IgxDirectionality } from '../../services/direction/directionality'; + +@Component({ + selector: 'igx-tab-header', + templateUrl: 'tab-header.component.html', + providers: [{ provide: IgxTabHeaderBase, useExisting: IgxTabHeaderComponent }] +}) +export class IgxTabHeaderComponent extends IgxTabHeaderDirective implements AfterViewInit, OnDestroy { + + /** @hidden @internal */ + @HostBinding('class.igx-tabs__header-item--selected') + public get provideCssClassSelected(): boolean { + return this.tab.selected; + } + + /** @hidden @internal */ + @HostBinding('class.igx-tabs__header-item--disabled') + public get provideCssClassDisabled(): boolean { + return this.tab.disabled; + } + + /** @hidden @internal */ + @HostBinding('class.igx-tabs__header-item') + public cssClass = true; + + private _resizeObserver: ResizeObserver; + + /** @hidden @internal */ + constructor( + protected tabs: IgxTabsComponent, + tab: IgxTabItemDirective, + elementRef: ElementRef, + protected platform: PlatformUtil, + private ngZone: NgZone, + private dir: IgxDirectionality + ) { + super(tabs, tab, elementRef, platform); + } + + /** @hidden @internal */ + @HostListener('keydown', ['$event']) + public keyDown(event: KeyboardEvent) { + let unsupportedKey = false; + const itemsArray = this.tabs.items.toArray(); + const previousIndex = itemsArray.indexOf(this.tab); + let newIndex = previousIndex; + const hasDisabledItems = itemsArray.some((item) => item.disabled); + switch (event.key) { + case this.platform.KEYMAP.ARROW_RIGHT: + newIndex = this.getNewSelectionIndex(newIndex, itemsArray, event.key, hasDisabledItems); + break; + case this.platform.KEYMAP.ARROW_LEFT: + newIndex = this.getNewSelectionIndex(newIndex, itemsArray, event.key, hasDisabledItems); + break; + case this.platform.KEYMAP.HOME: + event.preventDefault(); + newIndex = 0; + while (itemsArray[newIndex].disabled && newIndex < itemsArray.length) { + newIndex = newIndex === itemsArray.length - 1 ? 0 : newIndex + 1; + } + break; + case this.platform.KEYMAP.END: + event.preventDefault(); + newIndex = itemsArray.length - 1; + while (hasDisabledItems && itemsArray[newIndex].disabled && newIndex > 0) { + newIndex = newIndex === 0 ? itemsArray.length - 1 : newIndex - 1; + } + break; + case this.platform.KEYMAP.ENTER: + if (!this.tab.panelComponent) { + this.nativeElement.click(); + } + unsupportedKey = true; + break; + case this.platform.KEYMAP.SPACE: + event.preventDefault(); + if (!this.tab.panelComponent) { + this.nativeElement.click(); + } + unsupportedKey = true; + break; + default: + unsupportedKey = true; + break; + } + + if (!unsupportedKey) { + itemsArray[newIndex].headerComponent.nativeElement.focus({preventScroll:true}); + if (this.tab.panelComponent) { + this.tabs.selectedIndex = newIndex; + } + } + } + + /** @hidden @internal */ + public ngAfterViewInit(): void { + this.ngZone.runOutsideAngular(() => { + this._resizeObserver = new (getResizeObserver())(() => { + this.tabs.realignSelectedIndicator(); + }); + this._resizeObserver.observe(this.nativeElement); + }); + } + + /** @hidden @internal */ + public ngOnDestroy(): void { + this.ngZone.runOutsideAngular(() => { + this._resizeObserver?.disconnect(); + }); + } + + private getNewSelectionIndex(newIndex: number, itemsArray: any[], key: string, hasDisabledItems: boolean): number { + if ((key === this.platform.KEYMAP.ARROW_RIGHT && !this.dir.rtl) || (key === this.platform.KEYMAP.ARROW_LEFT && this.dir.rtl)) { + newIndex = newIndex === itemsArray.length - 1 ? 0 : newIndex + 1; + while (hasDisabledItems && itemsArray[newIndex].disabled && newIndex < itemsArray.length) { + newIndex = newIndex === itemsArray.length - 1 ? 0 : newIndex + 1; + } + } else { + newIndex = newIndex === 0 ? itemsArray.length - 1 : newIndex - 1; + while (hasDisabledItems && itemsArray[newIndex].disabled && newIndex >= 0) { + newIndex = newIndex === 0 ? itemsArray.length - 1 : newIndex - 1; + } + } + return newIndex; + } +} + diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.html b/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.html index ea2b8f0d647..f49b848d342 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.html +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.html @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.ts index 24dc010328a..bdbeb63e24a 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tab-item.component.ts @@ -1,11 +1,11 @@ -import { Component } from '@angular/core'; -import { IgxTabItemDirective } from '../tab-item.directive'; - -@Component({ - selector: 'igx-tab-item', - templateUrl: 'tab-item.component.html', - providers: [{ provide: IgxTabItemDirective, useExisting: IgxTabItemComponent }] -}) -export class IgxTabItemComponent extends IgxTabItemDirective { - -} +import { Component } from '@angular/core'; +import { IgxTabItemDirective } from '../tab-item.directive'; + +@Component({ + selector: 'igx-tab-item', + templateUrl: 'tab-item.component.html', + providers: [{ provide: IgxTabItemDirective, useExisting: IgxTabItemComponent }] +}) +export class IgxTabItemComponent extends IgxTabItemDirective { + +} diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.html b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.html index e727ed4fe32..707a867a791 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.html +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.html @@ -1,24 +1,24 @@ -
- -
-
-
- - - -
-
-
-
-
- -
-
- - - +
+ +
+
+
+ + + +
+
+
+
+
+ +
+
+ + +
\ No newline at end of file diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts index 00976a05db2..6b8d181fdf5 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.component.ts @@ -1,337 +1,337 @@ -import { AnimationBuilder } from '@angular/animations'; -import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostBinding, Input, NgZone, OnDestroy, ViewChild } from '@angular/core'; -import { getResizeObserver, mkenum } from '../../core/utils'; -import { IgxDirectionality } from '../../services/direction/directionality'; -import { IgxTabsBase } from '../tabs.base'; -import { IgxTabsDirective } from '../tabs.directive'; - -export const IgxTabsAlignment = mkenum({ - start: 'start', - end: 'end', - center: 'center', - justify: 'justify' -}); - -/** @hidden */ -enum TabScrollButtonStyle { - Visible = 'visible', - Hidden = 'hidden', - NotDisplayed = 'not_displayed' -} - -export type IgxTabsAlignment = (typeof IgxTabsAlignment)[keyof typeof IgxTabsAlignment]; - -/** @hidden */ -let NEXT_TAB_ID = 0; - -/** - * Tabs component is used to organize or switch between similar data sets. - * - * @igxModule IgxTabsModule - * - * @igxTheme igx-tabs-theme - * - * @igxKeywords tabs - * - * @igxGroup Layouts - * - * @remarks - * The Ignite UI for Angular Tabs component places tabs at the top and allows for scrolling when there are multiple tab items on the screen. - * - * @example - * ```html - * - * - * - * folder - * Tab 1 - * - * - * Content 1 - * - * - * ... - * - * ``` - */ -@Component({ - selector: 'igx-tabs', - templateUrl: 'tabs.component.html', - providers: [{ provide: IgxTabsBase, useExisting: IgxTabsComponent }] -}) - -export class IgxTabsComponent extends IgxTabsDirective implements AfterViewInit, OnDestroy { - - /** - * An @Input property which determines the tab alignment. Defaults to `start`. - */ - @Input() - public get tabAlignment(): string | IgxTabsAlignment { - return this._tabAlignment; - }; - - public set tabAlignment(value: string | IgxTabsAlignment) { - this._tabAlignment = value; - requestAnimationFrame(() => { - this.updateScrollButtons(); - this.realignSelectedIndicator(); - }); - } - - /** @hidden */ - @ViewChild('headerContainer', { static: true }) - public headerContainer: ElementRef; - - /** @hidden */ - @ViewChild('viewPort', { static: true }) - public viewPort: ElementRef; - - /** @hidden */ - @ViewChild('itemsWrapper', { static: true }) - public itemsWrapper: ElementRef; - - /** @hidden */ - @ViewChild('itemsContainer', { static: true }) - public itemsContainer: ElementRef; - - /** @hidden */ - @ViewChild('selectedIndicator') - public selectedIndicator: ElementRef; - - /** @hidden */ - @ViewChild('scrollPrevButton') - public scrollPrevButton: ElementRef; - - /** @hidden */ - @ViewChild('scrollNextButton') - public scrollNextButton: ElementRef; - - /** @hidden */ - @HostBinding('class.igx-tabs') - public defaultClass = true; - - /** @hidden */ - public offset = 0; - - /** @hidden */ - protected componentName = 'igx-tabs'; - - private _tabAlignment: string | IgxTabsAlignment = 'start'; - private _resizeObserver: ResizeObserver; - - constructor(builder: AnimationBuilder, cdr: ChangeDetectorRef, private ngZone: NgZone, public dir: IgxDirectionality) { - super(builder, cdr, dir); - } - - - /** @hidden @internal */ - public ngAfterViewInit(): void { - super.ngAfterViewInit(); - - this.ngZone.runOutsideAngular(() => { - this._resizeObserver = new (getResizeObserver())(() => { - this.updateScrollButtons(); - this.realignSelectedIndicator(); - }); - this._resizeObserver.observe(this.headerContainer.nativeElement); - this._resizeObserver.observe(this.viewPort.nativeElement); - }); - } - - /** @hidden @internal */ - public ngOnDestroy(): void { - super.ngOnDestroy(); - - this.ngZone.runOutsideAngular(() => { - this._resizeObserver?.disconnect(); - }); - } - - /** @hidden */ - public scrollPrev() { - this.scroll(false); - } - - /** @hidden */ - public scrollNext() { - this.scroll(true); - } - - /** @hidden */ - public realignSelectedIndicator() { - if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) { - const header = this.items.get(this.selectedIndex).headerComponent.nativeElement; - this.alignSelectedIndicator(header, 0); - } - } - - /** @hidden */ - public resolveHeaderScrollClasses() { - return { - 'igx-tabs__header-scroll--start': this.tabAlignment === 'start', - 'igx-tabs__header-scroll--end': this.tabAlignment === 'end', - 'igx-tabs__header-scroll--center': this.tabAlignment === 'center', - 'igx-tabs__header-scroll--justify': this.tabAlignment === 'justify', - }; - } - - /** @hidden */ - protected scrollTabHeaderIntoView() { - if (this.selectedIndex >= 0) { - const tabItems = this.items.toArray(); - const tabHeaderNativeElement = tabItems[this.selectedIndex].headerComponent.nativeElement; - - // Scroll left if there is need - if (this.getElementOffset(tabHeaderNativeElement) < this.offset) { - this.scrollElement(tabHeaderNativeElement, false); - } - - // Scroll right if there is need - const viewPortOffsetWidth = this.viewPort.nativeElement.offsetWidth; - const delta = (this.getElementOffset(tabHeaderNativeElement) + tabHeaderNativeElement.offsetWidth) - (viewPortOffsetWidth + this.offset); - - // Fix for IE 11, a difference is accumulated from the widths calculations - if (delta > 1) { - this.scrollElement(tabHeaderNativeElement, true); - } - - this.alignSelectedIndicator(tabHeaderNativeElement); - } else { - this.hideSelectedIndicator(); - } - } - - /** @hidden */ - protected getNextTabId() { - return NEXT_TAB_ID++; - } - - /** @hidden */ - protected onItemChanges() { - super.onItemChanges(); - - Promise.resolve().then(() => { - this.updateScrollButtons(); - }); - } - - private alignSelectedIndicator(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)`; - } - } - - private hideSelectedIndicator(): void { - if (this.selectedIndicator) { - this.selectedIndicator.nativeElement.style.visibility = 'hidden'; - } - } - - private scroll(scrollNext: boolean): void { - const tabsArray = this.items.toArray(); - - for (let index = 0; index < tabsArray.length; index++) { - const tab = tabsArray[index]; - const element = tab.headerComponent.nativeElement; - if (scrollNext) { - if (element.offsetWidth + this.getElementOffset(element) > this.viewPort.nativeElement.offsetWidth + this.offset) { - this.scrollElement(element, scrollNext); - break; - } - } else { - if (this.getElementOffset(element) >= this.offset) { - this.scrollElement(tabsArray[index - 1].headerComponent.nativeElement, scrollNext); - break; - } - } - } - } - - private scrollElement(element: any, scrollNext: boolean): void { - const viewPortWidth = this.viewPort.nativeElement.offsetWidth; - - this.offset = (scrollNext) ? element.offsetWidth + this.getElementOffset(element) - viewPortWidth : this.getElementOffset(element); - this.viewPort.nativeElement.scrollLeft = this.getOffset(this.offset); - this.updateScrollButtons(); - } - - private updateScrollButtons() { - const itemsContainerWidth = this.getTabItemsContainerWidth(); - - const scrollPrevButtonStyle = this.resolveLeftScrollButtonStyle(itemsContainerWidth); - this.setScrollButtonStyle(this.scrollPrevButton.nativeElement, scrollPrevButtonStyle); - - const scrollNextButtonStyle = this.resolveRightScrollButtonStyle(itemsContainerWidth); - this.setScrollButtonStyle(this.scrollNextButton.nativeElement, scrollNextButtonStyle); - } - - private setScrollButtonStyle(button: HTMLElement, buttonStyle: TabScrollButtonStyle) { - if (buttonStyle === TabScrollButtonStyle.Visible) { - button.style.visibility = 'visible'; - button.style.display = ''; - } else if (buttonStyle === TabScrollButtonStyle.Hidden) { - button.style.visibility = 'hidden'; - button.style.display = ''; - } else if (buttonStyle === TabScrollButtonStyle.NotDisplayed) { - button.style.display = 'none'; - } - } - private resolveLeftScrollButtonStyle(itemsContainerWidth: number): TabScrollButtonStyle { - const headerContainerWidth = this.headerContainer.nativeElement.offsetWidth; - const offset = this.offset; - - if (offset === 0) { - // Fix for IE 11, a difference is accumulated from the widths calculations. - if (itemsContainerWidth - headerContainerWidth <= 1) { - return TabScrollButtonStyle.NotDisplayed; - } - return TabScrollButtonStyle.Hidden; - } else { - return TabScrollButtonStyle.Visible; - } - } - - private resolveRightScrollButtonStyle(itemsContainerWidth: number): TabScrollButtonStyle { - const viewPortWidth = this.viewPort.nativeElement.offsetWidth; - const headerContainerWidth = this.headerContainer.nativeElement.offsetWidth; - const offset = this.offset; - const total = offset + viewPortWidth; - - // Fix for IE 11, a difference is accumulated from the widths calculations. - if (itemsContainerWidth - headerContainerWidth <= 1 && offset === 0) { - return TabScrollButtonStyle.NotDisplayed; - } - - if (itemsContainerWidth > total) { - return TabScrollButtonStyle.Visible; - } else { - return TabScrollButtonStyle.Hidden; - } - } - - private getTabItemsContainerWidth() { - // We use this hacky way to get the width of the itemsContainer, - // because there is inconsistency in IE we cannot use offsetWidth or scrollOffset. - const itemsContainerChildrenCount = this.itemsContainer.nativeElement.children.length; - let itemsContainerWidth = 0; - - if (itemsContainerChildrenCount > 1) { - const lastTab = this.itemsContainer.nativeElement.children[itemsContainerChildrenCount - 1] as HTMLElement; - itemsContainerWidth = this.getElementOffset(lastTab) + lastTab.offsetWidth; - } - - return itemsContainerWidth; - } - - private getOffset(offset: number): number { - return this.dir.rtl ? -offset : offset; - } - - private getElementOffset(element: HTMLElement): number { - return this.dir.rtl ? this.itemsWrapper.nativeElement.offsetWidth - element.offsetLeft - element.offsetWidth : element.offsetLeft; - } -} - +import { AnimationBuilder } from '@angular/animations'; +import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, HostBinding, Input, NgZone, OnDestroy, ViewChild } from '@angular/core'; +import { getResizeObserver, mkenum } from '../../core/utils'; +import { IgxDirectionality } from '../../services/direction/directionality'; +import { IgxTabsBase } from '../tabs.base'; +import { IgxTabsDirective } from '../tabs.directive'; + +export const IgxTabsAlignment = mkenum({ + start: 'start', + end: 'end', + center: 'center', + justify: 'justify' +}); + +/** @hidden */ +enum TabScrollButtonStyle { + Visible = 'visible', + Hidden = 'hidden', + NotDisplayed = 'not_displayed' +} + +export type IgxTabsAlignment = (typeof IgxTabsAlignment)[keyof typeof IgxTabsAlignment]; + +/** @hidden */ +let NEXT_TAB_ID = 0; + +/** + * Tabs component is used to organize or switch between similar data sets. + * + * @igxModule IgxTabsModule + * + * @igxTheme igx-tabs-theme + * + * @igxKeywords tabs + * + * @igxGroup Layouts + * + * @remarks + * The Ignite UI for Angular Tabs component places tabs at the top and allows for scrolling when there are multiple tab items on the screen. + * + * @example + * ```html + * + * + * + * folder + * Tab 1 + * + * + * Content 1 + * + * + * ... + * + * ``` + */ +@Component({ + selector: 'igx-tabs', + templateUrl: 'tabs.component.html', + providers: [{ provide: IgxTabsBase, useExisting: IgxTabsComponent }] +}) + +export class IgxTabsComponent extends IgxTabsDirective implements AfterViewInit, OnDestroy { + + /** + * An @Input property which determines the tab alignment. Defaults to `start`. + */ + @Input() + public get tabAlignment(): string | IgxTabsAlignment { + return this._tabAlignment; + }; + + public set tabAlignment(value: string | IgxTabsAlignment) { + this._tabAlignment = value; + requestAnimationFrame(() => { + this.updateScrollButtons(); + this.realignSelectedIndicator(); + }); + } + + /** @hidden */ + @ViewChild('headerContainer', { static: true }) + public headerContainer: ElementRef; + + /** @hidden */ + @ViewChild('viewPort', { static: true }) + public viewPort: ElementRef; + + /** @hidden */ + @ViewChild('itemsWrapper', { static: true }) + public itemsWrapper: ElementRef; + + /** @hidden */ + @ViewChild('itemsContainer', { static: true }) + public itemsContainer: ElementRef; + + /** @hidden */ + @ViewChild('selectedIndicator') + public selectedIndicator: ElementRef; + + /** @hidden */ + @ViewChild('scrollPrevButton') + public scrollPrevButton: ElementRef; + + /** @hidden */ + @ViewChild('scrollNextButton') + public scrollNextButton: ElementRef; + + /** @hidden */ + @HostBinding('class.igx-tabs') + public defaultClass = true; + + /** @hidden */ + public offset = 0; + + /** @hidden */ + protected componentName = 'igx-tabs'; + + private _tabAlignment: string | IgxTabsAlignment = 'start'; + private _resizeObserver: ResizeObserver; + + constructor(builder: AnimationBuilder, cdr: ChangeDetectorRef, private ngZone: NgZone, public dir: IgxDirectionality) { + super(builder, cdr, dir); + } + + + /** @hidden @internal */ + public ngAfterViewInit(): void { + super.ngAfterViewInit(); + + this.ngZone.runOutsideAngular(() => { + this._resizeObserver = new (getResizeObserver())(() => { + this.updateScrollButtons(); + this.realignSelectedIndicator(); + }); + this._resizeObserver.observe(this.headerContainer.nativeElement); + this._resizeObserver.observe(this.viewPort.nativeElement); + }); + } + + /** @hidden @internal */ + public ngOnDestroy(): void { + super.ngOnDestroy(); + + this.ngZone.runOutsideAngular(() => { + this._resizeObserver?.disconnect(); + }); + } + + /** @hidden */ + public scrollPrev() { + this.scroll(false); + } + + /** @hidden */ + public scrollNext() { + this.scroll(true); + } + + /** @hidden */ + public realignSelectedIndicator() { + if (this.selectedIndex >= 0 && this.selectedIndex < this.items.length) { + const header = this.items.get(this.selectedIndex).headerComponent.nativeElement; + this.alignSelectedIndicator(header, 0); + } + } + + /** @hidden */ + public resolveHeaderScrollClasses() { + return { + 'igx-tabs__header-scroll--start': this.tabAlignment === 'start', + 'igx-tabs__header-scroll--end': this.tabAlignment === 'end', + 'igx-tabs__header-scroll--center': this.tabAlignment === 'center', + 'igx-tabs__header-scroll--justify': this.tabAlignment === 'justify', + }; + } + + /** @hidden */ + protected scrollTabHeaderIntoView() { + if (this.selectedIndex >= 0) { + const tabItems = this.items.toArray(); + const tabHeaderNativeElement = tabItems[this.selectedIndex].headerComponent.nativeElement; + + // Scroll left if there is need + if (this.getElementOffset(tabHeaderNativeElement) < this.offset) { + this.scrollElement(tabHeaderNativeElement, false); + } + + // Scroll right if there is need + const viewPortOffsetWidth = this.viewPort.nativeElement.offsetWidth; + const delta = (this.getElementOffset(tabHeaderNativeElement) + tabHeaderNativeElement.offsetWidth) - (viewPortOffsetWidth + this.offset); + + // Fix for IE 11, a difference is accumulated from the widths calculations + if (delta > 1) { + this.scrollElement(tabHeaderNativeElement, true); + } + + this.alignSelectedIndicator(tabHeaderNativeElement); + } else { + this.hideSelectedIndicator(); + } + } + + /** @hidden */ + protected getNextTabId() { + return NEXT_TAB_ID++; + } + + /** @hidden */ + protected onItemChanges() { + super.onItemChanges(); + + Promise.resolve().then(() => { + this.updateScrollButtons(); + }); + } + + private alignSelectedIndicator(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)`; + } + } + + private hideSelectedIndicator(): void { + if (this.selectedIndicator) { + this.selectedIndicator.nativeElement.style.visibility = 'hidden'; + } + } + + private scroll(scrollNext: boolean): void { + const tabsArray = this.items.toArray(); + + for (let index = 0; index < tabsArray.length; index++) { + const tab = tabsArray[index]; + const element = tab.headerComponent.nativeElement; + if (scrollNext) { + if (element.offsetWidth + this.getElementOffset(element) > this.viewPort.nativeElement.offsetWidth + this.offset) { + this.scrollElement(element, scrollNext); + break; + } + } else { + if (this.getElementOffset(element) >= this.offset) { + this.scrollElement(tabsArray[index - 1].headerComponent.nativeElement, scrollNext); + break; + } + } + } + } + + private scrollElement(element: any, scrollNext: boolean): void { + const viewPortWidth = this.viewPort.nativeElement.offsetWidth; + + this.offset = (scrollNext) ? element.offsetWidth + this.getElementOffset(element) - viewPortWidth : this.getElementOffset(element); + this.viewPort.nativeElement.scrollLeft = this.getOffset(this.offset); + this.updateScrollButtons(); + } + + private updateScrollButtons() { + const itemsContainerWidth = this.getTabItemsContainerWidth(); + + const scrollPrevButtonStyle = this.resolveLeftScrollButtonStyle(itemsContainerWidth); + this.setScrollButtonStyle(this.scrollPrevButton.nativeElement, scrollPrevButtonStyle); + + const scrollNextButtonStyle = this.resolveRightScrollButtonStyle(itemsContainerWidth); + this.setScrollButtonStyle(this.scrollNextButton.nativeElement, scrollNextButtonStyle); + } + + private setScrollButtonStyle(button: HTMLElement, buttonStyle: TabScrollButtonStyle) { + if (buttonStyle === TabScrollButtonStyle.Visible) { + button.style.visibility = 'visible'; + button.style.display = ''; + } else if (buttonStyle === TabScrollButtonStyle.Hidden) { + button.style.visibility = 'hidden'; + button.style.display = ''; + } else if (buttonStyle === TabScrollButtonStyle.NotDisplayed) { + button.style.display = 'none'; + } + } + private resolveLeftScrollButtonStyle(itemsContainerWidth: number): TabScrollButtonStyle { + const headerContainerWidth = this.headerContainer.nativeElement.offsetWidth; + const offset = this.offset; + + if (offset === 0) { + // Fix for IE 11, a difference is accumulated from the widths calculations. + if (itemsContainerWidth - headerContainerWidth <= 1) { + return TabScrollButtonStyle.NotDisplayed; + } + return TabScrollButtonStyle.Hidden; + } else { + return TabScrollButtonStyle.Visible; + } + } + + private resolveRightScrollButtonStyle(itemsContainerWidth: number): TabScrollButtonStyle { + const viewPortWidth = this.viewPort.nativeElement.offsetWidth; + const headerContainerWidth = this.headerContainer.nativeElement.offsetWidth; + const offset = this.offset; + const total = offset + viewPortWidth; + + // Fix for IE 11, a difference is accumulated from the widths calculations. + if (itemsContainerWidth - headerContainerWidth <= 1 && offset === 0) { + return TabScrollButtonStyle.NotDisplayed; + } + + if (itemsContainerWidth > total) { + return TabScrollButtonStyle.Visible; + } else { + return TabScrollButtonStyle.Hidden; + } + } + + private getTabItemsContainerWidth() { + // We use this hacky way to get the width of the itemsContainer, + // because there is inconsistency in IE we cannot use offsetWidth or scrollOffset. + const itemsContainerChildrenCount = this.itemsContainer.nativeElement.children.length; + let itemsContainerWidth = 0; + + if (itemsContainerChildrenCount > 1) { + const lastTab = this.itemsContainer.nativeElement.children[itemsContainerChildrenCount - 1] as HTMLElement; + itemsContainerWidth = this.getElementOffset(lastTab) + lastTab.offsetWidth; + } + + return itemsContainerWidth; + } + + private getOffset(offset: number): number { + return this.dir.rtl ? -offset : offset; + } + + private getElementOffset(element: HTMLElement): number { + return this.dir.rtl ? this.itemsWrapper.nativeElement.offsetWidth - element.offsetLeft - element.offsetWidth : element.offsetLeft; + } +} + diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.directives.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.directives.ts index cd41313c01b..4d361fefdc1 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.directives.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.directives.ts @@ -1,11 +1,11 @@ -import { Directive } from '@angular/core'; - -@Directive({ - selector: 'igx-tab-header-label,[igxTabHeaderLabel]' -}) -export class IgxTabHeaderLabelDirective { } - -@Directive({ - selector: 'igx-tab-header-icon,[igxTabHeaderIcon]' -}) -export class IgxTabHeaderIconDirective { } +import { Directive } from '@angular/core'; + +@Directive({ + selector: 'igx-tab-header-label,[igxTabHeaderLabel]' +}) +export class IgxTabHeaderLabelDirective { } + +@Directive({ + selector: 'igx-tab-header-icon,[igxTabHeaderIcon]' +}) +export class IgxTabHeaderIconDirective { } diff --git a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.module.ts b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.module.ts index ea22e2f0cc7..adce4e86ac2 100644 --- a/projects/igniteui-angular/src/lib/tabs/tabs/tabs.module.ts +++ b/projects/igniteui-angular/src/lib/tabs/tabs/tabs.module.ts @@ -1,36 +1,36 @@ -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { IgxRippleModule } from '../../directives/ripple/ripple.directive'; -import { IgxIconModule } from '../../icon/public_api'; -import { IgxTabHeaderComponent } from './tab-header.component'; -import { IgxTabHeaderIconDirective, IgxTabHeaderLabelDirective } from './tabs.directives'; -import { IgxTabItemComponent } from './tab-item.component'; -import { IgxTabContentComponent } from './tab-content.component'; -import { IgxTabsComponent } from './tabs.component'; -import { IgxPrefixModule } from '../../directives/prefix/prefix.directive'; -import { IgxSuffixModule } from '../../directives/suffix/suffix.directive'; - -/** @hidden */ -@NgModule({ - declarations: [ - IgxTabsComponent, - IgxTabItemComponent, - IgxTabHeaderComponent, - IgxTabContentComponent, - IgxTabHeaderLabelDirective, - IgxTabHeaderIconDirective - ], - exports: [ - IgxTabsComponent, - IgxTabItemComponent, - IgxTabHeaderComponent, - IgxTabContentComponent, - IgxTabHeaderLabelDirective, - IgxTabHeaderIconDirective, - IgxPrefixModule, - IgxSuffixModule - ], - imports: [CommonModule, IgxIconModule, IgxRippleModule, IgxPrefixModule, IgxSuffixModule] -}) -export class IgxTabsModule { -} +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { IgxRippleModule } from '../../directives/ripple/ripple.directive'; +import { IgxIconModule } from '../../icon/public_api'; +import { IgxTabHeaderComponent } from './tab-header.component'; +import { IgxTabHeaderIconDirective, IgxTabHeaderLabelDirective } from './tabs.directives'; +import { IgxTabItemComponent } from './tab-item.component'; +import { IgxTabContentComponent } from './tab-content.component'; +import { IgxTabsComponent } from './tabs.component'; +import { IgxPrefixModule } from '../../directives/prefix/prefix.directive'; +import { IgxSuffixModule } from '../../directives/suffix/suffix.directive'; + +/** @hidden */ +@NgModule({ + declarations: [ + IgxTabsComponent, + IgxTabItemComponent, + IgxTabHeaderComponent, + IgxTabContentComponent, + IgxTabHeaderLabelDirective, + IgxTabHeaderIconDirective + ], + exports: [ + IgxTabsComponent, + IgxTabItemComponent, + IgxTabHeaderComponent, + IgxTabContentComponent, + IgxTabHeaderLabelDirective, + IgxTabHeaderIconDirective, + IgxPrefixModule, + IgxSuffixModule + ], + imports: [CommonModule, IgxIconModule, IgxRippleModule, IgxPrefixModule, IgxSuffixModule] +}) +export class IgxTabsModule { +} diff --git a/src/app/grid-cell-api/grid-cell-api.sample.css b/src/app/grid-cell-api/grid-cell-api.sample.css index f814d60a525..824423498ba 100644 --- a/src/app/grid-cell-api/grid-cell-api.sample.css +++ b/src/app/grid-cell-api/grid-cell-api.sample.css @@ -1,76 +1,76 @@ -.sample-buttons { - margin-top: 24px; -} - -[igxButton] { - margin-right: 8px; - margin-bottom: 8px; -} - -.density-chooser { - margin-bottom: 16px; - max-width: 900px; -} - -.references { - font-size: .75em; -} - -.references>p { - margin: 0; - letter-spacing: initial; - line-height: initial; - font-size: 1em; -} - -.sample-column { - width: 60%; - margin: 8px; - flex-flow: ''; -} - -.log-wrapper { - width: 30%; -} - -.clearBtn { - top: 3px; - margin-left: 20px; -} - -.logContainer { - padding: 0.2rem 0.4rem; -} - -:host { - width: 100%; -} - -.sample-column { - display: flex; - flex-flow: row wrap !important; - width: 100%; -} - -.grid-wrapper { - width: 60%; -} - -.clearBtn { - top: 3px; - margin-left: 20px; -} - -.selected-data-area { - overflow-y: auto; - max-height: 550px; - width: 100%; - height: 100%; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); - margin-top: 8px; -} - -.highlight { - text-align: center; - margin-bottom: 0.4rem; +.sample-buttons { + margin-top: 24px; +} + +[igxButton] { + margin-right: 8px; + margin-bottom: 8px; +} + +.density-chooser { + margin-bottom: 16px; + max-width: 900px; +} + +.references { + font-size: .75em; +} + +.references>p { + margin: 0; + letter-spacing: initial; + line-height: initial; + font-size: 1em; +} + +.sample-column { + width: 60%; + margin: 8px; + flex-flow: ''; +} + +.log-wrapper { + width: 30%; +} + +.clearBtn { + top: 3px; + margin-left: 20px; +} + +.logContainer { + padding: 0.2rem 0.4rem; +} + +:host { + width: 100%; +} + +.sample-column { + display: flex; + flex-flow: row wrap !important; + width: 100%; +} + +.grid-wrapper { + width: 60%; +} + +.clearBtn { + top: 3px; + margin-left: 20px; +} + +.selected-data-area { + overflow-y: auto; + max-height: 550px; + width: 100%; + height: 100%; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); + margin-top: 8px; +} + +.highlight { + text-align: center; + margin-bottom: 0.4rem; } \ No newline at end of file diff --git a/src/app/grid-cell-api/grid-cell-api.sample.html b/src/app/grid-cell-api/grid-cell-api.sample.html index 6af6f69b693..6cad8da28fe 100644 --- a/src/app/grid-cell-api/grid-cell-api.sample.html +++ b/src/app/grid-cell-api/grid-cell-api.sample.html @@ -1,303 +1,303 @@ -
-
igxGrid
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- One digit indicates Column Index. Two digits indicates rowIndex, colIndex
- -
- - -
-
-
- - - - -
-
Country: {{dataItem.Country}}
-
City: {{dataItem.City}}
-
Address: {{dataItem.Address}}
-
-
- - - - - - - - - -
-
-
-
-
-
- -
-
-
-
- -
-
IgxTreeGrid Hierarchical Data
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- One digit indicates Column Index. Two digits indicates rowIndex, colIndex
- -
- - -
-
-
- - - - - - - - - - - - -
-
-
-
-
- -
-
-
- -
-
IgxTreeGrid Flat Data
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- One digit indicates Column Index. Two digits indicates rowIndex, colIndex
- -
- - -
-
-
- - - - - - - - - - - - -
-
-
-
-
- -
-
-
- -
-
igxHierarchicalGrid
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- One digit indicates Column Index. Two digits indicates rowIndex, colIndex
- -
- - -
-
-
- - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- -
-
-
+
+
igxGrid
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ One digit indicates Column Index. Two digits indicates rowIndex, colIndex
+ +
+ + +
+
+
+ + + + +
+
Country: {{dataItem.Country}}
+
City: {{dataItem.City}}
+
Address: {{dataItem.Address}}
+
+
+ + + + + + + + + +
+
+
+
+
+
+ +
+
+
+
+ +
+
IgxTreeGrid Hierarchical Data
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ One digit indicates Column Index. Two digits indicates rowIndex, colIndex
+ +
+ + +
+
+
+ + + + + + + + + + + + +
+
+
+
+
+ +
+
+
+ +
+
IgxTreeGrid Flat Data
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ One digit indicates Column Index. Two digits indicates rowIndex, colIndex
+ +
+ + +
+
+
+ + + + + + + + + + + + +
+
+
+
+
+ +
+
+
+ +
+
igxHierarchicalGrid
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ One digit indicates Column Index. Two digits indicates rowIndex, colIndex
+ +
+ + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +
+
+
diff --git a/src/app/grid-cell-api/grid-cell-api.sample.ts b/src/app/grid-cell-api/grid-cell-api.sample.ts index cf9c10d5219..e747876d8b0 100644 --- a/src/app/grid-cell-api/grid-cell-api.sample.ts +++ b/src/app/grid-cell-api/grid-cell-api.sample.ts @@ -1,367 +1,367 @@ -import { Component, OnInit, Renderer2, ViewChild } from '@angular/core'; -import { - IgxGridComponent, - IgxTreeGridComponent, - IgxHierarchicalGridComponent, - CellType -} from 'igniteui-angular'; -import { HIERARCHICAL_SAMPLE_DATA } from '../shared/sample-data'; - -@Component({ - selector: 'app-grid-cell-api-sample', - styleUrls: ['grid-cell-api.sample.css'], - templateUrl: 'grid-cell-api.sample.html', - // providers: [ - // { provide: IgxGridTransaction, useClass: IgxTransactionService } - // ], -}) - -export class GridCellAPISampleComponent implements OnInit { - @ViewChild('grid', { static: true }) - private grid: IgxGridComponent; - - public data2: any; - public data: any[]; - public treeGridHierData: any[]; - public hierarchicalData: any[]; - public columns: any[]; - public hColumns: any[]; - public treeGridHierColumns: any[]; - public treeColumns: any[]; - public treeData: any[]; - - public index = '00'; - public tIndex = '00'; - public tHIndex = '00'; - public hIndex = '00'; - - public cellKey = 'ALFKI'; - public tCellKey = '0'; - public tHCellKey = 'ALFKI'; - public hCellKey = '0'; - - public columnField = 'ContactName'; - public tcolumnField = 'Salary'; - public tHcolumnField = 'ContactName'; - public hcolumnField = 'ProductName'; - - public selectedCell: CellType; - - constructor(private renderer: Renderer2) { } - - public ngOnInit(): void { - this.columns = [ - { field: 'ID', width: '200px', hidden: false }, - { field: 'CompanyName', header: 'Company Name', width: '200px', groupable: true }, - { field: 'ContactName', width: '200px', pinned: false, groupable: true }, - { field: 'ContactTitle', width: '300px', pinned: false, groupable: true }, - { field: 'Address', width: '250px' }, - { field: 'City', width: '200px' }, - { field: 'Region', width: '300px' }, - { field: 'PostalCode', width: '150px' }, - { field: 'Phone', width: '200px' }, - { field: 'Fax', width: '200px' } - ]; - - this.hColumns = [ - { field: 'ID', width: '200px' }, - { field: 'ChildLevels', width: '200px' }, - { field: 'ProductName', width: '200px' }, - { field: 'Col1', width: '200px' }, - { field: 'Col2', width: '200px' }, - { field: 'Col3', width: '200px' }, - { field: 'childData', width: '200px' }, - { field: 'childData2', width: '200px' }, - { field: 'hasChild', width: '200px' } - ]; - - this.treeGridHierColumns = [ - { field: 'ID', width: 200, resizable: true, pinned: true }, - { field: 'CompanyName', width: 150, resizable: true }, - { field: 'ContactName', width: 150, resizable: true }, - { field: 'ContactTitle', width: 150, resizable: true }, - { field: 'Address', width: 150, resizable: true}, - { field: 'City', width: 150, resizable: true, summary: true }, - { field: 'Region', width: 150, resizable: true }, - { field: 'PostalCode', width: 150, resizable: true }, - { field: 'Phone', width: 150, resizable: true }, - { field: 'Fax', width: 150, resizable: true } - ]; - this.treeGridHierData = HIERARCHICAL_SAMPLE_DATA.slice(0); - - this.data = [ - /* eslint-disable max-len */ - { ID: 'ALFKI', CompanyName: 'Alfreds Futterkiste', ContactName: 'Maria Anders', ContactTitle: 'Sales Representative', Address: 'Obere Str. 57', City: 'Berlin', Region: null, PostalCode: '12209', Country: 'Germany', Phone: '030-0074321', Fax: '030-0076545' }, - { ID: 'ANATR', CompanyName: 'Ana Trujillo Emparedados y helados', ContactName: 'Ana Trujillo', ContactTitle: 'Owner', Address: 'Avda. de la Constitución 2222', City: 'México D.F.', Region: null, PostalCode: '05021', Country: 'Mexico', Phone: '(5) 555-4729', Fax: '(5) 555-3745' }, - { ID: 'ANTON', CompanyName: 'Antonio Moreno Taquería', ContactName: 'Antonio Moreno', ContactTitle: 'Owner', Address: 'Mataderos 2312', City: 'México D.F.', Region: null, PostalCode: '05023', Country: 'Mexico', Phone: '(5) 555-3932', Fax: null }, - { ID: 'AROUT', CompanyName: 'Around the Horn', ContactName: 'Thomas Hardy', ContactTitle: 'Sales Representative', Address: '120 Hanover Sq.', City: 'London', Region: null, PostalCode: 'WA1 1DP', Country: 'UK', Phone: '(171) 555-7788', Fax: '(171) 555-6750' }, - { ID: 'BERGS', CompanyName: 'Berglunds snabbköp', ContactName: 'Christina Berglund', ContactTitle: 'Order Administrator', Address: 'Berguvsvägen 8', City: 'Luleå', Region: null, PostalCode: 'S-958 22', Country: 'Sweden', Phone: '0921-12 34 65', Fax: '0921-12 34 67' }, - { ID: 'BLAUS', CompanyName: 'Blauer See Delikatessen', ContactName: 'Hanna Moos', ContactTitle: 'Sales Representative', Address: 'Forsterstr. 57', City: 'Mannheim', Region: null, PostalCode: '68306', Country: 'Germany', Phone: '0621-08460', Fax: '0621-08924' }, - { ID: 'BLONP', CompanyName: 'Blondesddsl père et fils', ContactName: 'Frédérique Citeaux', ContactTitle: 'Marketing Manager', Address: '24, place Kléber', City: 'Strasbourg', Region: null, PostalCode: '67000', Country: 'France', Phone: '88.60.15.31', Fax: '88.60.15.32' }, - { ID: 'BOLID', CompanyName: 'Bólido Comidas preparadas', ContactName: 'Martín Sommer', ContactTitle: 'Owner', Address: 'C/ Araquil, 67', City: 'Madrid', Region: null, PostalCode: '28023', Country: 'Spain', Phone: '(91) 555 22 82', Fax: '(91) 555 91 99' }, - { ID: 'BONAP', CompanyName: 'Bon app\'', ContactName: 'Laurence Lebihan', ContactTitle: 'Owner', Address: '12, rue des Bouchers', City: 'Marseille', Region: null, PostalCode: '13008', Country: 'France', Phone: '91.24.45.40', Fax: '91.24.45.41' }, - { ID: 'BOTTM', CompanyName: 'Bottom-Dollar Markets', ContactName: 'Elizabeth Lincoln', ContactTitle: 'Accounting Manager', Address: '23 Tsawassen Blvd.', City: 'Tsawassen', Region: 'BC', PostalCode: 'T2F 8M4', Country: 'Canada', Phone: '(604) 555-4729', Fax: '(604) 555-3745' }, - { ID: 'BSBEV', CompanyName: 'B\'s Beverages', ContactName: 'Victoria Ashworth', ContactTitle: 'Sales Representative', Address: 'Fauntleroy Circus', City: 'London', Region: null, PostalCode: 'EC2 5NT', Country: 'UK', Phone: '(171) 555-1212', Fax: null }, - { ID: 'CACTU', CompanyName: 'Cactus Comidas para llevar', ContactName: 'Patricio Simpson', ContactTitle: 'Sales Agent', Address: 'Cerrito 333', City: 'Buenos Aires', Region: null, PostalCode: '1010', Country: 'Argentina', Phone: '(1) 135-5555', Fax: '(1) 135-4892' }, - { ID: 'CENTC', CompanyName: 'Centro comercial Moctezuma', ContactName: 'Francisco Chang', ContactTitle: 'Marketing Manager', Address: 'Sierras de Granada 9993', City: 'México D.F.', Region: null, PostalCode: '05022', Country: 'Mexico', Phone: '(5) 555-3392', Fax: '(5) 555-7293' }, - { ID: 'CHOPS', CompanyName: 'Chop-suey Chinese', ContactName: 'Yang Wang', ContactTitle: 'Owner', Address: 'Hauptstr. 29', City: 'Bern', Region: null, PostalCode: '3012', Country: 'Switzerland', Phone: '0452-076545', Fax: null }, - { ID: 'COMMI', CompanyName: 'Comércio Mineiro', ContactName: 'Pedro Afonso', ContactTitle: 'Sales Associate', Address: 'Av. dos Lusíadas, 23', City: 'Sao Paulo', Region: 'SP', PostalCode: '05432-043', Country: 'Brazil', Phone: '(11) 555-7647', Fax: null }, - { ID: 'CONSH', CompanyName: 'Consolidated Holdings', ContactName: 'Elizabeth Brown', ContactTitle: 'Sales Representative', Address: 'Berkeley Gardens 12 Brewery', City: 'London', Region: null, PostalCode: 'WX1 6LT', Country: 'UK', Phone: '(171) 555-2282', Fax: '(171) 555-9199' }, - { ID: 'DRACD', CompanyName: 'Drachenblut Delikatessen', ContactName: 'Sven Ottlieb', ContactTitle: 'Order Administrator', Address: 'Walserweg 21', City: 'Aachen', Region: null, PostalCode: '52066', Country: 'Germany', Phone: '0241-039123', Fax: '0241-059428' }, - { ID: 'DUMON', CompanyName: 'Du monde entier', ContactName: 'Janine Labrune', ContactTitle: 'Owner', Address: '67, rue des Cinquante Otages', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.67.88.88', Fax: '40.67.89.89' }, - { ID: 'EASTC', CompanyName: 'Eastern Connection', ContactName: 'Ann Devon', ContactTitle: 'Sales Agent', Address: '35 King George', City: 'London', Region: null, PostalCode: 'WX3 6FW', Country: 'UK', Phone: '(171) 555-0297', Fax: '(171) 555-3373' }, - { ID: 'ERNSH', CompanyName: 'Ernst Handel', ContactName: 'Roland Mendel', ContactTitle: 'Sales Manager', Address: 'Kirchgasse 6', City: 'Graz', Region: null, PostalCode: '8010', Country: 'Austria', Phone: '7675-3425', Fax: '7675-3426' }, - { ID: 'FAMIA', CompanyName: 'Familia Arquibaldo', ContactName: 'Aria Cruz', ContactTitle: 'Marketing Assistant', Address: 'Rua Orós, 92', City: 'Sao Paulo', Region: 'SP', PostalCode: '05442-030', Country: 'Brazil', Phone: '(11) 555-9857', Fax: null }, - { ID: 'FISSA', CompanyName: 'FISSA Fabrica Inter. Salchichas S.A.', ContactName: 'Diego Roel', ContactTitle: 'Accounting Manager', Address: 'C/ Moralzarzal, 86', City: 'Madrid', Region: null, PostalCode: '28034', Country: 'Spain', Phone: '(91) 555 94 44', Fax: '(91) 555 55 93' }, - { ID: 'FOLIG', CompanyName: 'Folies gourmandes', ContactName: 'Martine Rancé', ContactTitle: 'Assistant Sales Agent', Address: '184, chaussée de Tournai', City: 'Lille', Region: null, PostalCode: '59000', Country: 'France', Phone: '20.16.10.16', Fax: '20.16.10.17' }, - { ID: 'FOLKO', CompanyName: 'Folk och fä HB', ContactName: 'Maria Larsson', ContactTitle: 'Owner', Address: 'Åkergatan 24', City: 'Bräcke', Region: null, PostalCode: 'S-844 67', Country: 'Sweden', Phone: '0695-34 67 21', Fax: null }, - { ID: 'FRANK', CompanyName: 'Frankenversand', ContactName: 'Peter Franken', ContactTitle: 'Marketing Manager', Address: 'Berliner Platz 43', City: 'München', Region: null, PostalCode: '80805', Country: 'Germany', Phone: '089-0877310', Fax: '089-0877451' }, - { ID: 'FRANR', CompanyName: 'France restauration', ContactName: 'Carine Schmitt', ContactTitle: 'Marketing Manager', Address: '54, rue Royale', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.32.21.21', Fax: '40.32.21.20' }, - { ID: 'FRANS', CompanyName: 'Franchi S.p.A.', ContactName: 'Paolo Accorti', ContactTitle: 'Sales Representative', Address: 'Via Monte Bianco 34', City: 'Torino', Region: null, PostalCode: '10100', Country: 'Italy', Phone: '011-4988260', Fax: '011-4988261' } - ]; - this.hierarchicalData = this.generateDataUneven(100, 3); - - // treegrid cols and data - this.treeColumns = [ - { field: 'employeeID', label: 'ID', width: 200, resizable: true, dataType: 'number', hasSummary: false }, - { field: 'Salary', label: 'Salary', width: 200, resizable: true, dataType: 'number', hasSummary: true }, - { field: 'firstName', label: 'First Name', width: 300, resizable: true, dataType: 'string', hasSummary: false }, - { field: 'lastName', label: 'Last Name', width: 150, resizable: true, dataType: 'string', hasSummary: false }, - { field: 'Title', label: 'Title', width: 200, resizable: true, dataType: 'string', hasSummary: true } - ]; - this.treeData = [ - { Salary: 2500, employeeID: 0, PID: -1, firstName: 'Andrew', lastName: 'Fuller', Title: 'Vice President, Sales' }, - { Salary: 3500, employeeID: 1, PID: -1, firstName: 'Jonathan', lastName: 'Smith', Title: 'Human resources' }, - { Salary: 1500, employeeID: 2, PID: -1, firstName: 'Nancy', lastName: 'Davolio', Title: 'CFO' }, - { Salary: 2500, employeeID: 3, PID: -1, firstName: 'Steven', lastName: 'Buchanan', Title: 'CTO' }, - // sub of ID 0 - { Salary: 2500, employeeID: 4, PID: 0, firstName: 'Janet', lastName: 'Leverling', Title: 'Sales Manager' }, - { Salary: 3500, employeeID: 5, PID: 0, firstName: 'Laura', lastName: 'Callahan', Title: 'Inside Sales Coordinator' }, - { Salary: 1500, employeeID: 6, PID: 0, firstName: 'Margaret', lastName: 'Peacock', Title: 'Sales Representative' }, - { Salary: 2500, employeeID: 7, PID: 0, firstName: 'Michael', lastName: 'Suyama', Title: 'Sales Representative' }, - // sub of ID 4 - { Salary: 2500, employeeID: 8, PID: 4, firstName: 'Anne', lastName: 'Dodsworth', Title: 'Sales Representative' }, - { Salary: 3500, employeeID: 9, PID: 4, firstName: 'Danielle', lastName: 'Davis', Title: 'Sales Representative' }, - { Salary: 1500, employeeID: 10, PID: 4, firstName: 'Robert', lastName: 'King', Title: 'Sales Representative' }, - // sub of ID 2 - { Salary: 2500, employeeID: 11, PID: 2, firstName: 'Peter', lastName: 'Lewis', Title: 'Chief Accountant' }, - { Salary: 3500, employeeID: 12, PID: 2, firstName: 'Ryder', lastName: 'Zenaida', Title: 'Accountant' }, - { Salary: 1500, employeeID: 13, PID: 2, firstName: 'Wang', lastName: 'Mercedes', Title: 'Accountant' }, - // sub of ID 3 - { Salary: 1500, employeeID: 14, PID: 3, firstName: 'Theodore', lastName: 'Zia', Title: 'Software Architect' }, - { Salary: 4500, employeeID: 15, PID: 3, firstName: 'Lacota', lastName: 'Mufutau', Title: 'Product Manager' }, - // sub of ID 16 - { Salary: 2500, employeeID: 16, PID: 15, firstName: 'Jin', lastName: 'Elliott', Title: 'Product Owner' }, - { Salary: 3500, employeeID: 17, PID: 15, firstName: 'Armand', lastName: 'Ross', Title: 'Product Owner' }, - { Salary: 1500, employeeID: 18, PID: 15, firstName: 'Dane', lastName: 'Rodriquez', Title: 'Team Leader' }, - // sub of ID 19 - { Salary: 2500, employeeID: 19, PID: 18, firstName: 'Declan', lastName: 'Lester', Title: 'Senior Software Developer' }, - { Salary: 3500, employeeID: 20, PID: 18, firstName: 'Bernard', lastName: 'Jarvis', Title: 'Senior Software Developer' }, - { Salary: 1500, employeeID: 21, PID: 18, firstName: 'Jason', lastName: 'Clark', Title: 'QA' }, - { Salary: 1500, employeeID: 22, PID: 18, firstName: 'Mark', lastName: 'Young', Title: 'QA' }, - // sub of ID 20 - { Salary: 1500, employeeID: 23, PID: 20, firstName: 'Jeremy', lastName: 'Donaldson', Title: 'Software Developer' } - ]; - /* eslint-enable max-len */ - } - - public updateCell(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, - logger: HTMLElement) { - const indxs = this.getIndices(indices); - const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); - cell.update('New Value'); - this.logState(grid, indices, logger); - } - - public select(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, logger: HTMLElement) { - const indxs = this.getIndices(indices); - const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); - cell.selected = !cell.selected; - this.selectedCell = cell; - this.logState(grid, indices, logger); - } - - public setEditMode(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, - logger: HTMLElement) { - const indxs = this.getIndices(indices); - const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); - cell.editMode = !cell.editMode; - this.logState(grid, indices, logger); - } - - public generateDataUneven(count: number, level: number, parendID: string = null) { - const prods = []; - const currLevel = level; - let children; - for (let i = 0; i < count; i++) { - const rowID = parendID ? parendID + i : i.toString(); - if (level > 0) { - // Have child grids for row with even id less rows by not multiplying by 2 - children = this.generateDataUneven(((i % 2) + 1) * Math.round(count / 3), currLevel - 1, rowID); - } - prods.push({ - ID: rowID, - ChildLevels: currLevel, - ProductName: 'Product: A' + i, - Col1: i, - Col2: i, - Col3: i, - childData: children, - childData2: children, - hasChild: true - }); - } - return prods; - } - - public clearLog(logger: HTMLElement) { - const elements = logger.querySelectorAll('p'); - - elements.forEach(element => { - this.renderer.removeChild(logger, element); - }); - } - - public logState(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, logger: HTMLElement) { - this.clearLog(logger); - const indxs = this.getIndices(indices); - const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); - let state: string; - let states: string[]; - - if (cell) { - state = ` - value: ${cell.value}, - selected: ${cell.selected}, - editable: ${cell.editable}, - editMode: ${cell.editMode}, - editValue: ${cell.editValue}, - -----------------------------, - colIndex: ${cell.column.index}, - visibleColIndex: ${cell.column.visibleIndex}, - colField: ${cell.column.field}, - -----------------------------, - rowIndex: ${cell.row.index}, - rowViewIndex: ${cell.row.viewIndex}, - rowKey: ${cell.row.key}, - rowData: ${cell.row.data}, - -----------------------------, - gridId: ${cell.grid.id}, - id: ${cell.id}, - width: ${cell.width}`; - states = state.split(','); - } else { - states = [`Cell is: ${cell}`]; - } - - const createElem = this.renderer.createElement('p'); - - states.forEach(st => { - const text = this.renderer.createText(st); - this.renderer.appendChild(createElem, text); - this.renderer.appendChild(createElem, this.renderer.createElement('br')); - }); - - this.renderer.insertBefore(logger, createElem, logger.children[0]); - } - - public logStateByKey(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, key: any, - field: string, logger: HTMLElement) { - this.clearLog(logger); - const cell = grid.getCellByKey(key, field); - let state: string; - let states: string[]; - - if (cell) { - state = ` - value: ${cell.value}, - selected: ${cell.selected}, - editable: ${cell.editable}, - editMode: ${cell.editMode}, - editValue: ${cell.editValue}, - -----------------------------, - colIndex: ${cell.column.index}, - visibleColIndex: ${cell.column.visibleIndex}, - colField: ${cell.column.field}, - -----------------------------, - rowIndex: ${cell.row.index}, - rowViewIndex: ${cell.row.viewIndex}, - rowKey: ${cell.row.key}, - rowData: ${cell.row.data}, - -----------------------------, - gridId: ${cell.grid.id}, - cellID: ${cell.id}, - width: ${cell.width}`; - - states = state.split(','); - } else { - states = [`Cell is: ${cell}`]; - } - - const createElem = this.renderer.createElement('p'); - - states.forEach(st => { - const text = this.renderer.createText(st); - this.renderer.appendChild(createElem, text); - this.renderer.appendChild(createElem, this.renderer.createElement('br')); - }); - - this.renderer.insertBefore(logger, createElem, logger.children[0]); - } - - public logStateByColumn(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, - field: string, logger: HTMLElement) { - this.clearLog(logger); - const indxs = this.getIndices(indices); - const cell = grid.getCellByColumn(indxs[0], field); - let state: string; - let states: string[]; - - if (cell) { - state = ` - value: ${cell.value}, - selected: ${cell.selected}, - editable: ${cell.editable}, - editMode: ${cell.editMode}, - editValue: ${cell.editValue}, - -----------------------------, - colIndex: ${cell.column.index}, - visibleColIndex: ${cell.column.visibleIndex}, - colField: ${cell.column.field}, - -----------------------------, - rowIndex: ${cell.row.index}, - rowViewIndex: ${cell.row.viewIndex}, - rowKey: ${cell.row.key}, - rowData: ${cell.row.data}, - -----------------------------, - gridId: ${cell.grid.id}, - cellID: ${cell.id}, - width: ${cell.width}`; - - states = state.split(','); - } else { - states = [`Cell is: ${cell}`]; - } - - const createElem = this.renderer.createElement('p'); - - states.forEach(st => { - const text = this.renderer.createText(st); - this.renderer.appendChild(createElem, text); - this.renderer.appendChild(createElem, this.renderer.createElement('br')); - }); - - this.renderer.insertBefore(logger, createElem, logger.children[0]); - } - - private getIndices(indices: string): number[] { - if (indices.length === 1) { - indices = `0${indices}`; - } - let nums: number[] = indices.split('').map(n => parseInt(n, 10)); - if (nums.length === 0) { - nums = [0, 0]; - } - return nums; - } -} +import { Component, OnInit, Renderer2, ViewChild } from '@angular/core'; +import { + IgxGridComponent, + IgxTreeGridComponent, + IgxHierarchicalGridComponent, + CellType +} from 'igniteui-angular'; +import { HIERARCHICAL_SAMPLE_DATA } from '../shared/sample-data'; + +@Component({ + selector: 'app-grid-cell-api-sample', + styleUrls: ['grid-cell-api.sample.css'], + templateUrl: 'grid-cell-api.sample.html', + // providers: [ + // { provide: IgxGridTransaction, useClass: IgxTransactionService } + // ], +}) + +export class GridCellAPISampleComponent implements OnInit { + @ViewChild('grid', { static: true }) + private grid: IgxGridComponent; + + public data2: any; + public data: any[]; + public treeGridHierData: any[]; + public hierarchicalData: any[]; + public columns: any[]; + public hColumns: any[]; + public treeGridHierColumns: any[]; + public treeColumns: any[]; + public treeData: any[]; + + public index = '00'; + public tIndex = '00'; + public tHIndex = '00'; + public hIndex = '00'; + + public cellKey = 'ALFKI'; + public tCellKey = '0'; + public tHCellKey = 'ALFKI'; + public hCellKey = '0'; + + public columnField = 'ContactName'; + public tcolumnField = 'Salary'; + public tHcolumnField = 'ContactName'; + public hcolumnField = 'ProductName'; + + public selectedCell: CellType; + + constructor(private renderer: Renderer2) { } + + public ngOnInit(): void { + this.columns = [ + { field: 'ID', width: '200px', hidden: false }, + { field: 'CompanyName', header: 'Company Name', width: '200px', groupable: true }, + { field: 'ContactName', width: '200px', pinned: false, groupable: true }, + { field: 'ContactTitle', width: '300px', pinned: false, groupable: true }, + { field: 'Address', width: '250px' }, + { field: 'City', width: '200px' }, + { field: 'Region', width: '300px' }, + { field: 'PostalCode', width: '150px' }, + { field: 'Phone', width: '200px' }, + { field: 'Fax', width: '200px' } + ]; + + this.hColumns = [ + { field: 'ID', width: '200px' }, + { field: 'ChildLevels', width: '200px' }, + { field: 'ProductName', width: '200px' }, + { field: 'Col1', width: '200px' }, + { field: 'Col2', width: '200px' }, + { field: 'Col3', width: '200px' }, + { field: 'childData', width: '200px' }, + { field: 'childData2', width: '200px' }, + { field: 'hasChild', width: '200px' } + ]; + + this.treeGridHierColumns = [ + { field: 'ID', width: 200, resizable: true, pinned: true }, + { field: 'CompanyName', width: 150, resizable: true }, + { field: 'ContactName', width: 150, resizable: true }, + { field: 'ContactTitle', width: 150, resizable: true }, + { field: 'Address', width: 150, resizable: true}, + { field: 'City', width: 150, resizable: true, summary: true }, + { field: 'Region', width: 150, resizable: true }, + { field: 'PostalCode', width: 150, resizable: true }, + { field: 'Phone', width: 150, resizable: true }, + { field: 'Fax', width: 150, resizable: true } + ]; + this.treeGridHierData = HIERARCHICAL_SAMPLE_DATA.slice(0); + + this.data = [ + /* eslint-disable max-len */ + { ID: 'ALFKI', CompanyName: 'Alfreds Futterkiste', ContactName: 'Maria Anders', ContactTitle: 'Sales Representative', Address: 'Obere Str. 57', City: 'Berlin', Region: null, PostalCode: '12209', Country: 'Germany', Phone: '030-0074321', Fax: '030-0076545' }, + { ID: 'ANATR', CompanyName: 'Ana Trujillo Emparedados y helados', ContactName: 'Ana Trujillo', ContactTitle: 'Owner', Address: 'Avda. de la Constitución 2222', City: 'México D.F.', Region: null, PostalCode: '05021', Country: 'Mexico', Phone: '(5) 555-4729', Fax: '(5) 555-3745' }, + { ID: 'ANTON', CompanyName: 'Antonio Moreno Taquería', ContactName: 'Antonio Moreno', ContactTitle: 'Owner', Address: 'Mataderos 2312', City: 'México D.F.', Region: null, PostalCode: '05023', Country: 'Mexico', Phone: '(5) 555-3932', Fax: null }, + { ID: 'AROUT', CompanyName: 'Around the Horn', ContactName: 'Thomas Hardy', ContactTitle: 'Sales Representative', Address: '120 Hanover Sq.', City: 'London', Region: null, PostalCode: 'WA1 1DP', Country: 'UK', Phone: '(171) 555-7788', Fax: '(171) 555-6750' }, + { ID: 'BERGS', CompanyName: 'Berglunds snabbköp', ContactName: 'Christina Berglund', ContactTitle: 'Order Administrator', Address: 'Berguvsvägen 8', City: 'Luleå', Region: null, PostalCode: 'S-958 22', Country: 'Sweden', Phone: '0921-12 34 65', Fax: '0921-12 34 67' }, + { ID: 'BLAUS', CompanyName: 'Blauer See Delikatessen', ContactName: 'Hanna Moos', ContactTitle: 'Sales Representative', Address: 'Forsterstr. 57', City: 'Mannheim', Region: null, PostalCode: '68306', Country: 'Germany', Phone: '0621-08460', Fax: '0621-08924' }, + { ID: 'BLONP', CompanyName: 'Blondesddsl père et fils', ContactName: 'Frédérique Citeaux', ContactTitle: 'Marketing Manager', Address: '24, place Kléber', City: 'Strasbourg', Region: null, PostalCode: '67000', Country: 'France', Phone: '88.60.15.31', Fax: '88.60.15.32' }, + { ID: 'BOLID', CompanyName: 'Bólido Comidas preparadas', ContactName: 'Martín Sommer', ContactTitle: 'Owner', Address: 'C/ Araquil, 67', City: 'Madrid', Region: null, PostalCode: '28023', Country: 'Spain', Phone: '(91) 555 22 82', Fax: '(91) 555 91 99' }, + { ID: 'BONAP', CompanyName: 'Bon app\'', ContactName: 'Laurence Lebihan', ContactTitle: 'Owner', Address: '12, rue des Bouchers', City: 'Marseille', Region: null, PostalCode: '13008', Country: 'France', Phone: '91.24.45.40', Fax: '91.24.45.41' }, + { ID: 'BOTTM', CompanyName: 'Bottom-Dollar Markets', ContactName: 'Elizabeth Lincoln', ContactTitle: 'Accounting Manager', Address: '23 Tsawassen Blvd.', City: 'Tsawassen', Region: 'BC', PostalCode: 'T2F 8M4', Country: 'Canada', Phone: '(604) 555-4729', Fax: '(604) 555-3745' }, + { ID: 'BSBEV', CompanyName: 'B\'s Beverages', ContactName: 'Victoria Ashworth', ContactTitle: 'Sales Representative', Address: 'Fauntleroy Circus', City: 'London', Region: null, PostalCode: 'EC2 5NT', Country: 'UK', Phone: '(171) 555-1212', Fax: null }, + { ID: 'CACTU', CompanyName: 'Cactus Comidas para llevar', ContactName: 'Patricio Simpson', ContactTitle: 'Sales Agent', Address: 'Cerrito 333', City: 'Buenos Aires', Region: null, PostalCode: '1010', Country: 'Argentina', Phone: '(1) 135-5555', Fax: '(1) 135-4892' }, + { ID: 'CENTC', CompanyName: 'Centro comercial Moctezuma', ContactName: 'Francisco Chang', ContactTitle: 'Marketing Manager', Address: 'Sierras de Granada 9993', City: 'México D.F.', Region: null, PostalCode: '05022', Country: 'Mexico', Phone: '(5) 555-3392', Fax: '(5) 555-7293' }, + { ID: 'CHOPS', CompanyName: 'Chop-suey Chinese', ContactName: 'Yang Wang', ContactTitle: 'Owner', Address: 'Hauptstr. 29', City: 'Bern', Region: null, PostalCode: '3012', Country: 'Switzerland', Phone: '0452-076545', Fax: null }, + { ID: 'COMMI', CompanyName: 'Comércio Mineiro', ContactName: 'Pedro Afonso', ContactTitle: 'Sales Associate', Address: 'Av. dos Lusíadas, 23', City: 'Sao Paulo', Region: 'SP', PostalCode: '05432-043', Country: 'Brazil', Phone: '(11) 555-7647', Fax: null }, + { ID: 'CONSH', CompanyName: 'Consolidated Holdings', ContactName: 'Elizabeth Brown', ContactTitle: 'Sales Representative', Address: 'Berkeley Gardens 12 Brewery', City: 'London', Region: null, PostalCode: 'WX1 6LT', Country: 'UK', Phone: '(171) 555-2282', Fax: '(171) 555-9199' }, + { ID: 'DRACD', CompanyName: 'Drachenblut Delikatessen', ContactName: 'Sven Ottlieb', ContactTitle: 'Order Administrator', Address: 'Walserweg 21', City: 'Aachen', Region: null, PostalCode: '52066', Country: 'Germany', Phone: '0241-039123', Fax: '0241-059428' }, + { ID: 'DUMON', CompanyName: 'Du monde entier', ContactName: 'Janine Labrune', ContactTitle: 'Owner', Address: '67, rue des Cinquante Otages', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.67.88.88', Fax: '40.67.89.89' }, + { ID: 'EASTC', CompanyName: 'Eastern Connection', ContactName: 'Ann Devon', ContactTitle: 'Sales Agent', Address: '35 King George', City: 'London', Region: null, PostalCode: 'WX3 6FW', Country: 'UK', Phone: '(171) 555-0297', Fax: '(171) 555-3373' }, + { ID: 'ERNSH', CompanyName: 'Ernst Handel', ContactName: 'Roland Mendel', ContactTitle: 'Sales Manager', Address: 'Kirchgasse 6', City: 'Graz', Region: null, PostalCode: '8010', Country: 'Austria', Phone: '7675-3425', Fax: '7675-3426' }, + { ID: 'FAMIA', CompanyName: 'Familia Arquibaldo', ContactName: 'Aria Cruz', ContactTitle: 'Marketing Assistant', Address: 'Rua Orós, 92', City: 'Sao Paulo', Region: 'SP', PostalCode: '05442-030', Country: 'Brazil', Phone: '(11) 555-9857', Fax: null }, + { ID: 'FISSA', CompanyName: 'FISSA Fabrica Inter. Salchichas S.A.', ContactName: 'Diego Roel', ContactTitle: 'Accounting Manager', Address: 'C/ Moralzarzal, 86', City: 'Madrid', Region: null, PostalCode: '28034', Country: 'Spain', Phone: '(91) 555 94 44', Fax: '(91) 555 55 93' }, + { ID: 'FOLIG', CompanyName: 'Folies gourmandes', ContactName: 'Martine Rancé', ContactTitle: 'Assistant Sales Agent', Address: '184, chaussée de Tournai', City: 'Lille', Region: null, PostalCode: '59000', Country: 'France', Phone: '20.16.10.16', Fax: '20.16.10.17' }, + { ID: 'FOLKO', CompanyName: 'Folk och fä HB', ContactName: 'Maria Larsson', ContactTitle: 'Owner', Address: 'Åkergatan 24', City: 'Bräcke', Region: null, PostalCode: 'S-844 67', Country: 'Sweden', Phone: '0695-34 67 21', Fax: null }, + { ID: 'FRANK', CompanyName: 'Frankenversand', ContactName: 'Peter Franken', ContactTitle: 'Marketing Manager', Address: 'Berliner Platz 43', City: 'München', Region: null, PostalCode: '80805', Country: 'Germany', Phone: '089-0877310', Fax: '089-0877451' }, + { ID: 'FRANR', CompanyName: 'France restauration', ContactName: 'Carine Schmitt', ContactTitle: 'Marketing Manager', Address: '54, rue Royale', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.32.21.21', Fax: '40.32.21.20' }, + { ID: 'FRANS', CompanyName: 'Franchi S.p.A.', ContactName: 'Paolo Accorti', ContactTitle: 'Sales Representative', Address: 'Via Monte Bianco 34', City: 'Torino', Region: null, PostalCode: '10100', Country: 'Italy', Phone: '011-4988260', Fax: '011-4988261' } + ]; + this.hierarchicalData = this.generateDataUneven(100, 3); + + // treegrid cols and data + this.treeColumns = [ + { field: 'employeeID', label: 'ID', width: 200, resizable: true, dataType: 'number', hasSummary: false }, + { field: 'Salary', label: 'Salary', width: 200, resizable: true, dataType: 'number', hasSummary: true }, + { field: 'firstName', label: 'First Name', width: 300, resizable: true, dataType: 'string', hasSummary: false }, + { field: 'lastName', label: 'Last Name', width: 150, resizable: true, dataType: 'string', hasSummary: false }, + { field: 'Title', label: 'Title', width: 200, resizable: true, dataType: 'string', hasSummary: true } + ]; + this.treeData = [ + { Salary: 2500, employeeID: 0, PID: -1, firstName: 'Andrew', lastName: 'Fuller', Title: 'Vice President, Sales' }, + { Salary: 3500, employeeID: 1, PID: -1, firstName: 'Jonathan', lastName: 'Smith', Title: 'Human resources' }, + { Salary: 1500, employeeID: 2, PID: -1, firstName: 'Nancy', lastName: 'Davolio', Title: 'CFO' }, + { Salary: 2500, employeeID: 3, PID: -1, firstName: 'Steven', lastName: 'Buchanan', Title: 'CTO' }, + // sub of ID 0 + { Salary: 2500, employeeID: 4, PID: 0, firstName: 'Janet', lastName: 'Leverling', Title: 'Sales Manager' }, + { Salary: 3500, employeeID: 5, PID: 0, firstName: 'Laura', lastName: 'Callahan', Title: 'Inside Sales Coordinator' }, + { Salary: 1500, employeeID: 6, PID: 0, firstName: 'Margaret', lastName: 'Peacock', Title: 'Sales Representative' }, + { Salary: 2500, employeeID: 7, PID: 0, firstName: 'Michael', lastName: 'Suyama', Title: 'Sales Representative' }, + // sub of ID 4 + { Salary: 2500, employeeID: 8, PID: 4, firstName: 'Anne', lastName: 'Dodsworth', Title: 'Sales Representative' }, + { Salary: 3500, employeeID: 9, PID: 4, firstName: 'Danielle', lastName: 'Davis', Title: 'Sales Representative' }, + { Salary: 1500, employeeID: 10, PID: 4, firstName: 'Robert', lastName: 'King', Title: 'Sales Representative' }, + // sub of ID 2 + { Salary: 2500, employeeID: 11, PID: 2, firstName: 'Peter', lastName: 'Lewis', Title: 'Chief Accountant' }, + { Salary: 3500, employeeID: 12, PID: 2, firstName: 'Ryder', lastName: 'Zenaida', Title: 'Accountant' }, + { Salary: 1500, employeeID: 13, PID: 2, firstName: 'Wang', lastName: 'Mercedes', Title: 'Accountant' }, + // sub of ID 3 + { Salary: 1500, employeeID: 14, PID: 3, firstName: 'Theodore', lastName: 'Zia', Title: 'Software Architect' }, + { Salary: 4500, employeeID: 15, PID: 3, firstName: 'Lacota', lastName: 'Mufutau', Title: 'Product Manager' }, + // sub of ID 16 + { Salary: 2500, employeeID: 16, PID: 15, firstName: 'Jin', lastName: 'Elliott', Title: 'Product Owner' }, + { Salary: 3500, employeeID: 17, PID: 15, firstName: 'Armand', lastName: 'Ross', Title: 'Product Owner' }, + { Salary: 1500, employeeID: 18, PID: 15, firstName: 'Dane', lastName: 'Rodriquez', Title: 'Team Leader' }, + // sub of ID 19 + { Salary: 2500, employeeID: 19, PID: 18, firstName: 'Declan', lastName: 'Lester', Title: 'Senior Software Developer' }, + { Salary: 3500, employeeID: 20, PID: 18, firstName: 'Bernard', lastName: 'Jarvis', Title: 'Senior Software Developer' }, + { Salary: 1500, employeeID: 21, PID: 18, firstName: 'Jason', lastName: 'Clark', Title: 'QA' }, + { Salary: 1500, employeeID: 22, PID: 18, firstName: 'Mark', lastName: 'Young', Title: 'QA' }, + // sub of ID 20 + { Salary: 1500, employeeID: 23, PID: 20, firstName: 'Jeremy', lastName: 'Donaldson', Title: 'Software Developer' } + ]; + /* eslint-enable max-len */ + } + + public updateCell(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, + logger: HTMLElement) { + const indxs = this.getIndices(indices); + const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); + cell.update('New Value'); + this.logState(grid, indices, logger); + } + + public select(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, logger: HTMLElement) { + const indxs = this.getIndices(indices); + const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); + cell.selected = !cell.selected; + this.selectedCell = cell; + this.logState(grid, indices, logger); + } + + public setEditMode(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, + logger: HTMLElement) { + const indxs = this.getIndices(indices); + const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); + cell.editMode = !cell.editMode; + this.logState(grid, indices, logger); + } + + public generateDataUneven(count: number, level: number, parendID: string = null) { + const prods = []; + const currLevel = level; + let children; + for (let i = 0; i < count; i++) { + const rowID = parendID ? parendID + i : i.toString(); + if (level > 0) { + // Have child grids for row with even id less rows by not multiplying by 2 + children = this.generateDataUneven(((i % 2) + 1) * Math.round(count / 3), currLevel - 1, rowID); + } + prods.push({ + ID: rowID, + ChildLevels: currLevel, + ProductName: 'Product: A' + i, + Col1: i, + Col2: i, + Col3: i, + childData: children, + childData2: children, + hasChild: true + }); + } + return prods; + } + + public clearLog(logger: HTMLElement) { + const elements = logger.querySelectorAll('p'); + + elements.forEach(element => { + this.renderer.removeChild(logger, element); + }); + } + + public logState(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, logger: HTMLElement) { + this.clearLog(logger); + const indxs = this.getIndices(indices); + const cell = grid.getCellByColumnVisibleIndex(indxs[0], indxs[1]); + let state: string; + let states: string[]; + + if (cell) { + state = ` + value: ${cell.value}, + selected: ${cell.selected}, + editable: ${cell.editable}, + editMode: ${cell.editMode}, + editValue: ${cell.editValue}, + -----------------------------, + colIndex: ${cell.column.index}, + visibleColIndex: ${cell.column.visibleIndex}, + colField: ${cell.column.field}, + -----------------------------, + rowIndex: ${cell.row.index}, + rowViewIndex: ${cell.row.viewIndex}, + rowKey: ${cell.row.key}, + rowData: ${cell.row.data}, + -----------------------------, + gridId: ${cell.grid.id}, + id: ${cell.id}, + width: ${cell.width}`; + states = state.split(','); + } else { + states = [`Cell is: ${cell}`]; + } + + const createElem = this.renderer.createElement('p'); + + states.forEach(st => { + const text = this.renderer.createText(st); + this.renderer.appendChild(createElem, text); + this.renderer.appendChild(createElem, this.renderer.createElement('br')); + }); + + this.renderer.insertBefore(logger, createElem, logger.children[0]); + } + + public logStateByKey(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, key: any, + field: string, logger: HTMLElement) { + this.clearLog(logger); + const cell = grid.getCellByKey(key, field); + let state: string; + let states: string[]; + + if (cell) { + state = ` + value: ${cell.value}, + selected: ${cell.selected}, + editable: ${cell.editable}, + editMode: ${cell.editMode}, + editValue: ${cell.editValue}, + -----------------------------, + colIndex: ${cell.column.index}, + visibleColIndex: ${cell.column.visibleIndex}, + colField: ${cell.column.field}, + -----------------------------, + rowIndex: ${cell.row.index}, + rowViewIndex: ${cell.row.viewIndex}, + rowKey: ${cell.row.key}, + rowData: ${cell.row.data}, + -----------------------------, + gridId: ${cell.grid.id}, + cellID: ${cell.id}, + width: ${cell.width}`; + + states = state.split(','); + } else { + states = [`Cell is: ${cell}`]; + } + + const createElem = this.renderer.createElement('p'); + + states.forEach(st => { + const text = this.renderer.createText(st); + this.renderer.appendChild(createElem, text); + this.renderer.appendChild(createElem, this.renderer.createElement('br')); + }); + + this.renderer.insertBefore(logger, createElem, logger.children[0]); + } + + public logStateByColumn(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, indices: string, + field: string, logger: HTMLElement) { + this.clearLog(logger); + const indxs = this.getIndices(indices); + const cell = grid.getCellByColumn(indxs[0], field); + let state: string; + let states: string[]; + + if (cell) { + state = ` + value: ${cell.value}, + selected: ${cell.selected}, + editable: ${cell.editable}, + editMode: ${cell.editMode}, + editValue: ${cell.editValue}, + -----------------------------, + colIndex: ${cell.column.index}, + visibleColIndex: ${cell.column.visibleIndex}, + colField: ${cell.column.field}, + -----------------------------, + rowIndex: ${cell.row.index}, + rowViewIndex: ${cell.row.viewIndex}, + rowKey: ${cell.row.key}, + rowData: ${cell.row.data}, + -----------------------------, + gridId: ${cell.grid.id}, + cellID: ${cell.id}, + width: ${cell.width}`; + + states = state.split(','); + } else { + states = [`Cell is: ${cell}`]; + } + + const createElem = this.renderer.createElement('p'); + + states.forEach(st => { + const text = this.renderer.createText(st); + this.renderer.appendChild(createElem, text); + this.renderer.appendChild(createElem, this.renderer.createElement('br')); + }); + + this.renderer.insertBefore(logger, createElem, logger.children[0]); + } + + private getIndices(indices: string): number[] { + if (indices.length === 1) { + indices = `0${indices}`; + } + let nums: number[] = indices.split('').map(n => parseInt(n, 10)); + if (nums.length === 0) { + nums = [0, 0]; + } + return nums; + } +} diff --git a/src/app/grid-events/grid-events.component.html b/src/app/grid-events/grid-events.component.html index b2231d88743..f50f700c7df 100644 --- a/src/app/grid-events/grid-events.component.html +++ b/src/app/grid-events/grid-events.component.html @@ -1,83 +1,83 @@ -
- cancel sorting - cancel filtering - cancel pinning - cancel resizing - cancel columnSelectionChanging - cancel hiding -
- - -
- - -
- -
-
-
- - - - - - - - Really advanced filtering - - - - - - - - - - - - - - - - - -
-
-
-
-
-
- Events execution sequence - -
-
-
-
-
-
-
+
+ cancel sorting + cancel filtering + cancel pinning + cancel resizing + cancel columnSelectionChanging + cancel hiding +
+ + +
+ + +
+ +
+
+
+ + + + + + + + Really advanced filtering + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+ Events execution sequence + +
+
+
+
+
+
+
diff --git a/src/app/grid-events/grid-events.component.scss b/src/app/grid-events/grid-events.component.scss index 40cb020490a..282479e40df 100644 --- a/src/app/grid-events/grid-events.component.scss +++ b/src/app/grid-events/grid-events.component.scss @@ -1,41 +1,41 @@ -:host { - width: 100%; -} - -.sample-wrapper { - display: flex; - flex-flow: row wrap; - width: 100%; -} - -.grid-wrapper { - width: 60%; - margin: 8px; -} -.log-wrapper { - width: 35%; -} - -.clearBtn { - top: 3px; - margin-left: 20px; -} - -.selected-data-area{ - overflow-y: auto; - max-height: 550px; - width: 100%; - height: 100%; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); - margin-top: 8px; -} - -.logContainer { - padding: 0.2rem 0.4rem; -} - -.highlight { - text-align: center; - margin-bottom: 0.4rem; -} - +:host { + width: 100%; +} + +.sample-wrapper { + display: flex; + flex-flow: row wrap; + width: 100%; +} + +.grid-wrapper { + width: 60%; + margin: 8px; +} +.log-wrapper { + width: 35%; +} + +.clearBtn { + top: 3px; + margin-left: 20px; +} + +.selected-data-area{ + overflow-y: auto; + max-height: 550px; + width: 100%; + height: 100%; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); + margin-top: 8px; +} + +.logContainer { + padding: 0.2rem 0.4rem; +} + +.highlight { + text-align: center; + margin-bottom: 0.4rem; +} + diff --git a/src/app/grid-events/grid-events.component.ts b/src/app/grid-events/grid-events.component.ts index 76f306aaec9..3fb51d356cd 100644 --- a/src/app/grid-events/grid-events.component.ts +++ b/src/app/grid-events/grid-events.component.ts @@ -1,127 +1,127 @@ -import { Component, ViewChild, ElementRef, Renderer2 } from '@angular/core'; -import { IgxGridComponent, - ISortingExpression, IPinColumnEventArgs, - IColumnResizeEventArgs, IColumnSelectionEventArgs, IPageEventArgs, ISortingEventArgs, - IFilteringEventArgs, IgxStringFilteringOperand, IColumnMovingEndEventArgs, - IColumnMovingEventArgs, IColumnMovingStartEventArgs, IPinColumnCancellableEventArgs, - IColumnVisibilityChangingEventArgs, - IFilteringExpressionsTree, - IColumnVisibilityChangedEventArgs -} from 'igniteui-angular'; -import { data } from '../shared/data'; - -@Component({ - selector: 'app-grid-events', - styleUrls: ['grid-events.component.scss'], - templateUrl: 'grid-events.component.html' -}) -export class GridEventsComponent { - - @ViewChild('grid1', { read: IgxGridComponent, static: true }) public grid: IgxGridComponent; - @ViewChild('logger') public logger: ElementRef; - - public $sorting = false; - public $filtering = false; - public $paging = false; - public $pinning = false; - public $resizing = false; - public $columnSelectionChanging = false; - public $hiding = false; - public $moving = false; - public localData: any[]; - - constructor(private renderer: Renderer2) { - this.localData = data; - } - - public filter(term) { - this.grid.filter('ProductName', term, IgxStringFilteringOperand.instance().condition('contains')); - } - - public filterGlobal(term) { - this.grid.filterGlobal(term, IgxStringFilteringOperand.instance().condition('contains')); - } - - public columnMovingStart(event: IColumnMovingStartEventArgs) { - console.log('event' + event); - this.logAnEvent('=> columnMovingStart'); - } - public columnMoving(event: IColumnMovingEventArgs) { - event.cancel = this.$moving; - this.logAnEvent(event.cancel ? '=> columnMoving cancelled' : '=> columnMoving'); - } - public columnMovingEnd(event: IColumnMovingEndEventArgs) { - console.log('event' + event); - this.logAnEvent('=> columnMovingEnd'); - } - - public onSorting(event: ISortingEventArgs) { - event.cancel = this.$sorting; - this.logAnEvent('=> sorting', event.cancel); - } - public sortingDone(event: ISortingExpression | ISortingExpression []) { - console.log('event' + event); - this.logAnEvent(`=> sortingDone`); - } - - public onFiltering(event: IFilteringEventArgs) { - event.cancel = this.$filtering; - this.logAnEvent('=> filtering', event.cancel); - } - public filteringDone(event: IFilteringExpressionsTree) { - console.log('event' + event); - this.logAnEvent(`=> filteringDone`); - } - public pagingDone(event: IPageEventArgs) { - console.log('event' + event); - this.logAnEvent(`=> pagingDone`); - } - - public columnPin(event: IPinColumnCancellableEventArgs) { - event.cancel = this.$pinning; - this.logAnEvent('=> columnPin', event.cancel); - } - public columnPinned(event: IPinColumnEventArgs) { - console.log('event' + event); - this.logAnEvent(`=> columnPinned`); - } - - public columnVisibilityChanging(event: IColumnVisibilityChangingEventArgs ) { - event.cancel = this.$hiding; - this.logAnEvent('=> columnVisibilityChanging', event.cancel); - } - public columnVisibilityChanged(event: IColumnVisibilityChangedEventArgs) { - console.log('event' + event); - this.logAnEvent(`=> columnVisibilityChanged`); - } - - public columnResized(event: IColumnResizeEventArgs) { - console.log('event' + event); - this.logAnEvent(`=> columnResized`); - } - - public columnSelectionChanging(event: IColumnSelectionEventArgs) { - event.cancel = this.$columnSelectionChanging; - this.logAnEvent('=> columnSelectionChanging', event.cancel); - } - - public clearLog() { - const elements = this.logger.nativeElement.querySelectorAll('p'); - for (const element of elements) { - this.renderer.removeChild(this.logger.nativeElement, element); - } - } - - private logAnEvent(msg: string, cancelled?: boolean) { - const createElem = this.renderer.createElement('p'); - if (cancelled) { - msg = msg.concat(': cancelled '); - } - - const text = this.renderer.createText(msg); - this.renderer.appendChild(createElem, text); - const container = this.logger.nativeElement; - this.renderer.insertBefore(container, createElem, container.children[0]); - } -} - +import { Component, ViewChild, ElementRef, Renderer2 } from '@angular/core'; +import { IgxGridComponent, + ISortingExpression, IPinColumnEventArgs, + IColumnResizeEventArgs, IColumnSelectionEventArgs, IPageEventArgs, ISortingEventArgs, + IFilteringEventArgs, IgxStringFilteringOperand, IColumnMovingEndEventArgs, + IColumnMovingEventArgs, IColumnMovingStartEventArgs, IPinColumnCancellableEventArgs, + IColumnVisibilityChangingEventArgs, + IFilteringExpressionsTree, + IColumnVisibilityChangedEventArgs +} from 'igniteui-angular'; +import { data } from '../shared/data'; + +@Component({ + selector: 'app-grid-events', + styleUrls: ['grid-events.component.scss'], + templateUrl: 'grid-events.component.html' +}) +export class GridEventsComponent { + + @ViewChild('grid1', { read: IgxGridComponent, static: true }) public grid: IgxGridComponent; + @ViewChild('logger') public logger: ElementRef; + + public $sorting = false; + public $filtering = false; + public $paging = false; + public $pinning = false; + public $resizing = false; + public $columnSelectionChanging = false; + public $hiding = false; + public $moving = false; + public localData: any[]; + + constructor(private renderer: Renderer2) { + this.localData = data; + } + + public filter(term) { + this.grid.filter('ProductName', term, IgxStringFilteringOperand.instance().condition('contains')); + } + + public filterGlobal(term) { + this.grid.filterGlobal(term, IgxStringFilteringOperand.instance().condition('contains')); + } + + public columnMovingStart(event: IColumnMovingStartEventArgs) { + console.log('event' + event); + this.logAnEvent('=> columnMovingStart'); + } + public columnMoving(event: IColumnMovingEventArgs) { + event.cancel = this.$moving; + this.logAnEvent(event.cancel ? '=> columnMoving cancelled' : '=> columnMoving'); + } + public columnMovingEnd(event: IColumnMovingEndEventArgs) { + console.log('event' + event); + this.logAnEvent('=> columnMovingEnd'); + } + + public onSorting(event: ISortingEventArgs) { + event.cancel = this.$sorting; + this.logAnEvent('=> sorting', event.cancel); + } + public sortingDone(event: ISortingExpression | ISortingExpression []) { + console.log('event' + event); + this.logAnEvent(`=> sortingDone`); + } + + public onFiltering(event: IFilteringEventArgs) { + event.cancel = this.$filtering; + this.logAnEvent('=> filtering', event.cancel); + } + public filteringDone(event: IFilteringExpressionsTree) { + console.log('event' + event); + this.logAnEvent(`=> filteringDone`); + } + public pagingDone(event: IPageEventArgs) { + console.log('event' + event); + this.logAnEvent(`=> pagingDone`); + } + + public columnPin(event: IPinColumnCancellableEventArgs) { + event.cancel = this.$pinning; + this.logAnEvent('=> columnPin', event.cancel); + } + public columnPinned(event: IPinColumnEventArgs) { + console.log('event' + event); + this.logAnEvent(`=> columnPinned`); + } + + public columnVisibilityChanging(event: IColumnVisibilityChangingEventArgs ) { + event.cancel = this.$hiding; + this.logAnEvent('=> columnVisibilityChanging', event.cancel); + } + public columnVisibilityChanged(event: IColumnVisibilityChangedEventArgs) { + console.log('event' + event); + this.logAnEvent(`=> columnVisibilityChanged`); + } + + public columnResized(event: IColumnResizeEventArgs) { + console.log('event' + event); + this.logAnEvent(`=> columnResized`); + } + + public columnSelectionChanging(event: IColumnSelectionEventArgs) { + event.cancel = this.$columnSelectionChanging; + this.logAnEvent('=> columnSelectionChanging', event.cancel); + } + + public clearLog() { + const elements = this.logger.nativeElement.querySelectorAll('p'); + for (const element of elements) { + this.renderer.removeChild(this.logger.nativeElement, element); + } + } + + private logAnEvent(msg: string, cancelled?: boolean) { + const createElem = this.renderer.createElement('p'); + if (cancelled) { + msg = msg.concat(': cancelled '); + } + + const text = this.renderer.createText(msg); + this.renderer.appendChild(createElem, text); + const container = this.logger.nativeElement; + this.renderer.insertBefore(container, createElem, container.children[0]); + } +} + diff --git a/src/app/grid-finjs/controllers.component.html b/src/app/grid-finjs/controllers.component.html index e046f820c27..7399b8287a4 100644 --- a/src/app/grid-finjs/controllers.component.html +++ b/src/app/grid-finjs/controllers.component.html @@ -1,33 +1,33 @@ -
-
-
-
- Dark -
-
- - Grouped -
-
- Toolbar -
-
- - -
-
- - -
-
-
- -
-
-
- Feeding {{volume}} records every {{frequency / 1000}} sec. - {{volume}} records updated. - Feeding {{volume}} records every {{frequency / 1000}} sec. - ~{{volume/5}} records updated. -
-
+
+
+
+
+ Dark +
+
+ + Grouped +
+
+ Toolbar +
+
+ + +
+
+ + +
+
+
+ +
+
+
+ Feeding {{volume}} records every {{frequency / 1000}} sec. + {{volume}} records updated. + Feeding {{volume}} records every {{frequency / 1000}} sec. + ~{{volume/5}} records updated. +
+
diff --git a/src/app/grid-finjs/controllers.component.scss b/src/app/grid-finjs/controllers.component.scss index 060abe0606b..204c7605de2 100644 --- a/src/app/grid-finjs/controllers.component.scss +++ b/src/app/grid-finjs/controllers.component.scss @@ -1,63 +1,63 @@ -:host ::ng-deep { - .fin-dark-theme { - .finjs-slider, - .sample-toolbar { - color: rgba(255, 255, 255, 0.87); - } - } - - .controls-holder { - display: flex; - justify-content: space-between; - align-items: center; - flex-wrap: wrap; - width: 100%; - padding-bottom: 15px; - } - .switches { - display: flex; - justify-content: space-between; - align-items: center; - flex: 1 0 0%; - padding-right: 20px; - font-size: 0.9rem; - } - .control-item { - padding-right: 20px; - label { - color: var(--igx-surface-500-contrast); - } - } - .igx-slider, - .igx-slider--disabled { - height: 24px; - } - .finjs-slider { - width: 40%; - min-width: 145px; - } - .finjs-play-controls { - width: 45%; - min-width: 620px; - margin-top: 10px; - } - .sample-toolbar { - height: 20px; - font-size: 0.8rem; - line-height: 20px; - /* position: absolute; */ - /* bottom: 10px; */ - /* left: 10px; */ - margin-top: 11px; - } - .igx-button--icon { - width: 2rem; - height: 2rem; - } -} - -.controls-wrapper { - display: flex; - justify-content: center; - position: relative; +:host ::ng-deep { + .fin-dark-theme { + .finjs-slider, + .sample-toolbar { + color: rgba(255, 255, 255, 0.87); + } + } + + .controls-holder { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + width: 100%; + padding-bottom: 15px; + } + .switches { + display: flex; + justify-content: space-between; + align-items: center; + flex: 1 0 0%; + padding-right: 20px; + font-size: 0.9rem; + } + .control-item { + padding-right: 20px; + label { + color: var(--igx-surface-500-contrast); + } + } + .igx-slider, + .igx-slider--disabled { + height: 24px; + } + .finjs-slider { + width: 40%; + min-width: 145px; + } + .finjs-play-controls { + width: 45%; + min-width: 620px; + margin-top: 10px; + } + .sample-toolbar { + height: 20px; + font-size: 0.8rem; + line-height: 20px; + /* position: absolute; */ + /* bottom: 10px; */ + /* left: 10px; */ + margin-top: 11px; + } + .igx-button--icon { + width: 2rem; + height: 2rem; + } +} + +.controls-wrapper { + display: flex; + justify-content: center; + position: relative; } \ No newline at end of file diff --git a/src/app/grid-finjs/controllers.component.ts b/src/app/grid-finjs/controllers.component.ts index 6de2f43dca3..39e09f747f1 100644 --- a/src/app/grid-finjs/controllers.component.ts +++ b/src/app/grid-finjs/controllers.component.ts @@ -1,106 +1,106 @@ -import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; -import { IgxButtonGroupComponent, IgxSliderComponent, -} from 'igniteui-angular'; -import { timer } from 'rxjs'; -import { debounce } from 'rxjs/operators'; - -@Component({ - selector: 'app-finjs-controllers', - styleUrls: ['./controllers.component.scss'], - templateUrl: './controllers.component.html' -}) -export class ControllerComponent implements OnInit, OnDestroy { - @ViewChild('buttonGroup1', { static: true }) public playButtons: IgxButtonGroupComponent; - @ViewChild('slider1', { static: true }) public volumeSlider: IgxSliderComponent; - @ViewChild('slider2', { static: true }) public intervalSlider: IgxSliderComponent; - - @Output() public switchChanged = new EventEmitter(); - @Output() public volumeChanged = new EventEmitter(); - @Output() public playAction = new EventEmitter(); - - public darkTheme = true; - public volume = 1000; - public frequency = 500; - public controls = [ - { - disabled: false, - icon: 'update', - label: 'LIVE PRICES', - selected: false - }, - { - disabled: false, - icon: 'update', - label: 'LIVE ALL PRICES', - selected: false - }, - { - disabled: true, - icon: 'stop', - label: 'Stop', - selected: false - } - ]; - - private subscription; - private selectedButton; - private volumeChanged$; - - public get buttonSelected(): number { - return this.selectedButton || this.selectedButton === 0 ? this.selectedButton : -1; - } - - public ngOnInit() { - this.volumeChanged$ = this.volumeSlider.valueChange.pipe(debounce(() => timer(200))); - this.volumeChanged$.subscribe(() => this.volumeChanged.emit(this.volumeSlider.value)); - } - - public onButtonSelected(event: any) { - switch (event.index) { - case 0: { - this.disableOtherButtons(event.index, true); - this.playAction.emit({ action: 'playRandom'}); - break; - } - case 1: { - this.disableOtherButtons(event.index, true); - this.playAction.emit({ action: 'playAll'}); - break; - } - case 2: { - this.disableOtherButtons(event.index, false); - this.playAction.emit({ action: 'stop'}); - break; - } - default: - { - break; - } - } - } - - public onChange(action: string, event: any) { - this.switchChanged.emit({action, value: event.checked }); - } - - public ngOnDestroy() { - this.volumeChanged$.unsubscribe(); - } - - private disableOtherButtons(ind: number, disableButtons: boolean) { - if (this.subscription) { - this.subscription.unsubscribe(); - } - this.volumeSlider.disabled = disableButtons; - this.intervalSlider.disabled = disableButtons; - this.selectedButton = ind; - this.playButtons.buttons.forEach((button, index) => { - if (index === 2) { - button.disabled = !disableButtons; - } else { - this.playButtons.buttons[0].disabled = disableButtons; - this.playButtons.buttons[1].disabled = disableButtons; - } - }); - } -} +import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { IgxButtonGroupComponent, IgxSliderComponent, +} from 'igniteui-angular'; +import { timer } from 'rxjs'; +import { debounce } from 'rxjs/operators'; + +@Component({ + selector: 'app-finjs-controllers', + styleUrls: ['./controllers.component.scss'], + templateUrl: './controllers.component.html' +}) +export class ControllerComponent implements OnInit, OnDestroy { + @ViewChild('buttonGroup1', { static: true }) public playButtons: IgxButtonGroupComponent; + @ViewChild('slider1', { static: true }) public volumeSlider: IgxSliderComponent; + @ViewChild('slider2', { static: true }) public intervalSlider: IgxSliderComponent; + + @Output() public switchChanged = new EventEmitter(); + @Output() public volumeChanged = new EventEmitter(); + @Output() public playAction = new EventEmitter(); + + public darkTheme = true; + public volume = 1000; + public frequency = 500; + public controls = [ + { + disabled: false, + icon: 'update', + label: 'LIVE PRICES', + selected: false + }, + { + disabled: false, + icon: 'update', + label: 'LIVE ALL PRICES', + selected: false + }, + { + disabled: true, + icon: 'stop', + label: 'Stop', + selected: false + } + ]; + + private subscription; + private selectedButton; + private volumeChanged$; + + public get buttonSelected(): number { + return this.selectedButton || this.selectedButton === 0 ? this.selectedButton : -1; + } + + public ngOnInit() { + this.volumeChanged$ = this.volumeSlider.valueChange.pipe(debounce(() => timer(200))); + this.volumeChanged$.subscribe(() => this.volumeChanged.emit(this.volumeSlider.value)); + } + + public onButtonSelected(event: any) { + switch (event.index) { + case 0: { + this.disableOtherButtons(event.index, true); + this.playAction.emit({ action: 'playRandom'}); + break; + } + case 1: { + this.disableOtherButtons(event.index, true); + this.playAction.emit({ action: 'playAll'}); + break; + } + case 2: { + this.disableOtherButtons(event.index, false); + this.playAction.emit({ action: 'stop'}); + break; + } + default: + { + break; + } + } + } + + public onChange(action: string, event: any) { + this.switchChanged.emit({action, value: event.checked }); + } + + public ngOnDestroy() { + this.volumeChanged$.unsubscribe(); + } + + private disableOtherButtons(ind: number, disableButtons: boolean) { + if (this.subscription) { + this.subscription.unsubscribe(); + } + this.volumeSlider.disabled = disableButtons; + this.intervalSlider.disabled = disableButtons; + this.selectedButton = ind; + this.playButtons.buttons.forEach((button, index) => { + if (index === 2) { + button.disabled = !disableButtons; + } else { + this.playButtons.buttons[0].disabled = disableButtons; + this.playButtons.buttons[1].disabled = disableButtons; + } + }); + } +} diff --git a/src/app/grid-finjs/main.component.html b/src/app/grid-finjs/main.component.html index a7aaad0a0e7..d84b507a1fb 100644 --- a/src/app/grid-finjs/main.component.html +++ b/src/app/grid-finjs/main.component.html @@ -1,9 +1,9 @@ -
- - - - +
+ + + +
\ No newline at end of file diff --git a/src/app/grid-finjs/main.component.scss b/src/app/grid-finjs/main.component.scss index 4cab541555f..ae02ecfa680 100644 --- a/src/app/grid-finjs/main.component.scss +++ b/src/app/grid-finjs/main.component.scss @@ -1,22 +1,22 @@ -.grid__wrapper { - position: relative; - width: 100%; - height: 100%; - min-height: 100%; - display: flex; - flex-direction: column; - top: 0; - left: 0; - padding: 15px; - display: flex; - flex-direction: column; -} - -:host ::ng-deep { - .fin-dark-theme { - .finjs-slider, - .sample-toolbar { - color: rgba(255, 255, 255, 0.87); - } - } +.grid__wrapper { + position: relative; + width: 100%; + height: 100%; + min-height: 100%; + display: flex; + flex-direction: column; + top: 0; + left: 0; + padding: 15px; + display: flex; + flex-direction: column; +} + +:host ::ng-deep { + .fin-dark-theme { + .finjs-slider, + .sample-toolbar { + color: rgba(255, 255, 255, 0.87); + } + } } \ No newline at end of file diff --git a/src/app/grid-finjs/main.component.ts b/src/app/grid-finjs/main.component.ts index 3c2ec19fce5..70f20b91bc8 100644 --- a/src/app/grid-finjs/main.component.ts +++ b/src/app/grid-finjs/main.component.ts @@ -1,91 +1,91 @@ -import { Component, EventEmitter, OnDestroy, Output, ViewChild } from '@angular/core'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { LocalService } from '../shared/local.service'; -import { ControllerComponent } from './controllers.component'; -import { GridFinJSComponent } from './grid-finjs.component'; - -@Component({ - providers: [LocalService], - selector: 'app-finjs-main', - styleUrls: ['./main.component.scss'], - templateUrl: './main.component.html' -}) -export class MainComponent implements OnDestroy { - @ViewChild('grid', { static: true }) public finGrid: GridFinJSComponent; - @ViewChild('controllers', { static: true }) public controller: ControllerComponent; - - @Output() public switch = new EventEmitter(); - @Output() public recordsVolume = new EventEmitter(); - @Output() public frequencyTimer = new EventEmitter(); - @Output() public player = new EventEmitter(); - - public volume = 1000; - public frequency = 500; - public darkTheme = true; - public data$: any; - private destroy$ = new Subject(); - private _timer; - - constructor(public finService: LocalService) { - this.finService.getFinancialData(this.volume); - this.data$ = this.finService.records.pipe(takeUntil(this.destroy$)); - } - - public ngOnDestroy() { - this.destroy$.next(true); - this.destroy$.complete(); - this.stopFeed(); - } - - public onSwitchChanged(event: any) { - switch (event.action) { - case 'toolbar': { - this.finGrid.showToolbar = event.value; - break; - } - case 'grouped': { - this.finGrid.toggleGrouping(event.value); - break; - } - default: - { - break; - } - } - } - - public onVolumeChanged(volume: any) { - this.finGrid.grid.deselectAllRows(); - this.finService.getFinancialData(volume); - } - - public onPlayAction(event: any) { - switch (event.action) { - case 'playAll': { - const currData = this.finGrid.grid.filteredSortedData ?? this.finGrid.data; - this._timer = setInterval(() => this.finService.updateAllPriceValues(currData), this.controller.frequency); - break; - } - case 'playRandom': { - const currData = this.finGrid.data; - this._timer = setInterval(() => this.finService.updateRandomPriceValues(currData), this.controller.frequency); - break; - } - case 'stop': { - this.stopFeed(); - break; - } - default: - { - break; - } - } - } - - public stopFeed() { - if (this._timer) { - clearInterval(this._timer); - } - } -} +import { Component, EventEmitter, OnDestroy, Output, ViewChild } from '@angular/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { LocalService } from '../shared/local.service'; +import { ControllerComponent } from './controllers.component'; +import { GridFinJSComponent } from './grid-finjs.component'; + +@Component({ + providers: [LocalService], + selector: 'app-finjs-main', + styleUrls: ['./main.component.scss'], + templateUrl: './main.component.html' +}) +export class MainComponent implements OnDestroy { + @ViewChild('grid', { static: true }) public finGrid: GridFinJSComponent; + @ViewChild('controllers', { static: true }) public controller: ControllerComponent; + + @Output() public switch = new EventEmitter(); + @Output() public recordsVolume = new EventEmitter(); + @Output() public frequencyTimer = new EventEmitter(); + @Output() public player = new EventEmitter(); + + public volume = 1000; + public frequency = 500; + public darkTheme = true; + public data$: any; + private destroy$ = new Subject(); + private _timer; + + constructor(public finService: LocalService) { + this.finService.getFinancialData(this.volume); + this.data$ = this.finService.records.pipe(takeUntil(this.destroy$)); + } + + public ngOnDestroy() { + this.destroy$.next(true); + this.destroy$.complete(); + this.stopFeed(); + } + + public onSwitchChanged(event: any) { + switch (event.action) { + case 'toolbar': { + this.finGrid.showToolbar = event.value; + break; + } + case 'grouped': { + this.finGrid.toggleGrouping(event.value); + break; + } + default: + { + break; + } + } + } + + public onVolumeChanged(volume: any) { + this.finGrid.grid.deselectAllRows(); + this.finService.getFinancialData(volume); + } + + public onPlayAction(event: any) { + switch (event.action) { + case 'playAll': { + const currData = this.finGrid.grid.filteredSortedData ?? this.finGrid.data; + this._timer = setInterval(() => this.finService.updateAllPriceValues(currData), this.controller.frequency); + break; + } + case 'playRandom': { + const currData = this.finGrid.data; + this._timer = setInterval(() => this.finService.updateRandomPriceValues(currData), this.controller.frequency); + break; + } + case 'stop': { + this.stopFeed(); + break; + } + default: + { + break; + } + } + } + + public stopFeed() { + if (this._timer) { + clearInterval(this._timer); + } + } +} diff --git a/src/app/grid-row-api/grid-row-api.sample.css b/src/app/grid-row-api/grid-row-api.sample.css index f814d60a525..824423498ba 100644 --- a/src/app/grid-row-api/grid-row-api.sample.css +++ b/src/app/grid-row-api/grid-row-api.sample.css @@ -1,76 +1,76 @@ -.sample-buttons { - margin-top: 24px; -} - -[igxButton] { - margin-right: 8px; - margin-bottom: 8px; -} - -.density-chooser { - margin-bottom: 16px; - max-width: 900px; -} - -.references { - font-size: .75em; -} - -.references>p { - margin: 0; - letter-spacing: initial; - line-height: initial; - font-size: 1em; -} - -.sample-column { - width: 60%; - margin: 8px; - flex-flow: ''; -} - -.log-wrapper { - width: 30%; -} - -.clearBtn { - top: 3px; - margin-left: 20px; -} - -.logContainer { - padding: 0.2rem 0.4rem; -} - -:host { - width: 100%; -} - -.sample-column { - display: flex; - flex-flow: row wrap !important; - width: 100%; -} - -.grid-wrapper { - width: 60%; -} - -.clearBtn { - top: 3px; - margin-left: 20px; -} - -.selected-data-area { - overflow-y: auto; - max-height: 550px; - width: 100%; - height: 100%; - box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); - margin-top: 8px; -} - -.highlight { - text-align: center; - margin-bottom: 0.4rem; +.sample-buttons { + margin-top: 24px; +} + +[igxButton] { + margin-right: 8px; + margin-bottom: 8px; +} + +.density-chooser { + margin-bottom: 16px; + max-width: 900px; +} + +.references { + font-size: .75em; +} + +.references>p { + margin: 0; + letter-spacing: initial; + line-height: initial; + font-size: 1em; +} + +.sample-column { + width: 60%; + margin: 8px; + flex-flow: ''; +} + +.log-wrapper { + width: 30%; +} + +.clearBtn { + top: 3px; + margin-left: 20px; +} + +.logContainer { + padding: 0.2rem 0.4rem; +} + +:host { + width: 100%; +} + +.sample-column { + display: flex; + flex-flow: row wrap !important; + width: 100%; +} + +.grid-wrapper { + width: 60%; +} + +.clearBtn { + top: 3px; + margin-left: 20px; +} + +.selected-data-area { + overflow-y: auto; + max-height: 550px; + width: 100%; + height: 100%; + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.2), 0 1px 1px 0 rgba(0, 0, 0, 0.14), 0 2px 1px -1px rgba(0, 0, 0, 0.12); + margin-top: 8px; +} + +.highlight { + text-align: center; + margin-bottom: 0.4rem; } \ No newline at end of file diff --git a/src/app/grid-row-api/grid-row-api.sample.html b/src/app/grid-row-api/grid-row-api.sample.html index b204da36ebd..daf52b40760 100644 --- a/src/app/grid-row-api/grid-row-api.sample.html +++ b/src/app/grid-row-api/grid-row-api.sample.html @@ -1,267 +1,267 @@ -
-
igxGrid
-
-
- -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-
-
- - -
-
Country: {{dataItem.Country}}
-
City: {{dataItem.City}}
-
Address: {{dataItem.Address}}
-
-
- - - -
- {{dragIcon}}{{countIcon}} -
-
- - - - - - - - - -
-
-
-
-
-
- -
-
-
-
- -
-
IgxTreeGrid Hierarchical Data
-
-
- -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-
-
- - - - - - - - - - ======= - - - -
-
-
-
-
- -
-
-
- -
-
IgxTreeGrid Flat Data
-
-
- -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-
-
- - - - - - - - - - - - -
-
-
-
-
- -
-
-
- -
-
igxHierarchicalGrid
-
-
- -
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- -
-
-
- - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- -
-
-
+
+
igxGrid
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+
+ + +
+
Country: {{dataItem.Country}}
+
City: {{dataItem.City}}
+
Address: {{dataItem.Address}}
+
+
+ + + +
+ {{dragIcon}}{{countIcon}} +
+
+ + + + + + + + + +
+
+
+
+
+
+ +
+
+
+
+ +
+
IgxTreeGrid Hierarchical Data
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+
+ + + + + + + + + + ======= + + + +
+
+
+
+
+ +
+
+
+ +
+
IgxTreeGrid Flat Data
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+
+
+ +
+
+
+ +
+
igxHierarchicalGrid
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+ +
+
+
diff --git a/src/app/grid-row-api/grid-row-api.sample.ts b/src/app/grid-row-api/grid-row-api.sample.ts index 5bfde56e20a..42987b7f547 100644 --- a/src/app/grid-row-api/grid-row-api.sample.ts +++ b/src/app/grid-row-api/grid-row-api.sample.ts @@ -1,323 +1,323 @@ -import { Component, OnInit, Renderer2, ViewChild } from '@angular/core'; -import { - IgxGridComponent, - RowType, - IgxTreeGridComponent, - IgxHierarchicalGridComponent, - IPinningConfig, - RowPinningPosition, - GridSummaryCalculationMode, - GridSummaryPosition -} from 'igniteui-angular'; -import { HIERARCHICAL_SAMPLE_DATA } from '../shared/sample-data'; - -@Component({ - selector: 'app-grid-row-api-sample', - styleUrls: ['grid-row-api.sample.css'], - templateUrl: 'grid-row-api.sample.html' -}) - -export class GridRowAPISampleComponent implements OnInit { - @ViewChild('grid', { static: true }) - private grid: IgxGridComponent; - - @ViewChild('targetGrid', { static: true }) - private targetGrid: IgxGridComponent; - - @ViewChild('treeGridHier', { static: true }) - private treeGridHier: IgxTreeGridComponent; - - @ViewChild('hGrid', { static: true }) - private hGrid: IgxTreeGridComponent; - public countIcon = 'drag_indicator'; - public dragIcon = 'arrow_right_alt'; - public data2: any; - public data: any[]; - public treeGridHierData: any[]; - public hierarchicalData: any[]; - public columns: any[]; - public hColumns: any[]; - public treeGridHierColumns: any[]; - public treeColumns: any[]; - public treeData: any[]; - - public index = 0; - public tIndex = 0; - public tHIndex = 0; - public hIndex = 0; - - public key = ''; - public tKey = ''; - public tHKey = ''; - public hKey = ''; - - public pinningConfig: IPinningConfig = { rows: RowPinningPosition.Top }; - - constructor(private renderer: Renderer2) { } - - public ngOnInit(): void { - this.grid.summaryCalculationMode = GridSummaryCalculationMode.childLevelsOnly; - this.grid.summaryPosition = GridSummaryPosition.bottom; - - this.treeGridHier.summaryCalculationMode = GridSummaryCalculationMode.childLevelsOnly; - this.columns = [ - { field: 'ID', width: '200px', hidden: true }, - { field: 'CompanyName', width: '200px', groupable: true }, - { field: 'ContactName', width: '200px', pinned: false, groupable: true }, - { field: 'ContactTitle', width: '300px', pinned: false, groupable: true }, - { field: 'Address', width: '250px' }, - { field: 'City', width: '200px' }, - { field: 'Region', width: '300px' }, - { field: 'PostalCode', width: '150px' }, - { field: 'Phone', width: '200px' }, - { field: 'Fax', width: '200px' } - ]; - - this.hColumns = [ - { field: 'ID', width: '200px' }, - { field: 'ChildLevels', width: '200px' }, - { field: 'ProductName', width: '200px' }, - { field: 'Col1', width: '200px' }, - { field: 'Col2', width: '200px' }, - { field: 'Col3', width: '200px' }, - { field: 'childData', width: '200px' }, - { field: 'childData2', width: '200px' }, - { field: 'hasChild', width: '200px' } - ]; - - this.treeGridHierColumns = [ - { field: 'ID', width: 200, resizable: true, pinned: true }, - { field: 'CompanyName', width: 150, resizable: true }, - { field: 'ContactName', width: 150, resizable: true }, - { field: 'ContactTitle', width: 150, resizable: true }, - { field: 'Address', width: 150, resizable: true }, - { field: 'City', width: 150, resizable: true, summary: true }, - { field: 'Region', width: 150, resizable: true }, - { field: 'PostalCode', width: 150, resizable: true }, - { field: 'Phone', width: 150, resizable: true }, - { field: 'Fax', width: 150, resizable: true } - ]; - this.treeGridHierData = HIERARCHICAL_SAMPLE_DATA.slice(0); - - this.data = [ - /* eslint-disable max-len */ - { ID: 'ALFKI', CompanyName: 'Alfreds Futterkiste', ContactName: 'Maria Anders', ContactTitle: 'Sales Representative', Address: 'Obere Str. 57', City: 'Berlin', Region: null, PostalCode: '12209', Country: 'Germany', Phone: '030-0074321', Fax: '030-0076545' }, - { ID: 'ANATR', CompanyName: 'Ana Trujillo Emparedados y helados', ContactName: 'Ana Trujillo', ContactTitle: 'Owner', Address: 'Avda. de la Constitución 2222', City: 'México D.F.', Region: null, PostalCode: '05021', Country: 'Mexico', Phone: '(5) 555-4729', Fax: '(5) 555-3745' }, - { ID: 'ANTON', CompanyName: 'Antonio Moreno Taquería', ContactName: 'Antonio Moreno', ContactTitle: 'Owner', Address: 'Mataderos 2312', City: 'México D.F.', Region: null, PostalCode: '05023', Country: 'Mexico', Phone: '(5) 555-3932', Fax: null }, - { ID: 'AROUT', CompanyName: 'Around the Horn', ContactName: 'Thomas Hardy', ContactTitle: 'Sales Representative', Address: '120 Hanover Sq.', City: 'London', Region: null, PostalCode: 'WA1 1DP', Country: 'UK', Phone: '(171) 555-7788', Fax: '(171) 555-6750' }, - { ID: 'BERGS', CompanyName: 'Berglunds snabbköp', ContactName: 'Christina Berglund', ContactTitle: 'Order Administrator', Address: 'Berguvsvägen 8', City: 'Luleå', Region: null, PostalCode: 'S-958 22', Country: 'Sweden', Phone: '0921-12 34 65', Fax: '0921-12 34 67' }, - { ID: 'BLAUS', CompanyName: 'Blauer See Delikatessen', ContactName: 'Hanna Moos', ContactTitle: 'Sales Representative', Address: 'Forsterstr. 57', City: 'Mannheim', Region: null, PostalCode: '68306', Country: 'Germany', Phone: '0621-08460', Fax: '0621-08924' }, - { ID: 'BLONP', CompanyName: 'Blondesddsl père et fils', ContactName: 'Frédérique Citeaux', ContactTitle: 'Marketing Manager', Address: '24, place Kléber', City: 'Strasbourg', Region: null, PostalCode: '67000', Country: 'France', Phone: '88.60.15.31', Fax: '88.60.15.32' }, - { ID: 'BOLID', CompanyName: 'Bólido Comidas preparadas', ContactName: 'Martín Sommer', ContactTitle: 'Owner', Address: 'C/ Araquil, 67', City: 'Madrid', Region: null, PostalCode: '28023', Country: 'Spain', Phone: '(91) 555 22 82', Fax: '(91) 555 91 99' }, - { ID: 'BONAP', CompanyName: 'Bon app\'', ContactName: 'Laurence Lebihan', ContactTitle: 'Owner', Address: '12, rue des Bouchers', City: 'Marseille', Region: null, PostalCode: '13008', Country: 'France', Phone: '91.24.45.40', Fax: '91.24.45.41' }, - { ID: 'BOTTM', CompanyName: 'Bottom-Dollar Markets', ContactName: 'Elizabeth Lincoln', ContactTitle: 'Accounting Manager', Address: '23 Tsawassen Blvd.', City: 'Tsawassen', Region: 'BC', PostalCode: 'T2F 8M4', Country: 'Canada', Phone: '(604) 555-4729', Fax: '(604) 555-3745' }, - { ID: 'BSBEV', CompanyName: 'B\'s Beverages', ContactName: 'Victoria Ashworth', ContactTitle: 'Sales Representative', Address: 'Fauntleroy Circus', City: 'London', Region: null, PostalCode: 'EC2 5NT', Country: 'UK', Phone: '(171) 555-1212', Fax: null }, - { ID: 'CACTU', CompanyName: 'Cactus Comidas para llevar', ContactName: 'Patricio Simpson', ContactTitle: 'Sales Agent', Address: 'Cerrito 333', City: 'Buenos Aires', Region: null, PostalCode: '1010', Country: 'Argentina', Phone: '(1) 135-5555', Fax: '(1) 135-4892' }, - { ID: 'CENTC', CompanyName: 'Centro comercial Moctezuma', ContactName: 'Francisco Chang', ContactTitle: 'Marketing Manager', Address: 'Sierras de Granada 9993', City: 'México D.F.', Region: null, PostalCode: '05022', Country: 'Mexico', Phone: '(5) 555-3392', Fax: '(5) 555-7293' }, - { ID: 'CHOPS', CompanyName: 'Chop-suey Chinese', ContactName: 'Yang Wang', ContactTitle: 'Owner', Address: 'Hauptstr. 29', City: 'Bern', Region: null, PostalCode: '3012', Country: 'Switzerland', Phone: '0452-076545', Fax: null }, - { ID: 'COMMI', CompanyName: 'Comércio Mineiro', ContactName: 'Pedro Afonso', ContactTitle: 'Sales Associate', Address: 'Av. dos Lusíadas, 23', City: 'Sao Paulo', Region: 'SP', PostalCode: '05432-043', Country: 'Brazil', Phone: '(11) 555-7647', Fax: null }, - { ID: 'CONSH', CompanyName: 'Consolidated Holdings', ContactName: 'Elizabeth Brown', ContactTitle: 'Sales Representative', Address: 'Berkeley Gardens 12 Brewery', City: 'London', Region: null, PostalCode: 'WX1 6LT', Country: 'UK', Phone: '(171) 555-2282', Fax: '(171) 555-9199' }, - { ID: 'DRACD', CompanyName: 'Drachenblut Delikatessen', ContactName: 'Sven Ottlieb', ContactTitle: 'Order Administrator', Address: 'Walserweg 21', City: 'Aachen', Region: null, PostalCode: '52066', Country: 'Germany', Phone: '0241-039123', Fax: '0241-059428' }, - { ID: 'DUMON', CompanyName: 'Du monde entier', ContactName: 'Janine Labrune', ContactTitle: 'Owner', Address: '67, rue des Cinquante Otages', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.67.88.88', Fax: '40.67.89.89' }, - { ID: 'EASTC', CompanyName: 'Eastern Connection', ContactName: 'Ann Devon', ContactTitle: 'Sales Agent', Address: '35 King George', City: 'London', Region: null, PostalCode: 'WX3 6FW', Country: 'UK', Phone: '(171) 555-0297', Fax: '(171) 555-3373' }, - { ID: 'ERNSH', CompanyName: 'Ernst Handel', ContactName: 'Roland Mendel', ContactTitle: 'Sales Manager', Address: 'Kirchgasse 6', City: 'Graz', Region: null, PostalCode: '8010', Country: 'Austria', Phone: '7675-3425', Fax: '7675-3426' }, - { ID: 'FAMIA', CompanyName: 'Familia Arquibaldo', ContactName: 'Aria Cruz', ContactTitle: 'Marketing Assistant', Address: 'Rua Orós, 92', City: 'Sao Paulo', Region: 'SP', PostalCode: '05442-030', Country: 'Brazil', Phone: '(11) 555-9857', Fax: null }, - { ID: 'FISSA', CompanyName: 'FISSA Fabrica Inter. Salchichas S.A.', ContactName: 'Diego Roel', ContactTitle: 'Accounting Manager', Address: 'C/ Moralzarzal, 86', City: 'Madrid', Region: null, PostalCode: '28034', Country: 'Spain', Phone: '(91) 555 94 44', Fax: '(91) 555 55 93' }, - { ID: 'FOLIG', CompanyName: 'Folies gourmandes', ContactName: 'Martine Rancé', ContactTitle: 'Assistant Sales Agent', Address: '184, chaussée de Tournai', City: 'Lille', Region: null, PostalCode: '59000', Country: 'France', Phone: '20.16.10.16', Fax: '20.16.10.17' }, - { ID: 'FOLKO', CompanyName: 'Folk och fä HB', ContactName: 'Maria Larsson', ContactTitle: 'Owner', Address: 'Åkergatan 24', City: 'Bräcke', Region: null, PostalCode: 'S-844 67', Country: 'Sweden', Phone: '0695-34 67 21', Fax: null }, - { ID: 'FRANK', CompanyName: 'Frankenversand', ContactName: 'Peter Franken', ContactTitle: 'Marketing Manager', Address: 'Berliner Platz 43', City: 'München', Region: null, PostalCode: '80805', Country: 'Germany', Phone: '089-0877310', Fax: '089-0877451' }, - { ID: 'FRANR', CompanyName: 'France restauration', ContactName: 'Carine Schmitt', ContactTitle: 'Marketing Manager', Address: '54, rue Royale', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.32.21.21', Fax: '40.32.21.20' }, - { ID: 'FRANS', CompanyName: 'Franchi S.p.A.', ContactName: 'Paolo Accorti', ContactTitle: 'Sales Representative', Address: 'Via Monte Bianco 34', City: 'Torino', Region: null, PostalCode: '10100', Country: 'Italy', Phone: '011-4988260', Fax: '011-4988261' } - ]; - this.hierarchicalData = this.generateDataUneven(100, 3); - - // treegrid cols and data - this.treeColumns = [ - { field: 'employeeID', label: 'ID', width: 200, resizable: true, dataType: 'number', hasSummary: false }, - { field: 'Salary', label: 'Salary', width: 200, resizable: true, dataType: 'number', hasSummary: true }, - { field: 'firstName', label: 'First Name', width: 300, resizable: true, dataType: 'string', hasSummary: false }, - { field: 'lastName', label: 'Last Name', width: 150, resizable: true, dataType: 'string', hasSummary: false }, - { field: 'Title', label: 'Title', width: 200, resizable: true, dataType: 'string', hasSummary: true } - ]; - this.treeData = [ - { Salary: 2500, employeeID: 0, PID: -1, firstName: 'Andrew', lastName: 'Fuller', Title: 'Vice President, Sales' }, - { Salary: 3500, employeeID: 1, PID: -1, firstName: 'Jonathan', lastName: 'Smith', Title: 'Human resources' }, - { Salary: 1500, employeeID: 2, PID: -1, firstName: 'Nancy', lastName: 'Davolio', Title: 'CFO' }, - { Salary: 2500, employeeID: 3, PID: -1, firstName: 'Steven', lastName: 'Buchanan', Title: 'CTO' }, - // sub of ID 0 - { Salary: 2500, employeeID: 4, PID: 0, firstName: 'Janet', lastName: 'Leverling', Title: 'Sales Manager' }, - { Salary: 3500, employeeID: 5, PID: 0, firstName: 'Laura', lastName: 'Callahan', Title: 'Inside Sales Coordinator' }, - { Salary: 1500, employeeID: 6, PID: 0, firstName: 'Margaret', lastName: 'Peacock', Title: 'Sales Representative' }, - { Salary: 2500, employeeID: 7, PID: 0, firstName: 'Michael', lastName: 'Suyama', Title: 'Sales Representative' }, - // sub of ID 4 - { Salary: 2500, employeeID: 8, PID: 4, firstName: 'Anne', lastName: 'Dodsworth', Title: 'Sales Representative' }, - { Salary: 3500, employeeID: 9, PID: 4, firstName: 'Danielle', lastName: 'Davis', Title: 'Sales Representative' }, - { Salary: 1500, employeeID: 10, PID: 4, firstName: 'Robert', lastName: 'King', Title: 'Sales Representative' }, - // sub of ID 2 - { Salary: 2500, employeeID: 11, PID: 2, firstName: 'Peter', lastName: 'Lewis', Title: 'Chief Accountant' }, - { Salary: 3500, employeeID: 12, PID: 2, firstName: 'Ryder', lastName: 'Zenaida', Title: 'Accountant' }, - { Salary: 1500, employeeID: 13, PID: 2, firstName: 'Wang', lastName: 'Mercedes', Title: 'Accountant' }, - // sub of ID 3 - { Salary: 1500, employeeID: 14, PID: 3, firstName: 'Theodore', lastName: 'Zia', Title: 'Software Architect' }, - { Salary: 4500, employeeID: 15, PID: 3, firstName: 'Lacota', lastName: 'Mufutau', Title: 'Product Manager' }, - // sub of ID 16 - { Salary: 2500, employeeID: 16, PID: 15, firstName: 'Jin', lastName: 'Elliott', Title: 'Product Owner' }, - { Salary: 3500, employeeID: 17, PID: 15, firstName: 'Armand', lastName: 'Ross', Title: 'Product Owner' }, - { Salary: 1500, employeeID: 18, PID: 15, firstName: 'Dane', lastName: 'Rodriquez', Title: 'Team Leader' }, - // sub of ID 19 - { Salary: 2500, employeeID: 19, PID: 18, firstName: 'Declan', lastName: 'Lester', Title: 'Senior Software Developer' }, - { Salary: 3500, employeeID: 20, PID: 18, firstName: 'Bernard', lastName: 'Jarvis', Title: 'Senior Software Developer' }, - { Salary: 1500, employeeID: 21, PID: 18, firstName: 'Jason', lastName: 'Clark', Title: 'QA' }, - { Salary: 1500, employeeID: 22, PID: 18, firstName: 'Mark', lastName: 'Young', Title: 'QA' }, - // sub of ID 20 - { Salary: 1500, employeeID: 23, PID: 20, firstName: 'Jeremy', lastName: 'Donaldson', Title: 'Software Developer' } - ]; - /* eslint-enable max-len */ - } - - public togglePinning(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, - byIndex: boolean, index: number, key: any) { - const row: RowType = byIndex ? grid.getRowByIndex(index) : grid.getRowByKey(key); - if (row.pinned) { - row.unpin(); - } else { - row.pin(); - } - } - - - public deleteRow(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number) { - const row = grid.getRowByIndex(index); - row.delete(); - } - - public toggle(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number) { - const row = grid.getRowByIndex(index); - row.expanded = !row.expanded; - } - - public select(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number) { - const row = grid.getRowByIndex(index); - row.selected = !row.selected; - } - - public selectChildren(grid: IgxGridComponent | IgxTreeGridComponent, index: number) { - const row = grid.getRowByIndex(index); - const children = row.children; - children.forEach(ch => { - ch.selected = !ch.selected; - }); - } - - public selectParent(grid: IgxGridComponent | IgxTreeGridComponent, index: number) { - const row = grid.getRowByIndex(index); - const parent = row.parent; - parent.selected = !parent.selected; - if (parent) { - parent.selected = !parent.selected; - } - } - - public generateDataUneven(count: number, level: number, parendID: string = null) { - const prods = []; - const currLevel = level; - let children; - for (let i = 0; i < count; i++) { - const rowID = parendID ? parendID + i : i.toString(); - if (level > 0) { - // Have child grids for row with even id less rows by not multiplying by 2 - children = this.generateDataUneven(((i % 2) + 1) * Math.round(count / 3), currLevel - 1, rowID); - } - prods.push({ - ID: rowID, - ChildLevels: currLevel, - ProductName: 'Product: A' + i, - Col1: i, - Col2: i, - Col3: i, - childData: children, - childData2: children, - hasChild: true - }); - } - return prods; - } - - public clearLog(logger: HTMLElement) { - const elements = logger.querySelectorAll('p'); - - elements.forEach(element => { - this.renderer.removeChild(logger, element); - }); - } - - public logState(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number, logger: HTMLElement) { - this.clearLog(logger); - const row = grid.getRowByIndex(index); - const state = ` - index: ${row.index}, - viewIndex: ${row.viewIndex}, - -----------------------------, - isSummaryRow: ${row.isSummaryRow}, - summaries: ${row.summaries}, - -----------------------------, - isGroupByRow: ${row.isGroupByRow}, - groupByRow: ${row.groupRow?.value}, - -----------------------------, - parent: ${row.parent}, - expanded: ${row.expanded}, - key: ${row.key}, - pinned: ${row.pinned}, - deleted: ${row.deleted}, - inEditMode: ${row.inEditMode}, - selected: ${row.selected}, - hasChildren: ${row.hasChildren}, - disabled: ${row.disabled}, - --------------------------------, - cells.length: ${row.cells?.length}`; - // firstCell: ${row.cells[0].value}, - // lastCell: ${row.cells[row.cells.length - 1].value}`; - - const states = state.split(','); - const createElem = this.renderer.createElement('p'); - - states.forEach(st => { - const text = this.renderer.createText(st); - this.renderer.appendChild(createElem, text); - this.renderer.appendChild(createElem, this.renderer.createElement('br')); - }); - - this.renderer.insertBefore(logger, createElem, logger.children[0]); - } - - public onRowDragEnd(args) { - args.animation = true; - } - - public onDropAllowed(args) { - let selected = false; - const ids = this.grid.selectedRows; - const selectedRowData = this.grid.data.filter((record) => ids.includes(record.ID)); - selectedRowData.forEach((rowData) => { - selected = true; - this.targetGrid.addRow(rowData); - this.grid.deleteRow(rowData.ID); - }); - if (selected === false) { - this.targetGrid.addRow(args.dragData.data); - // this.grid.deleteRow(args.dragData.key); - } - } - - public onEnter() { - this.dragIcon = 'add'; - } - public onRowDragStart() { - const count = this.grid.selectedRows.length || 1; - this.countIcon = `filter_${count > 9 ? '9_plus' : `${count}`}`; - } - public onLeave() { - this.onRowDragStart(); - this.dragIcon = 'arrow_right_alt'; - } -} +import { Component, OnInit, Renderer2, ViewChild } from '@angular/core'; +import { + IgxGridComponent, + RowType, + IgxTreeGridComponent, + IgxHierarchicalGridComponent, + IPinningConfig, + RowPinningPosition, + GridSummaryCalculationMode, + GridSummaryPosition +} from 'igniteui-angular'; +import { HIERARCHICAL_SAMPLE_DATA } from '../shared/sample-data'; + +@Component({ + selector: 'app-grid-row-api-sample', + styleUrls: ['grid-row-api.sample.css'], + templateUrl: 'grid-row-api.sample.html' +}) + +export class GridRowAPISampleComponent implements OnInit { + @ViewChild('grid', { static: true }) + private grid: IgxGridComponent; + + @ViewChild('targetGrid', { static: true }) + private targetGrid: IgxGridComponent; + + @ViewChild('treeGridHier', { static: true }) + private treeGridHier: IgxTreeGridComponent; + + @ViewChild('hGrid', { static: true }) + private hGrid: IgxTreeGridComponent; + public countIcon = 'drag_indicator'; + public dragIcon = 'arrow_right_alt'; + public data2: any; + public data: any[]; + public treeGridHierData: any[]; + public hierarchicalData: any[]; + public columns: any[]; + public hColumns: any[]; + public treeGridHierColumns: any[]; + public treeColumns: any[]; + public treeData: any[]; + + public index = 0; + public tIndex = 0; + public tHIndex = 0; + public hIndex = 0; + + public key = ''; + public tKey = ''; + public tHKey = ''; + public hKey = ''; + + public pinningConfig: IPinningConfig = { rows: RowPinningPosition.Top }; + + constructor(private renderer: Renderer2) { } + + public ngOnInit(): void { + this.grid.summaryCalculationMode = GridSummaryCalculationMode.childLevelsOnly; + this.grid.summaryPosition = GridSummaryPosition.bottom; + + this.treeGridHier.summaryCalculationMode = GridSummaryCalculationMode.childLevelsOnly; + this.columns = [ + { field: 'ID', width: '200px', hidden: true }, + { field: 'CompanyName', width: '200px', groupable: true }, + { field: 'ContactName', width: '200px', pinned: false, groupable: true }, + { field: 'ContactTitle', width: '300px', pinned: false, groupable: true }, + { field: 'Address', width: '250px' }, + { field: 'City', width: '200px' }, + { field: 'Region', width: '300px' }, + { field: 'PostalCode', width: '150px' }, + { field: 'Phone', width: '200px' }, + { field: 'Fax', width: '200px' } + ]; + + this.hColumns = [ + { field: 'ID', width: '200px' }, + { field: 'ChildLevels', width: '200px' }, + { field: 'ProductName', width: '200px' }, + { field: 'Col1', width: '200px' }, + { field: 'Col2', width: '200px' }, + { field: 'Col3', width: '200px' }, + { field: 'childData', width: '200px' }, + { field: 'childData2', width: '200px' }, + { field: 'hasChild', width: '200px' } + ]; + + this.treeGridHierColumns = [ + { field: 'ID', width: 200, resizable: true, pinned: true }, + { field: 'CompanyName', width: 150, resizable: true }, + { field: 'ContactName', width: 150, resizable: true }, + { field: 'ContactTitle', width: 150, resizable: true }, + { field: 'Address', width: 150, resizable: true }, + { field: 'City', width: 150, resizable: true, summary: true }, + { field: 'Region', width: 150, resizable: true }, + { field: 'PostalCode', width: 150, resizable: true }, + { field: 'Phone', width: 150, resizable: true }, + { field: 'Fax', width: 150, resizable: true } + ]; + this.treeGridHierData = HIERARCHICAL_SAMPLE_DATA.slice(0); + + this.data = [ + /* eslint-disable max-len */ + { ID: 'ALFKI', CompanyName: 'Alfreds Futterkiste', ContactName: 'Maria Anders', ContactTitle: 'Sales Representative', Address: 'Obere Str. 57', City: 'Berlin', Region: null, PostalCode: '12209', Country: 'Germany', Phone: '030-0074321', Fax: '030-0076545' }, + { ID: 'ANATR', CompanyName: 'Ana Trujillo Emparedados y helados', ContactName: 'Ana Trujillo', ContactTitle: 'Owner', Address: 'Avda. de la Constitución 2222', City: 'México D.F.', Region: null, PostalCode: '05021', Country: 'Mexico', Phone: '(5) 555-4729', Fax: '(5) 555-3745' }, + { ID: 'ANTON', CompanyName: 'Antonio Moreno Taquería', ContactName: 'Antonio Moreno', ContactTitle: 'Owner', Address: 'Mataderos 2312', City: 'México D.F.', Region: null, PostalCode: '05023', Country: 'Mexico', Phone: '(5) 555-3932', Fax: null }, + { ID: 'AROUT', CompanyName: 'Around the Horn', ContactName: 'Thomas Hardy', ContactTitle: 'Sales Representative', Address: '120 Hanover Sq.', City: 'London', Region: null, PostalCode: 'WA1 1DP', Country: 'UK', Phone: '(171) 555-7788', Fax: '(171) 555-6750' }, + { ID: 'BERGS', CompanyName: 'Berglunds snabbköp', ContactName: 'Christina Berglund', ContactTitle: 'Order Administrator', Address: 'Berguvsvägen 8', City: 'Luleå', Region: null, PostalCode: 'S-958 22', Country: 'Sweden', Phone: '0921-12 34 65', Fax: '0921-12 34 67' }, + { ID: 'BLAUS', CompanyName: 'Blauer See Delikatessen', ContactName: 'Hanna Moos', ContactTitle: 'Sales Representative', Address: 'Forsterstr. 57', City: 'Mannheim', Region: null, PostalCode: '68306', Country: 'Germany', Phone: '0621-08460', Fax: '0621-08924' }, + { ID: 'BLONP', CompanyName: 'Blondesddsl père et fils', ContactName: 'Frédérique Citeaux', ContactTitle: 'Marketing Manager', Address: '24, place Kléber', City: 'Strasbourg', Region: null, PostalCode: '67000', Country: 'France', Phone: '88.60.15.31', Fax: '88.60.15.32' }, + { ID: 'BOLID', CompanyName: 'Bólido Comidas preparadas', ContactName: 'Martín Sommer', ContactTitle: 'Owner', Address: 'C/ Araquil, 67', City: 'Madrid', Region: null, PostalCode: '28023', Country: 'Spain', Phone: '(91) 555 22 82', Fax: '(91) 555 91 99' }, + { ID: 'BONAP', CompanyName: 'Bon app\'', ContactName: 'Laurence Lebihan', ContactTitle: 'Owner', Address: '12, rue des Bouchers', City: 'Marseille', Region: null, PostalCode: '13008', Country: 'France', Phone: '91.24.45.40', Fax: '91.24.45.41' }, + { ID: 'BOTTM', CompanyName: 'Bottom-Dollar Markets', ContactName: 'Elizabeth Lincoln', ContactTitle: 'Accounting Manager', Address: '23 Tsawassen Blvd.', City: 'Tsawassen', Region: 'BC', PostalCode: 'T2F 8M4', Country: 'Canada', Phone: '(604) 555-4729', Fax: '(604) 555-3745' }, + { ID: 'BSBEV', CompanyName: 'B\'s Beverages', ContactName: 'Victoria Ashworth', ContactTitle: 'Sales Representative', Address: 'Fauntleroy Circus', City: 'London', Region: null, PostalCode: 'EC2 5NT', Country: 'UK', Phone: '(171) 555-1212', Fax: null }, + { ID: 'CACTU', CompanyName: 'Cactus Comidas para llevar', ContactName: 'Patricio Simpson', ContactTitle: 'Sales Agent', Address: 'Cerrito 333', City: 'Buenos Aires', Region: null, PostalCode: '1010', Country: 'Argentina', Phone: '(1) 135-5555', Fax: '(1) 135-4892' }, + { ID: 'CENTC', CompanyName: 'Centro comercial Moctezuma', ContactName: 'Francisco Chang', ContactTitle: 'Marketing Manager', Address: 'Sierras de Granada 9993', City: 'México D.F.', Region: null, PostalCode: '05022', Country: 'Mexico', Phone: '(5) 555-3392', Fax: '(5) 555-7293' }, + { ID: 'CHOPS', CompanyName: 'Chop-suey Chinese', ContactName: 'Yang Wang', ContactTitle: 'Owner', Address: 'Hauptstr. 29', City: 'Bern', Region: null, PostalCode: '3012', Country: 'Switzerland', Phone: '0452-076545', Fax: null }, + { ID: 'COMMI', CompanyName: 'Comércio Mineiro', ContactName: 'Pedro Afonso', ContactTitle: 'Sales Associate', Address: 'Av. dos Lusíadas, 23', City: 'Sao Paulo', Region: 'SP', PostalCode: '05432-043', Country: 'Brazil', Phone: '(11) 555-7647', Fax: null }, + { ID: 'CONSH', CompanyName: 'Consolidated Holdings', ContactName: 'Elizabeth Brown', ContactTitle: 'Sales Representative', Address: 'Berkeley Gardens 12 Brewery', City: 'London', Region: null, PostalCode: 'WX1 6LT', Country: 'UK', Phone: '(171) 555-2282', Fax: '(171) 555-9199' }, + { ID: 'DRACD', CompanyName: 'Drachenblut Delikatessen', ContactName: 'Sven Ottlieb', ContactTitle: 'Order Administrator', Address: 'Walserweg 21', City: 'Aachen', Region: null, PostalCode: '52066', Country: 'Germany', Phone: '0241-039123', Fax: '0241-059428' }, + { ID: 'DUMON', CompanyName: 'Du monde entier', ContactName: 'Janine Labrune', ContactTitle: 'Owner', Address: '67, rue des Cinquante Otages', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.67.88.88', Fax: '40.67.89.89' }, + { ID: 'EASTC', CompanyName: 'Eastern Connection', ContactName: 'Ann Devon', ContactTitle: 'Sales Agent', Address: '35 King George', City: 'London', Region: null, PostalCode: 'WX3 6FW', Country: 'UK', Phone: '(171) 555-0297', Fax: '(171) 555-3373' }, + { ID: 'ERNSH', CompanyName: 'Ernst Handel', ContactName: 'Roland Mendel', ContactTitle: 'Sales Manager', Address: 'Kirchgasse 6', City: 'Graz', Region: null, PostalCode: '8010', Country: 'Austria', Phone: '7675-3425', Fax: '7675-3426' }, + { ID: 'FAMIA', CompanyName: 'Familia Arquibaldo', ContactName: 'Aria Cruz', ContactTitle: 'Marketing Assistant', Address: 'Rua Orós, 92', City: 'Sao Paulo', Region: 'SP', PostalCode: '05442-030', Country: 'Brazil', Phone: '(11) 555-9857', Fax: null }, + { ID: 'FISSA', CompanyName: 'FISSA Fabrica Inter. Salchichas S.A.', ContactName: 'Diego Roel', ContactTitle: 'Accounting Manager', Address: 'C/ Moralzarzal, 86', City: 'Madrid', Region: null, PostalCode: '28034', Country: 'Spain', Phone: '(91) 555 94 44', Fax: '(91) 555 55 93' }, + { ID: 'FOLIG', CompanyName: 'Folies gourmandes', ContactName: 'Martine Rancé', ContactTitle: 'Assistant Sales Agent', Address: '184, chaussée de Tournai', City: 'Lille', Region: null, PostalCode: '59000', Country: 'France', Phone: '20.16.10.16', Fax: '20.16.10.17' }, + { ID: 'FOLKO', CompanyName: 'Folk och fä HB', ContactName: 'Maria Larsson', ContactTitle: 'Owner', Address: 'Åkergatan 24', City: 'Bräcke', Region: null, PostalCode: 'S-844 67', Country: 'Sweden', Phone: '0695-34 67 21', Fax: null }, + { ID: 'FRANK', CompanyName: 'Frankenversand', ContactName: 'Peter Franken', ContactTitle: 'Marketing Manager', Address: 'Berliner Platz 43', City: 'München', Region: null, PostalCode: '80805', Country: 'Germany', Phone: '089-0877310', Fax: '089-0877451' }, + { ID: 'FRANR', CompanyName: 'France restauration', ContactName: 'Carine Schmitt', ContactTitle: 'Marketing Manager', Address: '54, rue Royale', City: 'Nantes', Region: null, PostalCode: '44000', Country: 'France', Phone: '40.32.21.21', Fax: '40.32.21.20' }, + { ID: 'FRANS', CompanyName: 'Franchi S.p.A.', ContactName: 'Paolo Accorti', ContactTitle: 'Sales Representative', Address: 'Via Monte Bianco 34', City: 'Torino', Region: null, PostalCode: '10100', Country: 'Italy', Phone: '011-4988260', Fax: '011-4988261' } + ]; + this.hierarchicalData = this.generateDataUneven(100, 3); + + // treegrid cols and data + this.treeColumns = [ + { field: 'employeeID', label: 'ID', width: 200, resizable: true, dataType: 'number', hasSummary: false }, + { field: 'Salary', label: 'Salary', width: 200, resizable: true, dataType: 'number', hasSummary: true }, + { field: 'firstName', label: 'First Name', width: 300, resizable: true, dataType: 'string', hasSummary: false }, + { field: 'lastName', label: 'Last Name', width: 150, resizable: true, dataType: 'string', hasSummary: false }, + { field: 'Title', label: 'Title', width: 200, resizable: true, dataType: 'string', hasSummary: true } + ]; + this.treeData = [ + { Salary: 2500, employeeID: 0, PID: -1, firstName: 'Andrew', lastName: 'Fuller', Title: 'Vice President, Sales' }, + { Salary: 3500, employeeID: 1, PID: -1, firstName: 'Jonathan', lastName: 'Smith', Title: 'Human resources' }, + { Salary: 1500, employeeID: 2, PID: -1, firstName: 'Nancy', lastName: 'Davolio', Title: 'CFO' }, + { Salary: 2500, employeeID: 3, PID: -1, firstName: 'Steven', lastName: 'Buchanan', Title: 'CTO' }, + // sub of ID 0 + { Salary: 2500, employeeID: 4, PID: 0, firstName: 'Janet', lastName: 'Leverling', Title: 'Sales Manager' }, + { Salary: 3500, employeeID: 5, PID: 0, firstName: 'Laura', lastName: 'Callahan', Title: 'Inside Sales Coordinator' }, + { Salary: 1500, employeeID: 6, PID: 0, firstName: 'Margaret', lastName: 'Peacock', Title: 'Sales Representative' }, + { Salary: 2500, employeeID: 7, PID: 0, firstName: 'Michael', lastName: 'Suyama', Title: 'Sales Representative' }, + // sub of ID 4 + { Salary: 2500, employeeID: 8, PID: 4, firstName: 'Anne', lastName: 'Dodsworth', Title: 'Sales Representative' }, + { Salary: 3500, employeeID: 9, PID: 4, firstName: 'Danielle', lastName: 'Davis', Title: 'Sales Representative' }, + { Salary: 1500, employeeID: 10, PID: 4, firstName: 'Robert', lastName: 'King', Title: 'Sales Representative' }, + // sub of ID 2 + { Salary: 2500, employeeID: 11, PID: 2, firstName: 'Peter', lastName: 'Lewis', Title: 'Chief Accountant' }, + { Salary: 3500, employeeID: 12, PID: 2, firstName: 'Ryder', lastName: 'Zenaida', Title: 'Accountant' }, + { Salary: 1500, employeeID: 13, PID: 2, firstName: 'Wang', lastName: 'Mercedes', Title: 'Accountant' }, + // sub of ID 3 + { Salary: 1500, employeeID: 14, PID: 3, firstName: 'Theodore', lastName: 'Zia', Title: 'Software Architect' }, + { Salary: 4500, employeeID: 15, PID: 3, firstName: 'Lacota', lastName: 'Mufutau', Title: 'Product Manager' }, + // sub of ID 16 + { Salary: 2500, employeeID: 16, PID: 15, firstName: 'Jin', lastName: 'Elliott', Title: 'Product Owner' }, + { Salary: 3500, employeeID: 17, PID: 15, firstName: 'Armand', lastName: 'Ross', Title: 'Product Owner' }, + { Salary: 1500, employeeID: 18, PID: 15, firstName: 'Dane', lastName: 'Rodriquez', Title: 'Team Leader' }, + // sub of ID 19 + { Salary: 2500, employeeID: 19, PID: 18, firstName: 'Declan', lastName: 'Lester', Title: 'Senior Software Developer' }, + { Salary: 3500, employeeID: 20, PID: 18, firstName: 'Bernard', lastName: 'Jarvis', Title: 'Senior Software Developer' }, + { Salary: 1500, employeeID: 21, PID: 18, firstName: 'Jason', lastName: 'Clark', Title: 'QA' }, + { Salary: 1500, employeeID: 22, PID: 18, firstName: 'Mark', lastName: 'Young', Title: 'QA' }, + // sub of ID 20 + { Salary: 1500, employeeID: 23, PID: 20, firstName: 'Jeremy', lastName: 'Donaldson', Title: 'Software Developer' } + ]; + /* eslint-enable max-len */ + } + + public togglePinning(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, + byIndex: boolean, index: number, key: any) { + const row: RowType = byIndex ? grid.getRowByIndex(index) : grid.getRowByKey(key); + if (row.pinned) { + row.unpin(); + } else { + row.pin(); + } + } + + + public deleteRow(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number) { + const row = grid.getRowByIndex(index); + row.delete(); + } + + public toggle(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number) { + const row = grid.getRowByIndex(index); + row.expanded = !row.expanded; + } + + public select(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number) { + const row = grid.getRowByIndex(index); + row.selected = !row.selected; + } + + public selectChildren(grid: IgxGridComponent | IgxTreeGridComponent, index: number) { + const row = grid.getRowByIndex(index); + const children = row.children; + children.forEach(ch => { + ch.selected = !ch.selected; + }); + } + + public selectParent(grid: IgxGridComponent | IgxTreeGridComponent, index: number) { + const row = grid.getRowByIndex(index); + const parent = row.parent; + parent.selected = !parent.selected; + if (parent) { + parent.selected = !parent.selected; + } + } + + public generateDataUneven(count: number, level: number, parendID: string = null) { + const prods = []; + const currLevel = level; + let children; + for (let i = 0; i < count; i++) { + const rowID = parendID ? parendID + i : i.toString(); + if (level > 0) { + // Have child grids for row with even id less rows by not multiplying by 2 + children = this.generateDataUneven(((i % 2) + 1) * Math.round(count / 3), currLevel - 1, rowID); + } + prods.push({ + ID: rowID, + ChildLevels: currLevel, + ProductName: 'Product: A' + i, + Col1: i, + Col2: i, + Col3: i, + childData: children, + childData2: children, + hasChild: true + }); + } + return prods; + } + + public clearLog(logger: HTMLElement) { + const elements = logger.querySelectorAll('p'); + + elements.forEach(element => { + this.renderer.removeChild(logger, element); + }); + } + + public logState(grid: IgxGridComponent | IgxTreeGridComponent | IgxHierarchicalGridComponent, index: number, logger: HTMLElement) { + this.clearLog(logger); + const row = grid.getRowByIndex(index); + const state = ` + index: ${row.index}, + viewIndex: ${row.viewIndex}, + -----------------------------, + isSummaryRow: ${row.isSummaryRow}, + summaries: ${row.summaries}, + -----------------------------, + isGroupByRow: ${row.isGroupByRow}, + groupByRow: ${row.groupRow?.value}, + -----------------------------, + parent: ${row.parent}, + expanded: ${row.expanded}, + key: ${row.key}, + pinned: ${row.pinned}, + deleted: ${row.deleted}, + inEditMode: ${row.inEditMode}, + selected: ${row.selected}, + hasChildren: ${row.hasChildren}, + disabled: ${row.disabled}, + --------------------------------, + cells.length: ${row.cells?.length}`; + // firstCell: ${row.cells[0].value}, + // lastCell: ${row.cells[row.cells.length - 1].value}`; + + const states = state.split(','); + const createElem = this.renderer.createElement('p'); + + states.forEach(st => { + const text = this.renderer.createText(st); + this.renderer.appendChild(createElem, text); + this.renderer.appendChild(createElem, this.renderer.createElement('br')); + }); + + this.renderer.insertBefore(logger, createElem, logger.children[0]); + } + + public onRowDragEnd(args) { + args.animation = true; + } + + public onDropAllowed(args) { + let selected = false; + const ids = this.grid.selectedRows; + const selectedRowData = this.grid.data.filter((record) => ids.includes(record.ID)); + selectedRowData.forEach((rowData) => { + selected = true; + this.targetGrid.addRow(rowData); + this.grid.deleteRow(rowData.ID); + }); + if (selected === false) { + this.targetGrid.addRow(args.dragData.data); + // this.grid.deleteRow(args.dragData.key); + } + } + + public onEnter() { + this.dragIcon = 'add'; + } + public onRowDragStart() { + const count = this.grid.selectedRows.length || 1; + this.countIcon = `filter_${count > 9 ? '9_plus' : `${count}`}`; + } + public onLeave() { + this.onRowDragStart(); + this.dragIcon = 'arrow_right_alt'; + } +} diff --git a/src/app/grid-updates-test/aminoData.ts b/src/app/grid-updates-test/aminoData.ts index ece38ccb18e..478adcbb7cf 100644 --- a/src/app/grid-updates-test/aminoData.ts +++ b/src/app/grid-updates-test/aminoData.ts @@ -1,552 +1,552 @@ -export const AMINO_DATA = [ - { - id: 1, - name: 'Alanine', - abbreviation: { - short: 'A', - long: 'Ala', - owner: { - name: 'User' - } - }, - weight: { - molecular: 89.1, - residue: 71.08 - }, - formula: { - molecular: 'C3H7NO2', - residue: 'C3H5NO' - }, - p: { - Ka: 2.34, - Kb: 9.69, - Kx: null, - l: 6.0 - } - }, - { - id: 2, - name: 'Arginine', - abbreviation: { - short: 'R', - long: 'Arg', - owner: { - name: 'User' - } - }, - weight: { - molecular: 174.2, - residue: 156.19 - }, - formula: { - molecular: 'C6H14N4O2', - residue: 'C6H12N4O' - }, - p: { - Ka: 2.17, - Kb: 9.04, - Kx: 12.48, - l: 10.76 - } - }, - { - id: 3, - name: 'Asparagine', - abbreviation: { - short: 'N', - long: 'Asn', - owner: { - name: 'User' - } - }, - weight: { - molecular: 132.12, - residue: 114.11 - }, - formula: { - molecular: 'C4H8N2O3', - residue: 'C4H6N2O2' - }, - p: { - Ka: 2.02, - Kb: 8.8, - Kx: null, - l: 5.41 - } - }, - { - id: 4, - name: 'Aspartic acid', - abbreviation: { - short: 'D', - long: 'Asp', - owner: { - name: 'User' - } - }, - weight: { - molecular: 133.11, - residue: 115.09 - }, - formula: { - molecular: 'C4H7NO4', - residue: 'C4H5NO3' - }, - p: { - Ka: 1.88, - Kb: 9.6, - Kx: 3.65, - l: 2.77 - } - }, - { - id: 5, - name: 'Cysteine', - abbreviation: { - short: 'C', - long: 'Cys', - owner: { - name: 'User' - } - }, - weight: { - molecular: 121.16, - residue: 103.15 - }, - formula: { - molecular: 'C3H7NO2S', - residue: 'C3H5NOS' - }, - p: { - Ka: 1.96, - Kb: 10.28, - Kx: 8.18, - l: 5.07 - } - }, - { - id: 6, - name: 'Glutamic acid', - abbreviation: { - short: 'E', - long: 'Glu', - owner: { - name: 'User' - } - }, - weight: { - molecular: 147.13, - residue: 129.12 - }, - formula: { - molecular: 'C5H9NO4', - residue: 'C5H7NO3' - }, - p: { - Ka: 2.19, - Kb: 9.67, - Kx: 4.25, - l: 3.22 - } - }, - { - id: 7, - name: 'Glutamine', - abbreviation: { - short: 'Q', - long: 'Gln', - owner: { - name: 'User' - } - }, - weight: { - molecular: 146.15, - residue: 128.13 - }, - formula: { - molecular: 'C5H10N2O3', - residue: 'C5H8N2O2' - }, - p: { - Ka: 2.17, - Kb: 9.13, - Kx: null, - l: 5.65 - } - }, - { - id: 8, - name: 'Glycine', - abbreviation: { - short: 'G', - long: 'Gly', - owner: { - name: 'User' - } - }, - weight: { - molecular: 75.07, - residue: 57.05 - }, - formula: { - molecular: 'C2H5NO2', - residue: 'C2H3NO' - }, - p: { - Ka: 2.34, - Kb: 9.6, - Kx: null, - l: 5.97 - } - }, - { - id: 9, - name: 'Histidine', - abbreviation: { - short: 'H', - long: 'His', - owner: { - name: 'User' - } - }, - weight: { - molecular: 155.16, - residue: 137.14 - }, - formula: { - molecular: 'C6H9N3O2', - residue: 'C6H7N3O' - }, - p: { - Ka: 1.82, - Kb: 9.17, - Kx: 6.0, - l: 7.59 - } - }, - { - id: 10, - name: 'Hydroxyproline', - abbreviation: { - short: 'O', - long: 'Hyp', - owner: { - name: 'User' - } - }, - weight: { - molecular: 131.13, - residue: 113.11 - }, - formula: { - molecular: 'C5H9NO3', - residue: 'C5H7NO2' - }, - p: { - Ka: 1.82, - Kb: 9.65, - Kx: null, - l: null - } - }, - { - id: 11, - name: 'Isoleucine', - abbreviation: { - short: 'I', - long: 'Ile', - owner: { - name: 'User' - } - }, - weight: { - molecular: 131.18, - residue: 113.16 - }, - formula: { - molecular: 'C6H13NO2', - residue: 'C6H11NO' - }, - p: { - Ka: 2.36, - Kb: 9.6, - Kx: null, - l: 6.02 - } - }, - { - id: 12, - name: 'Leucine', - abbreviation: { - short: 'L', - long: 'Leu', - owner: { - name: 'User' - } - }, - weight: { - molecular: 131.18, - residue: 113.16 - }, - formula: { - molecular: 'C6H13NO2', - residue: 'C6H11NO' - }, - p: { - Ka: 2.36, - Kb: 9.6, - Kx: null, - l: 5.98 - } - }, - { - id: 13, - name: 'Lysine', - abbreviation: { - short: 'K', - long: 'Lys', - owner: { - name: 'User' - } - }, - weight: { - molecular: 146.19, - residue: 128.18 - }, - formula: { - molecular: 'C6H14N2O2', - residue: 'C6H12N2O' - }, - p: { - Ka: 2.18, - Kb: 8.95, - Kx: 10.53, - l: 9.74 - } - }, - { - id: 14, - name: 'Methionine', - abbreviation: { - short: 'M', - long: 'Met', - owner: { - name: 'User' - } - }, - weight: { - molecular: 149.21, - residue: 131.2 - }, - formula: { - molecular: 'C5H11NO2S', - residue: 'C5H9NOS' - }, - p: { - Ka: 2.28, - Kb: 9.21, - Kx: null, - l: 5.74 - } - }, - { - id: 15, - name: 'Phenylalanine', - abbreviation: { - short: 'F', - long: 'Phe', - owner: { - name: 'User' - } - }, - weight: { - molecular: 165.19, - residue: 147.18 - }, - formula: { - molecular: 'C9H11NO2', - residue: 'C9H9NO' - }, - p: { - Ka: 1.83, - Kb: 9.13, - Kx: null, - l: 5.48 - } - }, - { - id: 16, - name: 'Proline', - abbreviation: { - short: 'P', - long: 'Pro', - owner: { - name: 'User' - } - }, - weight: { - molecular: 115.13, - residue: 97.12 - }, - formula: { - molecular: 'C5H9NO2', - residue: 'C5H7NO' - }, - p: { - Ka: 1.99, - Kb: 10.6, - Kx: null, - l: 6.3 - } - }, - { - id: 17, - name: 'Pyroglutamatic', - abbreviation: { - short: 'U', - long: 'Glp', - owner: { - name: 'User' - } - }, - weight: { - molecular: 139.11, - residue: 121.09 - }, - formula: { - molecular: 'C5H7NO3', - residue: 'C5H5NO2' - }, - p: { - Ka: null, - Kb: null, - Kx: null, - l: 5.68 - } - }, - { - id: 18, - name: 'Serine', - abbreviation: { - short: 'S', - long: 'Ser', - owner: { - name: 'User' - } - }, - weight: { - molecular: 105.09, - residue: 87.08 - }, - formula: { - molecular: 'C3H7NO3', - residue: 'C3H5NO2' - }, - p: { - Ka: 2.21, - Kb: 9.15, - Kx: null, - l: 5.68 - } - }, - { - id: 19, - name: 'Threonine', - abbreviation: { - short: 'T', - long: 'Thr', - owner: { - name: 'User' - } - }, - weight: { - molecular: 119.12, - residue: 101.11 - }, - formula: { - molecular: 'C4H9NO3', - residue: 'C4H7NO2' - }, - p: { - Ka: 2.09, - Kb: 9.1, - Kx: null, - l: 5.6 - } - }, - { - id: 20, - name: 'Tryptophan', - abbreviation: { - short: 'W', - long: 'Trp', - owner: { - name: 'User' - } - }, - weight: { - molecular: 204.23, - residue: 186.22 - }, - formula: { - molecular: 'C11H12N2O2', - residue: 'C11H10N2O' - }, - p: { - Ka: 2.83, - Kb: 9.39, - Kx: null, - l: 5.89 - } - }, - { - id: 21, - name: 'Tyrosine', - abbreviation: { - short: 'Y', - long: 'Tyr', - owner: { - name: 'User' - } - }, - weight: { - molecular: 181.19, - residue: 163.18 - }, - formula: { - molecular: 'C9H11NO3', - residue: 'C9H9NO2' - }, - p: { - Ka: 2.2, - Kb: 9.11, - Kx: 10.07, - l: 5.66 - } - }, - { - id: 22, - name: 'Valine', - abbreviation: { - short: 'V', - long: 'Val', - owner: { - name: 'User' - } - }, - weight: { - molecular: 117.15, - residue: 99.13 - }, - formula: { - molecular: 'C5H11NO2', - residue: 'C5H9NO' - }, - p: { - Ka: 2.32, - Kb: 9.62, - Kx: null, - l: 5.96 - } - } - ]; +export const AMINO_DATA = [ + { + id: 1, + name: 'Alanine', + abbreviation: { + short: 'A', + long: 'Ala', + owner: { + name: 'User' + } + }, + weight: { + molecular: 89.1, + residue: 71.08 + }, + formula: { + molecular: 'C3H7NO2', + residue: 'C3H5NO' + }, + p: { + Ka: 2.34, + Kb: 9.69, + Kx: null, + l: 6.0 + } + }, + { + id: 2, + name: 'Arginine', + abbreviation: { + short: 'R', + long: 'Arg', + owner: { + name: 'User' + } + }, + weight: { + molecular: 174.2, + residue: 156.19 + }, + formula: { + molecular: 'C6H14N4O2', + residue: 'C6H12N4O' + }, + p: { + Ka: 2.17, + Kb: 9.04, + Kx: 12.48, + l: 10.76 + } + }, + { + id: 3, + name: 'Asparagine', + abbreviation: { + short: 'N', + long: 'Asn', + owner: { + name: 'User' + } + }, + weight: { + molecular: 132.12, + residue: 114.11 + }, + formula: { + molecular: 'C4H8N2O3', + residue: 'C4H6N2O2' + }, + p: { + Ka: 2.02, + Kb: 8.8, + Kx: null, + l: 5.41 + } + }, + { + id: 4, + name: 'Aspartic acid', + abbreviation: { + short: 'D', + long: 'Asp', + owner: { + name: 'User' + } + }, + weight: { + molecular: 133.11, + residue: 115.09 + }, + formula: { + molecular: 'C4H7NO4', + residue: 'C4H5NO3' + }, + p: { + Ka: 1.88, + Kb: 9.6, + Kx: 3.65, + l: 2.77 + } + }, + { + id: 5, + name: 'Cysteine', + abbreviation: { + short: 'C', + long: 'Cys', + owner: { + name: 'User' + } + }, + weight: { + molecular: 121.16, + residue: 103.15 + }, + formula: { + molecular: 'C3H7NO2S', + residue: 'C3H5NOS' + }, + p: { + Ka: 1.96, + Kb: 10.28, + Kx: 8.18, + l: 5.07 + } + }, + { + id: 6, + name: 'Glutamic acid', + abbreviation: { + short: 'E', + long: 'Glu', + owner: { + name: 'User' + } + }, + weight: { + molecular: 147.13, + residue: 129.12 + }, + formula: { + molecular: 'C5H9NO4', + residue: 'C5H7NO3' + }, + p: { + Ka: 2.19, + Kb: 9.67, + Kx: 4.25, + l: 3.22 + } + }, + { + id: 7, + name: 'Glutamine', + abbreviation: { + short: 'Q', + long: 'Gln', + owner: { + name: 'User' + } + }, + weight: { + molecular: 146.15, + residue: 128.13 + }, + formula: { + molecular: 'C5H10N2O3', + residue: 'C5H8N2O2' + }, + p: { + Ka: 2.17, + Kb: 9.13, + Kx: null, + l: 5.65 + } + }, + { + id: 8, + name: 'Glycine', + abbreviation: { + short: 'G', + long: 'Gly', + owner: { + name: 'User' + } + }, + weight: { + molecular: 75.07, + residue: 57.05 + }, + formula: { + molecular: 'C2H5NO2', + residue: 'C2H3NO' + }, + p: { + Ka: 2.34, + Kb: 9.6, + Kx: null, + l: 5.97 + } + }, + { + id: 9, + name: 'Histidine', + abbreviation: { + short: 'H', + long: 'His', + owner: { + name: 'User' + } + }, + weight: { + molecular: 155.16, + residue: 137.14 + }, + formula: { + molecular: 'C6H9N3O2', + residue: 'C6H7N3O' + }, + p: { + Ka: 1.82, + Kb: 9.17, + Kx: 6.0, + l: 7.59 + } + }, + { + id: 10, + name: 'Hydroxyproline', + abbreviation: { + short: 'O', + long: 'Hyp', + owner: { + name: 'User' + } + }, + weight: { + molecular: 131.13, + residue: 113.11 + }, + formula: { + molecular: 'C5H9NO3', + residue: 'C5H7NO2' + }, + p: { + Ka: 1.82, + Kb: 9.65, + Kx: null, + l: null + } + }, + { + id: 11, + name: 'Isoleucine', + abbreviation: { + short: 'I', + long: 'Ile', + owner: { + name: 'User' + } + }, + weight: { + molecular: 131.18, + residue: 113.16 + }, + formula: { + molecular: 'C6H13NO2', + residue: 'C6H11NO' + }, + p: { + Ka: 2.36, + Kb: 9.6, + Kx: null, + l: 6.02 + } + }, + { + id: 12, + name: 'Leucine', + abbreviation: { + short: 'L', + long: 'Leu', + owner: { + name: 'User' + } + }, + weight: { + molecular: 131.18, + residue: 113.16 + }, + formula: { + molecular: 'C6H13NO2', + residue: 'C6H11NO' + }, + p: { + Ka: 2.36, + Kb: 9.6, + Kx: null, + l: 5.98 + } + }, + { + id: 13, + name: 'Lysine', + abbreviation: { + short: 'K', + long: 'Lys', + owner: { + name: 'User' + } + }, + weight: { + molecular: 146.19, + residue: 128.18 + }, + formula: { + molecular: 'C6H14N2O2', + residue: 'C6H12N2O' + }, + p: { + Ka: 2.18, + Kb: 8.95, + Kx: 10.53, + l: 9.74 + } + }, + { + id: 14, + name: 'Methionine', + abbreviation: { + short: 'M', + long: 'Met', + owner: { + name: 'User' + } + }, + weight: { + molecular: 149.21, + residue: 131.2 + }, + formula: { + molecular: 'C5H11NO2S', + residue: 'C5H9NOS' + }, + p: { + Ka: 2.28, + Kb: 9.21, + Kx: null, + l: 5.74 + } + }, + { + id: 15, + name: 'Phenylalanine', + abbreviation: { + short: 'F', + long: 'Phe', + owner: { + name: 'User' + } + }, + weight: { + molecular: 165.19, + residue: 147.18 + }, + formula: { + molecular: 'C9H11NO2', + residue: 'C9H9NO' + }, + p: { + Ka: 1.83, + Kb: 9.13, + Kx: null, + l: 5.48 + } + }, + { + id: 16, + name: 'Proline', + abbreviation: { + short: 'P', + long: 'Pro', + owner: { + name: 'User' + } + }, + weight: { + molecular: 115.13, + residue: 97.12 + }, + formula: { + molecular: 'C5H9NO2', + residue: 'C5H7NO' + }, + p: { + Ka: 1.99, + Kb: 10.6, + Kx: null, + l: 6.3 + } + }, + { + id: 17, + name: 'Pyroglutamatic', + abbreviation: { + short: 'U', + long: 'Glp', + owner: { + name: 'User' + } + }, + weight: { + molecular: 139.11, + residue: 121.09 + }, + formula: { + molecular: 'C5H7NO3', + residue: 'C5H5NO2' + }, + p: { + Ka: null, + Kb: null, + Kx: null, + l: 5.68 + } + }, + { + id: 18, + name: 'Serine', + abbreviation: { + short: 'S', + long: 'Ser', + owner: { + name: 'User' + } + }, + weight: { + molecular: 105.09, + residue: 87.08 + }, + formula: { + molecular: 'C3H7NO3', + residue: 'C3H5NO2' + }, + p: { + Ka: 2.21, + Kb: 9.15, + Kx: null, + l: 5.68 + } + }, + { + id: 19, + name: 'Threonine', + abbreviation: { + short: 'T', + long: 'Thr', + owner: { + name: 'User' + } + }, + weight: { + molecular: 119.12, + residue: 101.11 + }, + formula: { + molecular: 'C4H9NO3', + residue: 'C4H7NO2' + }, + p: { + Ka: 2.09, + Kb: 9.1, + Kx: null, + l: 5.6 + } + }, + { + id: 20, + name: 'Tryptophan', + abbreviation: { + short: 'W', + long: 'Trp', + owner: { + name: 'User' + } + }, + weight: { + molecular: 204.23, + residue: 186.22 + }, + formula: { + molecular: 'C11H12N2O2', + residue: 'C11H10N2O' + }, + p: { + Ka: 2.83, + Kb: 9.39, + Kx: null, + l: 5.89 + } + }, + { + id: 21, + name: 'Tyrosine', + abbreviation: { + short: 'Y', + long: 'Tyr', + owner: { + name: 'User' + } + }, + weight: { + molecular: 181.19, + residue: 163.18 + }, + formula: { + molecular: 'C9H11NO3', + residue: 'C9H9NO2' + }, + p: { + Ka: 2.2, + Kb: 9.11, + Kx: 10.07, + l: 5.66 + } + }, + { + id: 22, + name: 'Valine', + abbreviation: { + short: 'V', + long: 'Val', + owner: { + name: 'User' + } + }, + weight: { + molecular: 117.15, + residue: 99.13 + }, + formula: { + molecular: 'C5H11NO2', + residue: 'C5H9NO' + }, + p: { + Ka: 2.32, + Kb: 9.62, + Kx: null, + l: 5.96 + } + } + ]; diff --git a/src/app/grid-updates-test/grid-updates.component.html b/src/app/grid-updates-test/grid-updates.component.html index 0ebfed7848a..4e3a9e15c35 100644 --- a/src/app/grid-updates-test/grid-updates.component.html +++ b/src/app/grid-updates-test/grid-updates.component.html @@ -1,24 +1,24 @@ - - - - - - - - -

Selected Name: {{selectedItem?.name}}

-

Selected Abbr. (long): {{selectedItem?.abbreviation.long}}

-

Selected Abbr. (owner name): {{selectedItem?.abbreviation.owner.name}}

+ + + + + + + + +

Selected Name: {{selectedItem?.name}}

+

Selected Abbr. (long): {{selectedItem?.abbreviation.long}}

+

Selected Abbr. (owner name): {{selectedItem?.abbreviation.owner.name}}

diff --git a/src/app/grid-updates-test/grid-updates.component.ts b/src/app/grid-updates-test/grid-updates.component.ts index e144eb665ef..877ac7f15ed 100644 --- a/src/app/grid-updates-test/grid-updates.component.ts +++ b/src/app/grid-updates-test/grid-updates.component.ts @@ -1,86 +1,86 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; -import { IRowSelectionEventArgs } from 'igniteui-angular'; -import { IgxGridComponent } from 'projects/igniteui-angular/src/lib/grids/grid/grid.component'; -import { AMINO_DATA } from './aminoData'; - -@Component({ - selector: 'app-grid-updates', - styleUrls: ['./grid-updates.component.scss'], - templateUrl: './grid-updates.component.html' -}) -export class GridUpdatesComponent implements OnInit { - @ViewChild('grid') public grid: IgxGridComponent; - public data = [...AMINO_DATA]; - - public nestedConfigColumns = [ - { field: 'name', header: 'Name' }, - { field: 'abbreviation.long', header: 'Abbr. (long)' }, - { field: 'abbreviation.owner.name', header: 'Abbr. (owner name)' } - ]; - - public counter = 0; - public selectedItem?: any; - private _update; - private itemUpdater: ItemUpdater; - - public ngOnInit(): void { - this.itemUpdater = new ItemUpdater(this.data[0], item => - this.onItemUpdate(item) - ); - } - - public update(): void { - this.itemUpdater.update(); - } - - public stop(): void { - this.itemUpdater.stop(); - } - - public handleRowSelectionChange(args: IRowSelectionEventArgs): void { - if (!args.newSelection || args.newSelection.length === 0) { - this.selectedItem = undefined; - } else { - const selectedItemId = args.newSelection[0] as number; - this.selectedItem = this.data.find(d => d.id === selectedItemId); - - // Fix: Make a copy - //this.selectedItem = this.originalItems.find(d => d === selectedItemId); - } - } - - private onItemUpdate(item: any) { - // update the data record reference - const itemIndex = this.data.findIndex(d => d.id === item.id); - this.data[itemIndex] = { ...item }; - - // Needed because of OnPush strategy - this.grid.markForCheck(); - } -} - -class ItemUpdater { - public counter = 0; - private _update; - - constructor(private item: any, private cb: (i: any) => void) {} - - public update(): void { - this._update = setInterval(() => this.updateData(this.counter), 100); - } - - public stop(): void { - clearInterval(this._update); - } - - public updateData(counter: number): void { - this.counter++; - - // update - this.item.name = `Alanine ${counter}`; - this.item.abbreviation.long = `Ala ${counter}`; - this.item.abbreviation.owner.name = `User ${counter}`; - - this.cb(this.item); - } -} +import { Component, OnInit, ViewChild } from '@angular/core'; +import { IRowSelectionEventArgs } from 'igniteui-angular'; +import { IgxGridComponent } from 'projects/igniteui-angular/src/lib/grids/grid/grid.component'; +import { AMINO_DATA } from './aminoData'; + +@Component({ + selector: 'app-grid-updates', + styleUrls: ['./grid-updates.component.scss'], + templateUrl: './grid-updates.component.html' +}) +export class GridUpdatesComponent implements OnInit { + @ViewChild('grid') public grid: IgxGridComponent; + public data = [...AMINO_DATA]; + + public nestedConfigColumns = [ + { field: 'name', header: 'Name' }, + { field: 'abbreviation.long', header: 'Abbr. (long)' }, + { field: 'abbreviation.owner.name', header: 'Abbr. (owner name)' } + ]; + + public counter = 0; + public selectedItem?: any; + private _update; + private itemUpdater: ItemUpdater; + + public ngOnInit(): void { + this.itemUpdater = new ItemUpdater(this.data[0], item => + this.onItemUpdate(item) + ); + } + + public update(): void { + this.itemUpdater.update(); + } + + public stop(): void { + this.itemUpdater.stop(); + } + + public handleRowSelectionChange(args: IRowSelectionEventArgs): void { + if (!args.newSelection || args.newSelection.length === 0) { + this.selectedItem = undefined; + } else { + const selectedItemId = args.newSelection[0] as number; + this.selectedItem = this.data.find(d => d.id === selectedItemId); + + // Fix: Make a copy + //this.selectedItem = this.originalItems.find(d => d === selectedItemId); + } + } + + private onItemUpdate(item: any) { + // update the data record reference + const itemIndex = this.data.findIndex(d => d.id === item.id); + this.data[itemIndex] = { ...item }; + + // Needed because of OnPush strategy + this.grid.markForCheck(); + } +} + +class ItemUpdater { + public counter = 0; + private _update; + + constructor(private item: any, private cb: (i: any) => void) {} + + public update(): void { + this._update = setInterval(() => this.updateData(this.counter), 100); + } + + public stop(): void { + clearInterval(this._update); + } + + public updateData(counter: number): void { + this.counter++; + + // update + this.item.name = `Alanine ${counter}`; + this.item.abbreviation.long = `Ala ${counter}`; + this.item.abbreviation.owner.name = `User ${counter}`; + + this.cb(this.item); + } +} diff --git a/src/web.config b/src/web.config index 30edc0f7ba0..5d230644d8a 100644 --- a/src/web.config +++ b/src/web.config @@ -1,17 +1,17 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + \ No newline at end of file