diff --git a/browser/public/index.html b/browser/public/index.html index c808bc6d0e..d185bec069 100644 --- a/browser/public/index.html +++ b/browser/public/index.html @@ -483,6 +483,7 @@ Action Strip Advanced Filtering Options Advanced Filtering Style + Batch Editing Binding Composite Data Binding Crud Data Binding Nested Data1 @@ -667,6 +668,7 @@ Excel Style Filtering Style Filtering Options Filtering Style + Grid Batch Editing Layout Display Density Multi Column Headers Export Multi Column Headers Overview @@ -781,6 +783,7 @@ Filtering Options Filtering Style Finjs + Grid Batch Editing Keyboard Custom Navigation Keyboard Navigation Guide Layout Display Density diff --git a/samples/grids/grid/grid-batch-editing/.prettierrc b/samples/grids/grid/grid-batch-editing/.prettierrc new file mode 100644 index 0000000000..15a7c7c6cf --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/.prettierrc @@ -0,0 +1,11 @@ +{ + "printWidth": 250, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "none", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "fluid": false +} \ No newline at end of file diff --git a/samples/grids/grid/grid-batch-editing/ReadMe.md b/samples/grids/grid/grid-batch-editing/ReadMe.md new file mode 100644 index 0000000000..94d190b64b --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of Web Components application with example of Batch Editing feature using [Grid](https://infragistics.com/webcomponentssite/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-angular-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-angular-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +To set up this project locally, execute these commands: + +``` +git clone https://github.com/IgniteUI/igniteui-wc-examples.git +git checkout master +cd ./igniteui-wc-examples +cd ./samples/grids/grid/grid-batch-editing +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: + +``` +npm install +npm run start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for Web Components**, check out the [Web Components documentation](https://infragistics.com/webcomponentssite/components/general-getting-started.html). diff --git a/samples/grids/grid/grid-batch-editing/index.html b/samples/grids/grid/grid-batch-editing/index.html new file mode 100644 index 0000000000..e09839ac19 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/index.html @@ -0,0 +1,145 @@ + + + + Grid Batch Editing | Ignite UI | Web Components | infragistics + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Add Row +
+ Undo + Redo + Discard + Commit +
+
+ + + + + + + +
+ Commit + Discard + Cancel +
+
+
+
+ + + <% if (false) { %><% } %> + + diff --git a/samples/grids/grid/grid-batch-editing/package.json b/samples/grids/grid/grid-batch-editing/package.json new file mode 100644 index 0000000000..8c50536621 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/package.json @@ -0,0 +1,61 @@ +{ + "name": "example-ignite-ui-web-components", + "description": "This project provides example of using Ignite UI for Web Components", + "author": "Infragistics", + "version": "1.0.0", + "license": "", + "private": true, + "homepage": ".", + "main": "src/index.ts", + "scripts": { + "build": "npm run build:prod", + "build:dev": "webpack --mode development --config ./webpack.config.js --progress --color --display-error-details", + "build:prod": "webpack --env.NODE_ENV=production --mode production --config ./webpack.config.js --progress --color --display-error-details --bail", + "serve:dev": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --config ./webpack.config.js --hot --progress --open", + "serve:prod": "webpack-dev-server --env.NODE_ENV=production --mode production --config ./webpack.config.js --port 3000 --host 0.0.0.0 --hot --progress --open --content-base dist/", + "start": "npm run serve:dev", + "build:legacy": "npm run build:prod:legacy", + "build:dev:legacy": "webpack --env.legacy=true --mode development --config ./webpack.config.js --progress --color --display-error-details", + "build:prod:legacy": "webpack --env.NODE_ENV=production --env.legacy=true --mode production --config ./webpack.config.js --progress --color --display-error-details --bail", + "serve:dev:legacy": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --env.legacy=true --mode development --config ./webpack.config.js --hot --progress --open", + "serve:prod:legacy": "webpack-dev-server --env.NODE_ENV=production --env.legacy=true --mode production --config ./webpack.config.js --port 3000 --host 0.0.0.0 --hot --progress --open --content-base dist/", + "start:legacy": "npm run serve:dev:legacy" + }, + "dependencies": { + "babel-runtime": "^6.26.0", + "igniteui-webcomponents": "^6.3.6", + "igniteui-webcomponents-core": "6.3.1", + "igniteui-webcomponents-grids": "6.3.0-alpha.1", + "igniteui-webcomponents-inputs": "6.3.1", + "igniteui-webcomponents-layouts": "6.3.1", + "lit-html": "^3.3.1", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@babel/cli": "^7.28.3", + "@babel/core": "^7.28.4", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-runtime": "^7.28.3", + "@babel/preset-env": "^7.28.3", + "@babel/preset-typescript": "^7.27.1", + "@types/source-map": "^0.5.7", + "babel-loader": "^10.0.0", + "babel-plugin-transform-custom-element-classes": "^0.1.0", + "css-loader": "^7.1.2", + "csv-loader": "^3.0.5", + "file-loader": "^6.2.0", + "fork-ts-checker-webpack-plugin": "^9.1.0", + "html-webpack-plugin": "^5.6.4", + "parcel-bundler": "^1.12.5", + "source-map": "^0.7.6", + "style-loader": "^4.0.0", + "tsconfig-paths-webpack-plugin": "^4.2.0", + "typescript": "^5.9.2", + "webpack": "^5.101.3", + "webpack-cli": "^6.0.1", + "webpack-dev-server": "^5.2.2", + "worker-loader": "^3.0.8", + "xml-loader": "^1.2.1" + } +} diff --git a/samples/grids/grid/grid-batch-editing/sandbox.config.json b/samples/grids/grid/grid-batch-editing/sandbox.config.json new file mode 100644 index 0000000000..52c7875103 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/sandbox.config.json @@ -0,0 +1,6 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser", + "template": "parcel" +} \ No newline at end of file diff --git a/samples/grids/grid/grid-batch-editing/src/NwindData.json b/samples/grids/grid/grid-batch-editing/src/NwindData.json new file mode 100644 index 0000000000..c00b03ec8d --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/src/NwindData.json @@ -0,0 +1,458 @@ +[ + { + "ProductID": 1, + "ProductName": "Chai", + "SupplierID": 1, + "CategoryID": 1, + "QuantityPerUnit": "10 boxes x 20 bags", + "UnitPrice": 18, + "UnitsInStock": 39, + "UnitsOnOrder": 30, + "ReorderLevel": 10, + "Discontinued": false, + "OrderDate": "2012-02-12", + "Rating": 5, + "Locations": [ + { + "Shop": "Fun-Tasty Co.", + "LastInventory": "2018-06-12" + }, + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + } + ] + }, + { + "ProductID": 2, + "ProductName": "Chang", + "SupplierID": 1, + "CategoryID": 1, + "QuantityPerUnit": "24 - 12 oz bottles", + "UnitPrice": 19, + "UnitsInStock": 17, + "UnitsOnOrder": 40, + "ReorderLevel": 25, + "Discontinued": true, + "OrderDate": "2003-03-17", + "Rating": 5, + "Locations": [ + { + "Shop": "Super Market", + "LastInventory": "2018-09-09" + } + ] + }, + { + "ProductID": 3, + "ProductName": "Aniseed Syrup", + "SupplierID": 1, + "CategoryID": 2, + "QuantityPerUnit": "12 - 550 ml bottles", + "UnitPrice": 10, + "UnitsInStock": 13, + "UnitsOnOrder": 70, + "ReorderLevel": 25, + "Discontinued": false, + "OrderDate": "2006-03-17", + "Rating": 3, + "Locations": [ + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + }, + { + "Shop": "Street Market", + "LastInventory": "2018-12-12" + }, + { + "Shop": "24/7 Market", + "LastInventory": "2018-11-11" + } + ] + }, + { + "ProductID": 4, + "ProductName": "Chef Antons Cajun Seasoning", + "SupplierID": 2, + "CategoryID": 2, + "QuantityPerUnit": "48 - 6 oz jars", + "UnitPrice": 22, + "UnitsInStock": 53, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2016-03-17", + "Rating": 3, + "Locations": [ + { + "Shop": "Fun-Tasty Co.", + "LastInventory": "2018-06-12" + }, + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + }, + { + "Shop": "Street Market", + "LastInventory": "2018-12-12" + } + ] + }, + { + "ProductID": 5, + "ProductName": "Chef Antons Gumbo Mix", + "SupplierID": 2, + "CategoryID": 2, + "QuantityPerUnit": "36 boxes", + "UnitPrice": 21.35, + "UnitsInStock": 0, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": true, + "OrderDate": "2011-11-11", + "Rating": 5, + "Locations": [ + { + "Shop": "Super Market", + "LastInventory": "2018-09-09" + } + ] + }, + { + "ProductID": 6, + "ProductName": "Grandmas Boysenberry Spread", + "SupplierID": 3, + "CategoryID": 2, + "QuantityPerUnit": "12 - 8 oz jars", + "UnitPrice": 25, + "UnitsInStock": 0, + "UnitsOnOrder": 30, + "ReorderLevel": 25, + "Discontinued": false, + "OrderDate": "2017-12-17", + "Rating": 4, + "Locations": [ + { + "Shop": "Super Market", + "LastInventory": "2018-09-09" + } + ] + }, + { + "ProductID": 7, + "ProductName": "Uncle Bobs Organic Dried Pears", + "SupplierID": 3, + "CategoryID": 7, + "QuantityPerUnit": "12 - 1 lb pkgs.", + "UnitPrice": 30, + "UnitsInStock": 150, + "UnitsOnOrder": 30, + "ReorderLevel": 10, + "Discontinued": false, + "OrderDate": "2016-07-17", + "Rating": 5, + "Locations": [ + { + "Shop": "Fun-Tasty Co.", + "LastInventory": "2018-06-12" + }, + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + }, + { + "Shop": "Street Market", + "LastInventory": "2018-12-12" + } + ] + }, + { + "ProductID": 8, + "ProductName": "Northwoods Cranberry Sauce", + "SupplierID": 3, + "CategoryID": 2, + "QuantityPerUnit": "12 - 12 oz jars", + "UnitPrice": 40, + "UnitsInStock": 6, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2018-01-17", + "Rating": 4, + "Locations": [ + { + "Shop": "Fun-Tasty Co.", + "LastInventory": "2018-06-12" + }, + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + } + ] + }, + { + "ProductID": 9, + "ProductName": "Mishi Kobe Niku", + "SupplierID": 4, + "CategoryID": 6, + "QuantityPerUnit": "18 - 500 g pkgs.", + "UnitPrice": 97, + "UnitsInStock": 29, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": true, + "OrderDate": "2010-02-17", + "Rating": 4, + "Locations": [ + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + } + ] + }, + { + "ProductID": 10, + "ProductName": "Ikura", + "SupplierID": 4, + "CategoryID": 8, + "QuantityPerUnit": "12 - 200 ml jars", + "UnitPrice": 31, + "UnitsInStock": 31, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2008-05-17", + "Rating": 3, + "Locations": [ + { + "Shop": "Wall Market", + "LastInventory": "2018-12-06" + } + ] + }, + { + "ProductID": 11, + "ProductName": "Queso Cabrales", + "SupplierID": 5, + "CategoryID": 4, + "QuantityPerUnit": "1 kg pkg.", + "UnitPrice": 21, + "UnitsInStock": 22, + "UnitsOnOrder": 30, + "ReorderLevel": 30, + "Discontinued": false, + "OrderDate": "2009-01-17", + "Rating": 5, + "Locations": [ + { + "Shop": "Fun-Tasty Co.", + "LastInventory": "2018-06-12" + }, + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + } + ] + }, + { + "ProductID": 12, + "ProductName": "Queso Manchego La Pastora", + "SupplierID": 5, + "CategoryID": 4, + "QuantityPerUnit": "10 - 500 g pkgs.", + "UnitPrice": 38, + "UnitsInStock": 86, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2015-11-17", + "Rating": 3, + "Locations": [ + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + } + ] + }, + { + "ProductID": 13, + "ProductName": "Konbu", + "SupplierID": 6, + "CategoryID": 8, + "QuantityPerUnit": "2 kg box", + "UnitPrice": 6, + "UnitsInStock": 24, + "UnitsOnOrder": 30, + "ReorderLevel": 5, + "Discontinued": false, + "OrderDate": "2015-03-17", + "Rating": 2, + "Locations": [ + { + "Shop": "Super Market", + "LastInventory": "2018-09-09" + } + ] + }, + { + "ProductID": 14, + "ProductName": "Tofu", + "SupplierID": 6, + "CategoryID": 7, + "QuantityPerUnit": "40 - 100 g pkgs.", + "UnitPrice": 23.25, + "UnitsInStock": 35, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2017-06-17", + "Rating": 4, + "Locations": [ + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + }, + { + "Shop": "Street Market", + "LastInventory": "2018-12-12" + } + ] + }, + { + "ProductID": 15, + "ProductName": "Genen Shouyu", + "SupplierID": 6, + "CategoryID": 2, + "QuantityPerUnit": "24 - 250 ml bottles", + "UnitPrice": 15.5, + "UnitsInStock": 39, + "UnitsOnOrder": 30, + "ReorderLevel": 5, + "Discontinued": false, + "OrderDate": "2014-03-17", + "Rating": 4, + "Locations": [ + { + "Shop": "Local Market", + "LastInventory": "2018-07-03" + }, + { + "Shop": "Wall Market", + "LastInventory": "2018-12-06" + } + ] + }, + { + "ProductID": 16, + "ProductName": "Pavlova", + "SupplierID": 7, + "CategoryID": 3, + "QuantityPerUnit": "32 - 500 g boxes", + "UnitPrice": 17.45, + "UnitsInStock": 29, + "UnitsOnOrder": 30, + "ReorderLevel": 10, + "Discontinued": false, + "OrderDate": "2018-03-28", + "Rating": 2, + "Locations": [ + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + }, + { + "Shop": "Street Market", + "LastInventory": "2018-12-12" + }, + { + "Shop": "24/7 Market", + "LastInventory": "2018-11-11" + } + ] + }, + { + "ProductID": 17, + "ProductName": "Alice Mutton", + "SupplierID": 7, + "CategoryID": 6, + "QuantityPerUnit": "20 - 1 kg tins", + "UnitPrice": 39, + "UnitsInStock": 0, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": true, + "OrderDate": "2015-08-17", + "Rating": 2, + "Locations": [ + { + "Shop": "Farmer Market", + "LastInventory": "2018-04-04" + } + ] + }, + { + "ProductID": 18, + "ProductName": "Carnarvon Tigers", + "SupplierID": 7, + "CategoryID": 8, + "QuantityPerUnit": "16 kg pkg.", + "UnitPrice": 62.5, + "UnitsInStock": 42, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2005-09-27", + "Rating": 2, + "Locations": [ + { + "Shop": "24/7 Market", + "LastInventory": "2018-11-11" + }, + { + "Shop": "Super Market", + "LastInventory": "2018-09-09" + } + ] + }, + { + "ProductID": 19, + "ProductName": "Teatime Chocolate Biscuits", + "SupplierID": 8, + "CategoryID": 3, + "QuantityPerUnit": "", + "UnitPrice": 9.2, + "UnitsInStock": 25, + "UnitsOnOrder": 30, + "ReorderLevel": 5, + "Discontinued": false, + "OrderDate": "2001-03-17", + "Rating": 2, + "Locations": [ + { + "Shop": "Local Market", + "LastInventory": "2018-07-03" + } + ] + }, + { + "ProductID": 20, + "ProductName": "Sir Rodneys Marmalade", + "SupplierID": 8, + "CategoryID": 3, + "QuantityPerUnit": "4 - 100 ml jars", + "UnitPrice": 4.5, + "UnitsInStock": 40, + "UnitsOnOrder": 30, + "ReorderLevel": 0, + "Discontinued": false, + "OrderDate": "2005-03-17", + "Rating": 5, + "Locations": [ + { + "Shop": "Super Market", + "LastInventory": "2018-09-09" + } + ] + } +] \ No newline at end of file diff --git a/samples/grids/grid/grid-batch-editing/src/index.css b/samples/grids/grid/grid-batch-editing/src/index.css new file mode 100644 index 0000000000..94f5e82799 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/src/index.css @@ -0,0 +1,39 @@ +/* shared styles are loaded from: */ +/* https://dl.infragistics.com/x/css/samples/shared.v8.css */ + +#grid { + --ig-size: var(--ig-size-medium); +} + +.buttons-wrapper { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 10px 0; +} + +.buttons-right { + display: flex; + gap: 8px; +} + +.dialog-buttons { + display: flex; + gap: 8px; + justify-content: flex-end; +} + +.transaction--add { + color: #6b3; + font-weight: 600; +} + +.transaction--update { + color: #4a71b9; + font-weight: 600; +} + +.transaction--delete { + color: #ee4920; + font-weight: 600; +} diff --git a/samples/grids/grid/grid-batch-editing/src/index.ts b/samples/grids/grid/grid-batch-editing/src/index.ts new file mode 100644 index 0000000000..f1631812d0 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/src/index.ts @@ -0,0 +1,142 @@ +import 'igniteui-webcomponents-grids/grids/combined'; +import { IgcGridComponent, IgcColumnComponent } from 'igniteui-webcomponents-grids/grids'; +import NwindData from './NwindData.json'; +import { IgcCellTemplateContext } from 'igniteui-webcomponents-grids/grids'; +import { html } from 'lit-html'; + +import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css"; +import 'igniteui-webcomponents/themes/light/bootstrap.css'; +import { defineAllComponents, IgcButtonComponent, IgcDialogComponent } from 'igniteui-webcomponents'; +defineAllComponents(); + +import "./index.css"; + +export class GridBatchEditingSample { + + private grid: IgcGridComponent; + private deleteRowColumn: IgcColumnComponent; + private addRowBtn: IgcButtonComponent; + private undoBtn: IgcButtonComponent; + private redoBtn: IgcButtonComponent; + private commitBtn: IgcButtonComponent; + private discardBtn: IgcButtonComponent; + private dialog: IgcDialogComponent; + private transactionGrid: IgcGridComponent; + private typeColumn: IgcColumnComponent; + private valueColumn: IgcColumnComponent; + private addProductId: number = 1000; + + constructor() { + this.grid = document.getElementById('grid') as IgcGridComponent; + this.deleteRowColumn = document.getElementById('actionsColumn') as IgcColumnComponent; + this.addRowBtn = document.getElementById('addRowBtn') as IgcButtonComponent; + this.undoBtn = document.getElementById('undoBtn') as IgcButtonComponent; + this.redoBtn = document.getElementById('redoBtn') as IgcButtonComponent; + this.commitBtn = document.getElementById('commitBtn') as IgcButtonComponent; + this.discardBtn = document.getElementById('discardBtn') as IgcButtonComponent; + this.dialog = document.getElementById('dialog') as IgcDialogComponent; + this.transactionGrid = document.getElementById('transactionGrid') as IgcGridComponent; + this.typeColumn = document.getElementById('typeColumn') as IgcColumnComponent; + this.valueColumn = document.getElementById('valueColumn') as IgcColumnComponent; + + this.grid.batchEditing = true; + this.grid.data = this.nwindData; + this.deleteRowColumn.bodyTemplate = this.deleteRowColumnTemplate; + this.typeColumn.bodyTemplate = this.typeColumnTemplate; + this.valueColumn.bodyTemplate = this.valueColumnTemplate; + + this.addRowBtn.addEventListener('click', this.onAddRowClick); + this.undoBtn.addEventListener('click', this.onUndoClick); + this.redoBtn.addEventListener('click', this.onRedoClick); + this.commitBtn.addEventListener('click', this.onOpenCommitDialog); + this.discardBtn.addEventListener('click', this.onDiscardClick); + + document.getElementById('dialogCommitBtn')!.addEventListener('click', this.onCommitClick); + document.getElementById('dialogDiscardBtn')!.addEventListener('click', this.onDiscardClick); + document.getElementById('dialogCancelBtn')!.addEventListener('click', this.onCancelClick); + + this.grid.transactions.onStateUpdate.subscribe(() => { + this.undoBtn.disabled = !this.grid.transactions.canUndo; + this.redoBtn.disabled = !this.grid.transactions.canRedo; + const hasChanges = this.grid.transactions.getAggregatedChanges(false).length > 0; + this.commitBtn.disabled = !hasChanges; + this.discardBtn.disabled = !hasChanges; + }); + } + + private _nwindData: any[] = NwindData; + public get nwindData(): any[] { + return this._nwindData; + } + + public deleteRowColumnTemplate = (ctx: IgcCellTemplateContext) => { + return html` this.onDeleteRowClick(ctx.cell.id.rowID)}>Delete`; + } + + public typeColumnTemplate = (ctx: IgcCellTemplateContext) => { + const type = ctx.cell.value as string; + return html`${type.toUpperCase()}`; + } + + public valueColumnTemplate = (ctx: IgcCellTemplateContext) => { + return html`${JSON.stringify(ctx.cell.value)}`; + } + + public onAddRowClick = () => { + this.grid.addRow({ + CategoryID: this.randomInt(1, 10), + Discontinued: this.randomInt(1, 10) % 2 === 0, + OrderDate: new Date(this.randomInt(2000, 2050), + this.randomInt(0, 11), this.randomInt(1, 25)) + .toISOString().slice(0, 10), + ProductID: this.addProductId++, + ProductName: 'Product with index ' + this.randomInt(0, 20), + QuantityPerUnit: (this.randomInt(1, 10) * 10).toString() + ' pcs.', + ReorderLevel: this.randomInt(10, 20), + SupplierID: this.randomInt(1, 20), + UnitPrice: this.randomInt(10, 1000), + UnitsInStock: this.randomInt(1, 100), + UnitsOnOrder: this.randomInt(1, 20) + }); + } + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + public onUndoClick = () => { + this.grid.endEdit(true); + this.grid.transactions.undo(); + } + + public onRedoClick = () => { + this.grid.endEdit(true); + this.grid.transactions.redo(); + } + + public onOpenCommitDialog = () => { + this.transactionGrid.data = this.grid.transactions.getAggregatedChanges(true); + this.dialog.show(); + } + + public onCommitClick = () => { + this.grid.transactions.commit(this.grid.data); + this.dialog.hide(); + } + + public onDiscardClick = () => { + this.grid.transactions.clear(); + this.dialog.hide(); + } + + public onCancelClick = () => { + this.dialog.hide(); + } + + public onDeleteRowClick = (rowId: any) => { + this.grid.deleteRow(rowId); + } + +} + +new GridBatchEditingSample(); diff --git a/samples/grids/grid/grid-batch-editing/tsconfig.json b/samples/grids/grid/grid-batch-editing/tsconfig.json new file mode 100644 index 0000000000..e7c370def4 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/tsconfig.json @@ -0,0 +1,41 @@ +{ + "compilerOptions": { + "noImplicitReturns": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "noImplicitAny": true, + "declarationDir": "dist/types", + "moduleResolution": "node", + "declaration": true, + "target": "es2015", + "module": "es2015", + "strict": true, + "strictNullChecks": false, + "baseUrl": ".", + "paths": { + "igniteui-webcomponents-core": [ "node_modules/igniteui-webcomponents-core", "node_modules/@infragistics/igniteui-webcomponents-core" ], + "igniteui-webcomponents-charts": [ "node_modules/igniteui-webcomponents-charts", "node_modules/@infragistics/igniteui-webcomponents-charts" ], + "igniteui-webcomponents-gauges": [ "node_modules/igniteui-webcomponents-gauges", "node_modules/@infragistics/igniteui-webcomponents-gauges" ], + "igniteui-webcomponents-datasources": [ "node_modules/igniteui-webcomponents-datasources", "node_modules/@infragistics/igniteui-webcomponents-datasources" ], + "igniteui-webcomponents-excel": [ "node_modules/igniteui-webcomponents-excel", "node_modules/@infragistics/igniteui-webcomponents-excel" ], + "igniteui-webcomponents-inputs": [ "node_modules/igniteui-webcomponents-inputs", "node_modules/@infragistics/igniteui-webcomponents-inputs" ], + "igniteui-webcomponents-grids": [ "node_modules/igniteui-webcomponents-grids", "node_modules/@infragistics/igniteui-webcomponents-grids" ], + "igniteui-webcomponents-maps": [ "node_modules/igniteui-webcomponents-maps", "node_modules/@infragistics/igniteui-webcomponents-maps" ], + "igniteui-webcomponents-spreadsheet": [ "node_modules/igniteui-webcomponents-spreadsheet", "node_modules/@infragistics/igniteui-webcomponents-spreadsheet" ], + "igniteui-webcomponents-spreadsheet-chart-adapter": [ "node_modules/igniteui-webcomponents-spreadsheet-chart-adapter", "node_modules/@infragistics/igniteui-webcomponents-spreadsheet-chart-adapter" ], + "igniteui-webcomponents-grids/*": [ "node_modules/igniteui-webcomponents-grids/*", "node_modules/@infragistics/igniteui-webcomponents-grids/*" ], + "igniteui-webcomponents-grids/grids": [ "node_modules/igniteui-webcomponents-grids/grids", "node_modules/@infragistics/igniteui-webcomponents-grids/grids" ], + "igniteui-webcomponents-grids/grids/*": [ "node_modules/igniteui-webcomponents-grids/grids/*", "node_modules/@infragistics/igniteui-webcomponents-grids/grids/*" ], + "igniteui-webcomponents-grids/grids/combined": [ "node_modules/igniteui-webcomponents-grids/grids/combined", "node_modules/@infragistics/igniteui-webcomponents-grids/grids/combined" ], + "igniteui-webcomponents-layouts": [ "node_modules/igniteui-webcomponents-layouts", "node_modules/@infragistics/igniteui-webcomponents-layouts" ], + "igniteui-webcomponents-dashboards": [ "node_modules/igniteui-webcomponents-dashboards", "node_modules/@infragistics/igniteui-webcomponents-dashboards" ] + } + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/samples/grids/grid/grid-batch-editing/tslint.json b/samples/grids/grid/grid-batch-editing/tslint.json new file mode 100644 index 0000000000..e3b56e93a1 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/tslint.json @@ -0,0 +1,54 @@ +{ + "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], + "linterOptions": { + "exclude": [ + "node_modules/**/*.ts", + "**/odatajs-4.0.0.js", + "src/images/*.*" + ] + }, + "rules": { + "curly": [false, "ignore-same-line"], + "jsx-no-lambda": false, + "jsx-self-close": false, + "jsx-wrap-multiline": false, + "max-classes-per-file": [true, 10], + "member-ordering": false, + "no-console": false, + "no-string-literal": false, + "no-unused-vars": false, + "no-useless-constructor": false, + "no-trailing-whitespace": false, + "no-var": false, + "no-var-requires": false, + "no-var-keyword": false, + "ordered-imports": false, + "object-literal-sort-keys": false, + "object-literal-shorthand": false, + "only-arrow-functions": false, + "prefer-const": false, + "prefer-for-of": false, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/type-annotation-spacing": "off" + }, + "jsRules": { + "curly": [false, "ignore-same-line"], + "jsx-no-lambda": false, + "jsx-self-close": false, + "jsx-wrap-multiline": false, + "max-classes-per-file": [true, 10], + "no-console": false, + "no-unused-vars": false, + "no-useless-constructor": false, + "no-var-requires": false, + "object-literal-sort-keys": false, + "object-literal-shorthand": false, + "only-arrow-functions": false, + "ordered-imports": false, + "prefer-const": false, + "prefer-for-of": false, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-useless-constructor": "off" + } + } \ No newline at end of file diff --git a/samples/grids/grid/grid-batch-editing/webpack.config.js b/samples/grids/grid/grid-batch-editing/webpack.config.js new file mode 100644 index 0000000000..c5c6b9f7e6 --- /dev/null +++ b/samples/grids/grid/grid-batch-editing/webpack.config.js @@ -0,0 +1,105 @@ +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const path = require('path'); +const webpack = require('webpack'); + +module.exports = env => { + const nodeEnv = process.env.NODE_ENV || 'development'; + const isProd = nodeEnv === 'production'; + const isLegacy = !!process.env.legacy && !(process.env.legacy == "false"); + console.log(">> webpack nodeEnv=" + nodeEnv); + console.log(">> webpack isProd=" + isProd); + console.log(">> webpack isLegacy=" + isLegacy); + const presets = [ + ["@babel/preset-env", { + "useBuiltIns": "usage", + "corejs": 3, + "targets": { + "browsers": isLegacy ? ["defaults"] : [ + "last 2 Chrome versions", + "last 2 Safari versions", + "last 2 iOS versions", + "last 2 Firefox versions", + "last 2 Edge versions"] + } + }], + "@babel/preset-typescript" + ]; + + return { + entry: isLegacy ? [ + path.resolve(__dirname, 'src') + ] : path.resolve(__dirname, 'src'), + devtool: isProd ? false : 'source-map', + output: { + filename: isProd ? '[fullhash].bundle.js' : '[fullhash].bundle.js', + globalObject: 'this', + path: path.resolve(__dirname, 'dist'), + }, + + resolve: { + mainFields: ['esm2015', 'module', 'main'], + extensions: ['.ts', '.js', '.json'], + plugins: [new TsconfigPathsPlugin({ + configFile: './tsconfig.json', + extensions: ['.ts', '.js'], + mainFields: ['esm2015', 'module', 'main'] + })] + }, + + module: { + rules: [ + { test: /\.(png|svg|jpg|gif)$/, use: ['file-loader'] }, + { test: /\.(csv|tsv)$/, use: ['csv-loader'] }, + { test: /\.xml$/, use: ['xml-loader'] }, + { test: /\.css$/, sideEffects: true, use: ['style-loader', 'css-loader'] }, + { + test: /worker\.(ts|js)$/, + use: [ + { loader: 'worker-loader' }, + { + loader: 'babel-loader', options: { + "compact": isProd ? true : false, + "presets": presets, + "plugins": [ + "@babel/plugin-transform-class-static-block", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-runtime" + ] + } + } + ] + }, + { + test: /\.(ts|js)$/, loader: 'babel-loader', + options: { + "compact": isProd ? true : false, + "presets": presets, + "plugins": [ + "@babel/plugin-transform-class-static-block", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-runtime" + ] + }, + exclude: + function (modulePath) { + return /node_modules/.test(modulePath) && + !/igniteui-webcomponents/.test(modulePath) && + !/lit-html/.test(modulePath); + } + }], + }, + + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(nodeEnv) + }), + new HtmlWebpackPlugin({ + title: 'Grid Batch Editing', + template: 'index.html' + }), + new ForkTsCheckerWebpackPlugin() + ] + }; +}; diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/.prettierrc b/samples/grids/hierarchical-grid/grid-batch-editing/.prettierrc new file mode 100644 index 0000000000..15a7c7c6cf --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/.prettierrc @@ -0,0 +1,11 @@ +{ + "printWidth": 250, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "none", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "fluid": false +} \ No newline at end of file diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/ReadMe.md b/samples/grids/hierarchical-grid/grid-batch-editing/ReadMe.md new file mode 100644 index 0000000000..b47226cc7d --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of Web Components application with example of Batch Editing feature using [Hierarchical Grid](https://infragistics.com/webcomponentssite/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-angular-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-angular-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +To set up this project locally, execute these commands: + +``` +git clone https://github.com/IgniteUI/igniteui-wc-examples.git +git checkout master +cd ./igniteui-wc-examples +cd ./samples/grids/hierarchical-grid/grid-batch-editing +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: + +``` +npm install +npm run start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for Web Components**, check out the [Web Components documentation](https://infragistics.com/webcomponentssite/components/general-getting-started.html). diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/index.html b/samples/grids/hierarchical-grid/grid-batch-editing/index.html new file mode 100644 index 0000000000..2b3dee345b --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/index.html @@ -0,0 +1,191 @@ + + + + Hierarchical Grid Batch Editing | Ignite UI | Web Components | infragistics + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ Add Row +
+ Undo + Redo + Discard + Commit +
+
+ + + + + + + +
+ Commit + Discard + Cancel +
+
+
+
+ + + <% if (false) { %><% } %> + + diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/package.json b/samples/grids/hierarchical-grid/grid-batch-editing/package.json new file mode 100644 index 0000000000..33206ac0b7 --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/package.json @@ -0,0 +1,61 @@ +{ + "name": "example-ignite-ui-web-components", + "description": "This project provides example of using Ignite UI for Web Components", + "author": "Infragistics", + "version": "1.0.0", + "license": "", + "private": true, + "homepage": ".", + "main": "src/index.ts", + "scripts": { + "build": "npm run build:prod", + "build:dev": "webpack --mode development --config ./webpack.config.js --progress --color --display-error-details", + "build:prod": "webpack --env.NODE_ENV=production --mode production --config ./webpack.config.js --progress --color --display-error-details --bail", + "serve:dev": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --config ./webpack.config.js --hot --progress --open", + "serve:prod": "webpack-dev-server --env.NODE_ENV=production --mode production --config ./webpack.config.js --port 3000 --host 0.0.0.0 --hot --progress --open --content-base dist/", + "start": "npm run serve:dev", + "build:legacy": "npm run build:prod:legacy", + "build:dev:legacy": "webpack --env.legacy=true --mode development --config ./webpack.config.js --progress --color --display-error-details", + "build:prod:legacy": "webpack --env.NODE_ENV=production --env.legacy=true --mode production --config ./webpack.config.js --progress --color --display-error-details --bail", + "serve:dev:legacy": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --env.legacy=true --mode development --config ./webpack.config.js --hot --progress --open", + "serve:prod:legacy": "webpack-dev-server --env.NODE_ENV=production --env.legacy=true --mode production --config ./webpack.config.js --port 3000 --host 0.0.0.0 --hot --progress --open --content-base dist/", + "start:legacy": "npm run serve:dev:legacy" + }, + "dependencies": { + "babel-runtime": "^6.26.0", + "igniteui-webcomponents": "^6.5.1", + "igniteui-webcomponents-core": "6.3.1", + "igniteui-webcomponents-grids": "6.3.0-alpha.1", + "igniteui-webcomponents-inputs": "6.3.1", + "igniteui-webcomponents-layouts": "6.3.1", + "lit-html": "^3.3.1", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@babel/cli": "^7.28.3", + "@babel/core": "^7.28.4", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-runtime": "^7.28.3", + "@babel/preset-env": "^7.28.3", + "@babel/preset-typescript": "^7.27.1", + "@types/source-map": "^0.5.7", + "babel-loader": "^10.0.0", + "babel-plugin-transform-custom-element-classes": "^0.1.0", + "css-loader": "^7.1.2", + "csv-loader": "^3.0.5", + "file-loader": "^6.2.0", + "fork-ts-checker-webpack-plugin": "^9.1.0", + "html-webpack-plugin": "^5.6.4", + "parcel-bundler": "^1.12.5", + "source-map": "^0.7.6", + "style-loader": "^4.0.0", + "tsconfig-paths-webpack-plugin": "^4.2.0", + "typescript": "^5.9.2", + "webpack": "^5.101.3", + "webpack-cli": "^6.0.1", + "webpack-dev-server": "^5.2.2", + "worker-loader": "^3.0.8", + "xml-loader": "^1.2.1" + } +} diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/sandbox.config.json b/samples/grids/hierarchical-grid/grid-batch-editing/sandbox.config.json new file mode 100644 index 0000000000..52c7875103 --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/sandbox.config.json @@ -0,0 +1,6 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser", + "template": "parcel" +} \ No newline at end of file diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/src/SingersData.json b/samples/grids/hierarchical-grid/grid-batch-editing/src/SingersData.json new file mode 100644 index 0000000000..b0c61e1499 --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/src/SingersData.json @@ -0,0 +1,2480 @@ +[ + { + "ID": 0, + "Artist": "Naomí Yepes", + "Photo": "https://dl.infragistics.com/x/img/people/names/naomi.png", + "Debut": 2011, + "GrammyNominations": 6, + "GrammyAwards": 0, + "HasGrammyAward": false, + "Tours": [ + { + "Tour": "Faithful Tour", + "StartedOn": "Sep 12", + "Location": "Worldwide", + "Headliner": "NO", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "City Jam Sessions", + "StartedOn": "Aug 13", + "Location": "North America", + "Headliner": "YES", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "Christmas NYC 2013", + "StartedOn": "Dec 13", + "Location": "United States", + "Headliner": "NO", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "Christmas NYC 2014", + "StartedOn": "Dec 14", + "Location": "North America", + "Headliner": "NO", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "Watermelon Tour", + "StartedOn": "Feb 15", + "Location": "Worldwide", + "Headliner": "YES", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "Christmas NYC 2016", + "StartedOn": "Dec 16", + "Location": "United States", + "Headliner": "NO", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "The Dragon Tour", + "StartedOn": "Feb 17", + "Location": "Worldwide", + "Headliner": "NO", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "Organic Sessions", + "StartedOn": "Aug 18", + "Location": "United States, England", + "Headliner": "YES", + "TouredBy": "Naomí Yepes" + }, + { + "Tour": "Hope World Tour", + "StartedOn": "Mar 19", + "Location": "Worldwide", + "Headliner": "NO", + "TouredBy": "Naomí Yepes" + } + ], + "Albums": [ + { + "Album": "Initiation", + "LaunchDate": "2013-09-03", + "BillboardReview": 86, + "USBillboard200": 1, + "Artist": "Naomí Yepes", + "Songs": [ + { + "Number": 1, + "Title": "Lonely Falling", + "Released": "2019-05-01", + "Genre": "*", + "Album": "Initiation" + }, + { + "Number": 2, + "Title": "Bright Breaking", + "Released": "2019-07-25", + "Genre": "Electro house Electropop", + "Album": "Initiation" + }, + { + "Number": 3, + "Title": "River of Whisper", + "Released": "2020-01-29", + "Genre": "Electro house Electropop", + "Album": "Initiation" + }, + { + "Number": 4, + "Title": "Sky of Storm", + "Released": "2019-05-07", + "Genre": "Electro house Electropop", + "Album": "Initiation" + }, + { + "Number": 5, + "Title": "Electric River", + "Released": "2020-01-20", + "Genre": "R&B", + "Album": "Initiation" + }, + { + "Number": 6, + "Title": "Storm of Storm", + "Released": "2019-09-01", + "Genre": "Crunk reggaeton", + "Album": "Initiation" + }, + { + "Number": 7, + "Title": "Fire of Dream", + "Released": "2019-09-12", + "Genre": "Electro house Electropop", + "Album": "Initiation" + }, + { + "Number": 8, + "Title": "Burning in the Light", + "Released": "2019-04-15", + "Genre": "*", + "Album": "Initiation" + }, + { + "Number": 9, + "Title": "Burning in the Storm", + "Released": "2019-09-10", + "Genre": "Electro house Electropop", + "Album": "Initiation" + }, + { + "Number": 10, + "Title": "Shadow of Whisper", + "Released": "2019-01-06", + "Genre": "Crunk reggaeton", + "Album": "Initiation" + } + ] + }, + { + "Album": "Dream Driven", + "LaunchDate": "2014-08-25", + "BillboardReview": 81, + "USBillboard200": 1, + "Artist": "Naomí Yepes", + "Songs": [ + { + "Number": 1, + "Title": "Intro", + "Released": "2019-09-10", + "Genre": "*", + "Album": "Dream Driven" + }, + { + "Number": 2, + "Title": "Ferocious", + "Released": "2014-04-28", + "Genre": "Dance-pop R&B", + "Album": "Dream Driven" + }, + { + "Number": 3, + "Title": "Going crazy", + "Released": "2015-02-10", + "Genre": "Dance-pop EDM", + "Album": "Dream Driven" + }, + { + "Number": 4, + "Title": "Future past", + "Released": "2011-09-20", + "Genre": "*", + "Album": "Dream Driven" + }, + { + "Number": 5, + "Title": "Roaming like them", + "Released": "2014-07-02", + "Genre": "Electro house Electropop", + "Album": "Dream Driven" + }, + { + "Number": 6, + "Title": "Last Wishes", + "Released": "2014-08-12", + "Genre": "R&B", + "Album": "Dream Driven" + }, + { + "Number": 7, + "Title": "Stay where you are", + "Released": "2013-09-14", + "Genre": "*", + "Album": "Dream Driven" + }, + { + "Number": 8, + "Title": "Imaginarium", + "Released": "2021-09-20", + "Genre": "*", + "Album": "Dream Driven" + }, + { + "Number": 9, + "Title": "Tell me", + "Released": "2014-09-30", + "Genre": "Synth-pop R&B", + "Album": "Dream Driven" + }, + { + "Number": 10, + "Title": "Shredded into pieces", + "Released": "2015-09-11", + "Genre": "*", + "Album": "Dream Driven" + }, + { + "Number": 11, + "Title": "Capture this moment", + "Released": "2016-09-13", + "Genre": "*", + "Album": "Dream Driven" + }, + { + "Number": 12, + "Title": "Dream Driven", + "Released": "2014-09-14", + "Genre": "*", + "Album": "Dream Driven" + } + ] + }, + { + "Album": "The dragon journey", + "LaunchDate": "2016-05-20", + "BillboardReview": 60, + "USBillboard200": 2, + "Artist": "Naomí Yepes", + "Songs": [ + { + "Number": 1, + "Title": "Calling in the Storm", + "Released": "2019-03-12", + "Genre": "Electro house Electropop", + "Album": "The dragon journey" + }, + { + "Number": 2, + "Title": "Hiding in the Dream", + "Released": "2019-03-23", + "Genre": "R&B", + "Album": "The dragon journey" + }, + { + "Number": 3, + "Title": "Electric Heart", + "Released": "2019-03-17", + "Genre": "ethno-tunes", + "Album": "The dragon journey" + }, + { + "Number": 4, + "Title": "Shadow of Echo", + "Released": "2019-02-20", + "Genre": "ethno-tunes", + "Album": "The dragon journey" + }, + { + "Number": 5, + "Title": "Flying in the Storm", + "Released": "2019-04-08", + "Genre": "R&B", + "Album": "The dragon journey" + }, + { + "Number": 6, + "Title": "Dark Waiting", + "Released": "2019-10-20", + "Genre": "Synth-pop R&B", + "Album": "The dragon journey" + }, + { + "Number": 7, + "Title": "Fire of River", + "Released": "2019-02-20", + "Genre": "Synth-pop R&B", + "Album": "The dragon journey" + }, + { + "Number": 8, + "Title": "Wild Crying", + "Released": "2019-06-14", + "Genre": "R&B", + "Album": "The dragon journey" + }, + { + "Number": 9, + "Title": "Bright Dancing", + "Released": "2019-03-14", + "Genre": "Electro house Electropop", + "Album": "The dragon journey" + }, + { + "Number": 10, + "Title": "Golden Waiting", + "Released": "2019-09-12", + "Genre": "Synth-pop R&B", + "Album": "The dragon journey" + } + ] + }, + { + "Album": "Organic me", + "LaunchDate": "2018-08-17", + "BillboardReview": 82, + "USBillboard200": 1, + "Artist": "Naomí Yepes", + "Songs": [ + { + "Number": 1, + "Title": "I Love", + "Released": "2019-05-11", + "Genre": "Crunk reggaeton", + "Album": "Organic me" + }, + { + "Number": 2, + "Title": "Early Morning Compass", + "Released": "2020-01-15", + "Genre": "mystical parody-bap ", + "Album": "Organic me" + }, + { + "Number": 3, + "Title": "Key Fields Forever", + "Released": "2020-01-02", + "Genre": "Dance-pop EDM", + "Album": "Organic me" + }, + { + "Number": 4, + "Title": "Stand by Your Goblins", + "Released": "2019-11-20", + "Genre": "*", + "Album": "Organic me" + }, + { + "Number": 5, + "Title": "Mad to Walk", + "Released": "2019-05-12", + "Genre": "Electro house Electropop", + "Album": "Organic me" + }, + { + "Number": 6, + "Title": "Alice's Waiting", + "Released": "2020-01-28", + "Genre": "R&B", + "Album": "Organic me" + }, + { + "Number": 7, + "Title": "We Shall Kiss", + "Released": "2019-10-30", + "Genre": "*", + "Album": "Organic me" + }, + { + "Number": 8, + "Title": "Behind Single Ants", + "Released": "2019-10-02", + "Genre": "*", + "Album": "Organic me" + }, + { + "Number": 9, + "Title": "Soap Autopsy", + "Released": "2019-08-08", + "Genre": "Synth-pop R&B", + "Album": "Organic me" + }, + { + "Number": 10, + "Title": "Have You Met Rich?", + "Released": "2019-07-01", + "Genre": "ethno-tunes", + "Album": "Organic me" + }, + { + "Number": 11, + "Title": "Livin' on a Banana", + "Released": "2019-11-22", + "Genre": "Crunk reggaeton", + "Album": "Organic me" + } + ] + }, + { + "Album": "Curiosity", + "LaunchDate": "2019-12-07", + "BillboardReview": 75, + "USBillboard200": 12, + "Artist": "Naomí Yepes", + "Songs": [ + { + "Number": 1, + "Title": "Storm of Dream", + "Released": "2019-01-05", + "Genre": "*", + "Album": "Curiosity" + }, + { + "Number": 2, + "Title": "Echo of Dream", + "Released": "2019-01-28", + "Genre": "Synth-pop R&B", + "Album": "Curiosity" + }, + { + "Number": 3, + "Title": "Light of Shadow", + "Released": "2019-02-07", + "Genre": "Synth-pop R&B", + "Album": "Curiosity" + }, + { + "Number": 4, + "Title": "Storm of Heart", + "Released": "2020-01-05", + "Genre": "Electro house Electropop", + "Album": "Curiosity" + }, + { + "Number": 5, + "Title": "Shadow of River", + "Released": "2019-02-27", + "Genre": "*", + "Album": "Curiosity" + }, + { + "Number": 6, + "Title": "Wicked Dancing", + "Released": "2020-01-17", + "Genre": "ethno-tunes", + "Album": "Curiosity" + }, + { + "Number": 7, + "Title": "River of Light", + "Released": "2019-02-22", + "Genre": "R&B", + "Album": "Curiosity" + }, + { + "Number": 8, + "Title": "Lonely Breaking", + "Released": "2019-09-09", + "Genre": "ethno-tunes", + "Album": "Curiosity" + }, + { + "Number": 9, + "Title": "Furious Flying", + "Released": "2019-06-08", + "Genre": "R&B", + "Album": "Curiosity" + }, + { + "Number": 10, + "Title": "Hiding in the Storm", + "Released": "2019-05-27", + "Genre": "Electro house Electropop", + "Album": "Curiosity" + } + ] + } + ] + }, + { + "ID": 1, + "Artist": "Babila Ebwélé", + "Photo": "https://dl.infragistics.com/x/img/people/names/babila.png", + "Debut": 2009, + "GrammyNominations": 0, + "GrammyAwards": 11, + "HasGrammyAward": true, + "Tours": [ + { + "Tour": "The last straw", + "StartedOn": "May 09", + "Location": "Europe, Asia", + "Headliner": "NO", + "TouredBy": "Babila Ebwélé" + }, + { + "Tour": "No foundations", + "StartedOn": "Jun 04", + "Location": "United States, Europe", + "Headliner": "YES", + "TouredBy": "Babila Ebwélé" + }, + { + "Tour": "Crazy eyes", + "StartedOn": "Jun 08", + "Location": "North America", + "Headliner": "NO", + "TouredBy": "Babila Ebwélé" + }, + { + "Tour": "Zero gravity", + "StartedOn": "Apr 19", + "Location": "United States", + "Headliner": "NO", + "TouredBy": "Babila Ebwélé" + }, + { + "Tour": "Battle with myself", + "StartedOn": "Mar 08", + "Location": "North America", + "Headliner": "YES", + "TouredBy": "Babila Ebwélé" + } + ], + "Albums": [ + { + "Album": "Pushing up daisies", + "LaunchDate": "2000-05-31", + "BillboardReview": 86, + "USBillboard200": 42, + "Artist": "Babila Ebwélé", + "Songs": [ + { + "Number": 1, + "Title": "Wood Shavings Forever", + "Released": "2019-06-09", + "Genre": "*", + "Album": "Pushing up daisies" + }, + { + "Number": 2, + "Title": "Early Morning Drive", + "Released": "2019-05-20", + "Genre": "*", + "Album": "Pushing up daisies" + }, + { + "Number": 3, + "Title": "Don't Natter", + "Released": "2019-06-10", + "Genre": "adult calypso-industrial", + "Album": "Pushing up daisies" + }, + { + "Number": 4, + "Title": "Stairway to Balloons", + "Released": "2019-06-18", + "Genre": "calypso and mariachi", + "Album": "Pushing up daisies" + }, + { + "Number": 5, + "Title": "The Number of your Apple", + "Released": "2019-10-29", + "Genre": "*", + "Album": "Pushing up daisies" + }, + { + "Number": 6, + "Title": "Your Delightful Heart", + "Released": "2019-02-24", + "Genre": "*", + "Album": "Pushing up daisies" + }, + { + "Number": 7, + "Title": "Nice Weather For Balloons", + "Released": "2019-08-01", + "Genre": "rap-hop", + "Album": "Pushing up daisies" + }, + { + "Number": 8, + "Title": "The Girl From Cornwall", + "Released": "2019-05-04", + "Genre": "enigmatic rock-and-roll", + "Album": "Pushing up daisies" + }, + { + "Number": 9, + "Title": "Here Without Jack", + "Released": "2019-10-24", + "Genre": "*", + "Album": "Pushing up daisies" + }, + { + "Number": 10, + "Title": "Born Rancid", + "Released": "2019-03-19", + "Genre": "*", + "Album": "Pushing up daisies" + } + ] + }, + { + "Album": "Death's dead", + "LaunchDate": "2016-06-08", + "BillboardReview": 85, + "USBillboard200": 95, + "Artist": "Babila Ebwélé", + "Songs": [ + { + "Number": 1, + "Title": "Men Sound Better With You", + "Released": "2019-10-20", + "Genre": "rap-hop", + "Album": "Death's dead" + }, + { + "Number": 2, + "Title": "Ghost in My Rod", + "Released": "2019-10-05", + "Genre": "enigmatic rock-and-roll", + "Album": "Death's dead" + }, + { + "Number": 3, + "Title": "Bed of Men", + "Released": "2019-11-14", + "Genre": "whimsical comedy-grass ", + "Album": "Death's dead" + }, + { + "Number": 4, + "Title": "Don't Push", + "Released": "2020-01-02", + "Genre": "unblack electronic-trip-hop", + "Album": "Death's dead" + }, + { + "Number": 5, + "Title": "Nice Weather For Men", + "Released": "2019-12-18", + "Genre": "*", + "Album": "Death's dead" + }, + { + "Number": 6, + "Title": "Rancid Rhapsody", + "Released": "2019-03-10", + "Genre": "*", + "Album": "Death's dead" + }, + { + "Number": 7, + "Title": "Push, Push, Push!", + "Released": "2019-02-21", + "Genre": "*", + "Album": "Death's dead" + }, + { + "Number": 8, + "Title": "My Name is Sarah", + "Released": "2019-11-15", + "Genre": "*", + "Album": "Death's dead" + }, + { + "Number": 9, + "Title": "The Girl From My Hotel", + "Released": "2019-11-06", + "Genre": "*", + "Album": "Death's dead" + }, + { + "Number": 10, + "Title": "Free Box", + "Released": "2019-04-18", + "Genre": "splitter-funk", + "Album": "Death's dead" + }, + { + "Number": 11, + "Title": "Hotel Cardiff", + "Released": "2019-12-30", + "Genre": "guilty pleasure ebm", + "Album": "Death's dead" + } + ] + } + ] + }, + { + "ID": 2, + "Artist": "Ahmad Nazeri", + "Photo": "https://dl.infragistics.com/x/img/people/names/ahmad.png", + "Debut": 2004, + "GrammyNominations": 3, + "GrammyAwards": 1, + "HasGrammyAward": true, + "Tours": [], + "Albums": [ + { + "Album": "Emergency", + "LaunchDate": "2004-03-06", + "BillboardReview": 98, + "USBillboard200": 69, + "Artist": "Ahmad Nazeri", + "Songs": [ + { + "Number": 1, + "Title": "Gentle Falling", + "Released": "2019-04-26", + "Genre": "Crunk reggaeton", + "Album": "Emergency" + }, + { + "Number": 2, + "Title": "Calling in the Fire", + "Released": "2019-09-03", + "Genre": "ethno-tunes", + "Album": "Emergency" + }, + { + "Number": 3, + "Title": "Fire of Shadow", + "Released": "2019-01-05", + "Genre": "ethno-tunes", + "Album": "Emergency" + }, + { + "Number": 4, + "Title": "Dancing in the Dream", + "Released": "2019-04-15", + "Genre": "R&B", + "Album": "Emergency" + }, + { + "Number": 5, + "Title": "Calling in the Shadow", + "Released": "2019-10-09", + "Genre": "R&B", + "Album": "Emergency" + }, + { + "Number": 6, + "Title": "Falling in the Sky", + "Released": "2019-03-08", + "Genre": "ethno-tunes", + "Album": "Emergency" + }, + { + "Number": 7, + "Title": "Calling in the Storm", + "Released": "2019-12-05", + "Genre": "ethno-tunes", + "Album": "Emergency" + }, + { + "Number": 8, + "Title": "Falling in the River", + "Released": "2019-08-19", + "Genre": "Electro house Electropop", + "Album": "Emergency" + }, + { + "Number": 9, + "Title": "Electric Fire", + "Released": "2019-11-30", + "Genre": "Crunk reggaeton", + "Album": "Emergency" + }, + { + "Number": 10, + "Title": "Lonely River", + "Released": "2019-11-11", + "Genre": "Electro house Electropop", + "Album": "Emergency" + } + ] + }, + { + "Album": "Bursting bubbles", + "LaunchDate": "2006-04-17", + "BillboardReview": 69, + "USBillboard200": 39, + "Artist": "Ahmad Nazeri", + "Songs": [ + { + "Number": 1, + "Title": "Lonely Dream", + "Released": "2019-12-11", + "Genre": "ethno-tunes", + "Album": "Bursting bubbles" + }, + { + "Number": 2, + "Title": "Fire of River", + "Released": "2019-08-01", + "Genre": "Synth-pop R&B", + "Album": "Bursting bubbles" + }, + { + "Number": 3, + "Title": "Wicked Falling", + "Released": "2019-01-25", + "Genre": "*", + "Album": "Bursting bubbles" + }, + { + "Number": 4, + "Title": "Crying in the Shadow", + "Released": "2019-01-04", + "Genre": "Synth-pop R&B", + "Album": "Bursting bubbles" + }, + { + "Number": 5, + "Title": "Wild Burning", + "Released": "2019-05-10", + "Genre": "ethno-tunes", + "Album": "Bursting bubbles" + }, + { + "Number": 6, + "Title": "Waiting in the Heart", + "Released": "2019-08-07", + "Genre": "ethno-tunes", + "Album": "Bursting bubbles" + }, + { + "Number": 7, + "Title": "Fire of Fire", + "Released": "2019-05-16", + "Genre": "Electro house Electropop", + "Album": "Bursting bubbles" + }, + { + "Number": 8, + "Title": "Bright Heart", + "Released": "2019-03-14", + "Genre": "Synth-pop R&B", + "Album": "Bursting bubbles" + }, + { + "Number": 9, + "Title": "Lonely Fire", + "Released": "2019-10-15", + "Genre": "R&B", + "Album": "Bursting bubbles" + }, + { + "Number": 10, + "Title": "Sky of Dream", + "Released": "2019-06-20", + "Genre": "ethno-tunes", + "Album": "Bursting bubbles" + } + ] + } + ] + }, + { + "ID": 3, + "Artist": "Kimmy McIlmorie", + "Photo": "https://dl.infragistics.com/x/img/people/names/kimmy.png", + "Debut": 2007, + "GrammyNominations": 21, + "GrammyAwards": 3, + "HasGrammyAward": true, + "Tours": [], + "Albums": [ + { + "Album": "Here we go again", + "LaunchDate": "2017-11-18", + "BillboardReview": 68, + "USBillboard200": 1, + "Artist": "Kimmy McIlmorie", + "Songs": [ + { + "Number": 1, + "Title": "Storm of Sky", + "Released": "2019-03-04", + "Genre": "ethno-tunes", + "Album": "Here we go again" + }, + { + "Number": 2, + "Title": "Dream of Shadow", + "Released": "2019-01-03", + "Genre": "ethno-tunes", + "Album": "Here we go again" + }, + { + "Number": 3, + "Title": "Dream of Shadow", + "Released": "2019-12-19", + "Genre": "Electro house Electropop", + "Album": "Here we go again" + }, + { + "Number": 4, + "Title": "Golden Fire", + "Released": "2019-01-20", + "Genre": "R&B", + "Album": "Here we go again" + }, + { + "Number": 5, + "Title": "Running in the Light", + "Released": "2020-01-03", + "Genre": "Synth-pop R&B", + "Album": "Here we go again" + }, + { + "Number": 6, + "Title": "Flying in the Heart", + "Released": "2019-01-17", + "Genre": "*", + "Album": "Here we go again" + }, + { + "Number": 7, + "Title": "Fire of Storm", + "Released": "2019-01-26", + "Genre": "ethno-tunes", + "Album": "Here we go again" + }, + { + "Number": 8, + "Title": "Calling in the Sky", + "Released": "2019-10-28", + "Genre": "Synth-pop R&B", + "Album": "Here we go again" + }, + { + "Number": 9, + "Title": "Flying in the Shadow", + "Released": "2019-03-30", + "Genre": "ethno-tunes", + "Album": "Here we go again" + }, + { + "Number": 10, + "Title": "Golden Dancing", + "Released": "2019-10-12", + "Genre": "ethno-tunes", + "Album": "Here we go again" + } + ] + } + ] + }, + { + "ID": 4, + "Artist": "Mar Rueda", + "Photo": "https://dl.infragistics.com/x/img/people/names/mar.png", + "Debut": 1996, + "GrammyNominations": 14, + "GrammyAwards": 2, + "HasGrammyAward": true, + "Tours": [], + "Albums": [] + }, + { + "ID": 5, + "Artist": "Izabella Tabakova", + "Photo": "https://dl.infragistics.com/x/img/people/names/izabella.png", + "Debut": 2017, + "GrammyNominations": 7, + "GrammyAwards": 11, + "HasGrammyAward": true, + "Tours": [ + { + "Tour": "Final breath", + "StartedOn": "Jun 13", + "Location": "Europe", + "Headliner": "YES", + "TouredBy": "Izabella Tabakova" + }, + { + "Tour": "Once bitten", + "StartedOn": "Dec 18", + "Location": "Australia, United States", + "Headliner": "NO", + "TouredBy": "Izabella Tabakova" + }, + { + "Tour": "Code word", + "StartedOn": "Sep 19", + "Location": "United States, Europe", + "Headliner": "NO", + "TouredBy": "Izabella Tabakova" + }, + { + "Tour": "Final draft", + "StartedOn": "Sep 17", + "Location": "United States, Europe", + "Headliner": "YES", + "TouredBy": "Izabella Tabakova" + } + ], + "Albums": [ + { + "Album": "Once bitten", + "LaunchDate": "2007-07-16", + "BillboardReview": 79, + "USBillboard200": 53, + "Artist": "Izabella Tabakova", + "Songs": [ + { + "Number": 1, + "Title": "Whole Lotta Super Cats", + "Released": "2019-05-21", + "Genre": "*", + "Album": "Once bitten" + }, + { + "Number": 2, + "Title": "Enter Becky", + "Released": "2020-01-16", + "Genre": "*", + "Album": "Once bitten" + }, + { + "Number": 3, + "Title": "Your Cheatin' Flamingo", + "Released": "2020-01-14", + "Genre": "*", + "Album": "Once bitten" + }, + { + "Number": 4, + "Title": "Mad to Kiss", + "Released": "2019-11-06", + "Genre": "Synth-pop R&B", + "Album": "Once bitten" + }, + { + "Number": 5, + "Title": "Hotel Prague", + "Released": "2019-10-20", + "Genre": "ethno-tunes", + "Album": "Once bitten" + }, + { + "Number": 6, + "Title": "Jail on My Mind", + "Released": "2019-05-31", + "Genre": "Crunk reggaeton", + "Album": "Once bitten" + }, + { + "Number": 7, + "Title": "Amazing Blues", + "Released": "2019-05-29", + "Genre": "mystical parody-bap ", + "Album": "Once bitten" + }, + { + "Number": 8, + "Title": "Goody Two Iron Filings", + "Released": "2019-07-04", + "Genre": "Electro house Electropop", + "Album": "Once bitten" + }, + { + "Number": 9, + "Title": "I Love in Your Arms", + "Released": "2019-06-07", + "Genre": "R&B", + "Album": "Once bitten" + }, + { + "Number": 10, + "Title": "Truly Madly Amazing", + "Released": "2019-09-12", + "Genre": "ethno-tunes", + "Album": "Once bitten" + } + ] + }, + { + "Album": "Your graciousness", + "LaunchDate": "2004-11-17", + "BillboardReview": 69, + "USBillboard200": 30, + "Artist": "Izabella Tabakova", + "Songs": [ + { + "Number": 1, + "Title": "We Shall Tickle", + "Released": "2019-08-31", + "Genre": "old emo-garage ", + "Album": "Your graciousness" + }, + { + "Number": 2, + "Title": "Snail Boogie", + "Released": "2019-06-14", + "Genre": "*", + "Album": "Your graciousness" + }, + { + "Number": 3, + "Title": "Amazing Liz", + "Released": "2019-10-15", + "Genre": "*", + "Album": "Your graciousness" + }, + { + "Number": 4, + "Title": "When Sexy Aardvarks Cry", + "Released": "2019-10-01", + "Genre": "whimsical comedy-grass ", + "Album": "Your graciousness" + }, + { + "Number": 5, + "Title": "Stand By Dave", + "Released": "2019-08-18", + "Genre": "unblack electronic-trip-hop", + "Album": "Your graciousness" + }, + { + "Number": 6, + "Title": "The Golf Course is Your Land", + "Released": "2019-04-02", + "Genre": "*", + "Album": "Your graciousness" + }, + { + "Number": 7, + "Title": "Where Have All the Men Gone?", + "Released": "2019-04-29", + "Genre": "*", + "Album": "Your graciousness" + }, + { + "Number": 8, + "Title": "Rhythm of the Leg", + "Released": "2019-08-05", + "Genre": "ethno-tunes", + "Album": "Your graciousness" + }, + { + "Number": 9, + "Title": "Baby, I Need Your Hats", + "Released": "2019-12-05", + "Genre": "neuro-tunes", + "Album": "Your graciousness" + }, + { + "Number": 10, + "Title": "Stand by Your Cat", + "Released": "2019-07-25", + "Genre": "*", + "Album": "Your graciousness" + } + ] + }, + { + "Album": "Dark matters", + "LaunchDate": "2002-11-03", + "BillboardReview": 79, + "USBillboard200": 85, + "Artist": "Izabella Tabakova", + "Songs": [ + { + "Number": 1, + "Title": "Hiding in the Light", + "Released": "2019-01-24", + "Genre": "Synth-pop R&B", + "Album": "Dark matters" + }, + { + "Number": 2, + "Title": "Furious River", + "Released": "2020-01-13", + "Genre": "Electro house Electropop", + "Album": "Dark matters" + }, + { + "Number": 3, + "Title": "Wild Crying", + "Released": "2019-02-27", + "Genre": "Electro house Electropop", + "Album": "Dark matters" + }, + { + "Number": 4, + "Title": "Light of Dream", + "Released": "2019-06-01", + "Genre": "Crunk reggaeton", + "Album": "Dark matters" + }, + { + "Number": 5, + "Title": "Light of Dream", + "Released": "2019-08-24", + "Genre": "*", + "Album": "Dark matters" + }, + { + "Number": 6, + "Title": "Storm of Light", + "Released": "2019-02-26", + "Genre": "*", + "Album": "Dark matters" + }, + { + "Number": 7, + "Title": "Dark Storm", + "Released": "2020-01-18", + "Genre": "R&B", + "Album": "Dark matters" + }, + { + "Number": 8, + "Title": "Dark Calling", + "Released": "2019-03-20", + "Genre": "Crunk reggaeton", + "Album": "Dark matters" + }, + { + "Number": 9, + "Title": "Sky of Whisper", + "Released": "2019-01-30", + "Genre": "ethno-tunes", + "Album": "Dark matters" + }, + { + "Number": 10, + "Title": "Dancing in the Light", + "Released": "2019-11-28", + "Genre": "Synth-pop R&B", + "Album": "Dark matters" + } + ] + } + ] + }, + { + "ID": 6, + "Artist": "Nguyễn Diệp Chi", + "Photo": "https://dl.infragistics.com/x/img/people/names/nguyen.png", + "Debut": 1992, + "GrammyNominations": 4, + "GrammyAwards": 2, + "HasGrammyAward": true, + "Tours": [], + "Albums": [ + { + "Album": "Library of liberty", + "LaunchDate": "2003-12-22", + "BillboardReview": 93, + "USBillboard200": 5, + "Artist": "Nguyễn Diệp Chi", + "Songs": [ + { + "Number": 1, + "Title": "Echo of River", + "Released": "2019-03-05", + "Genre": "Synth-pop R&B", + "Album": "Library of liberty" + }, + { + "Number": 2, + "Title": "Heart of River", + "Released": "2020-01-12", + "Genre": "Electro house Electropop", + "Album": "Library of liberty" + }, + { + "Number": 3, + "Title": "Dark Light", + "Released": "2019-08-09", + "Genre": "Electro house Electropop", + "Album": "Library of liberty" + }, + { + "Number": 4, + "Title": "Dark Fire", + "Released": "2019-06-22", + "Genre": "R&B", + "Album": "Library of liberty" + }, + { + "Number": 5, + "Title": "Flying in the Fire", + "Released": "2019-07-22", + "Genre": "*", + "Album": "Library of liberty" + }, + { + "Number": 6, + "Title": "Shadow of Heart", + "Released": "2020-01-02", + "Genre": "*", + "Album": "Library of liberty" + }, + { + "Number": 7, + "Title": "Fire of Fire", + "Released": "2019-01-27", + "Genre": "*", + "Album": "Library of liberty" + }, + { + "Number": 8, + "Title": "Falling in the River", + "Released": "2019-08-05", + "Genre": "Crunk reggaeton", + "Album": "Library of liberty" + }, + { + "Number": 9, + "Title": "Fire of Light", + "Released": "2019-12-31", + "Genre": "ethno-tunes", + "Album": "Library of liberty" + }, + { + "Number": 10, + "Title": "Bright Flying", + "Released": "2019-01-24", + "Genre": "*", + "Album": "Library of liberty" + } + ] + } + ] + }, + { + "ID": 7, + "Artist": "Eva Lee", + "Photo": "https://dl.infragistics.com/x/img/people/names/eva.png", + "Debut": 2008, + "GrammyNominations": 2, + "GrammyAwards": 0, + "HasGrammyAward": false, + "Tours": [], + "Albums": [ + { + "Album": "Just a tease", + "LaunchDate": "2001-05-03", + "BillboardReview": 91, + "USBillboard200": 29, + "Artist": "Eva Lee", + "Songs": [ + { + "Number": 1, + "Title": "Dancing in the Shadow", + "Released": "2019-08-02", + "Genre": "ethno-tunes", + "Album": "Just a tease" + }, + { + "Number": 2, + "Title": "Silent Whisper", + "Released": "2019-07-09", + "Genre": "*", + "Album": "Just a tease" + }, + { + "Number": 3, + "Title": "Crying in the Whisper", + "Released": "2019-05-30", + "Genre": "Crunk reggaeton", + "Album": "Just a tease" + }, + { + "Number": 4, + "Title": "River of Light", + "Released": "2019-01-10", + "Genre": "Electro house Electropop", + "Album": "Just a tease" + }, + { + "Number": 5, + "Title": "Golden River", + "Released": "2019-11-15", + "Genre": "*", + "Album": "Just a tease" + }, + { + "Number": 6, + "Title": "Burning in the Shadow", + "Released": "2019-04-18", + "Genre": "Crunk reggaeton", + "Album": "Just a tease" + }, + { + "Number": 7, + "Title": "Shadow of Sky", + "Released": "2019-09-06", + "Genre": "Crunk reggaeton", + "Album": "Just a tease" + }, + { + "Number": 8, + "Title": "Gentle Waiting", + "Released": "2019-12-05", + "Genre": "R&B", + "Album": "Just a tease" + }, + { + "Number": 9, + "Title": "Bright River", + "Released": "2020-01-27", + "Genre": "R&B", + "Album": "Just a tease" + }, + { + "Number": 10, + "Title": "Heart of Storm", + "Released": "2019-01-07", + "Genre": "Synth-pop R&B", + "Album": "Just a tease" + } + ] + } + ] + }, + { + "ID": 8, + "Artist": "Siri Jakobsson", + "Photo": "https://dl.infragistics.com/x/img/people/names/siri.png", + "Debut": 1990, + "GrammyNominations": 2, + "GrammyAwards": 8, + "HasGrammyAward": true, + "Tours": [ + { + "Tour": "Basket case", + "StartedOn": "Jan 07", + "Location": "Europe, Asia", + "Headliner": "NO", + "TouredBy": "Siri Jakobsson" + }, + { + "Tour": "The bigger fish", + "StartedOn": "Dec 07", + "Location": "United States, Europe", + "Headliner": "YES", + "TouredBy": "Siri Jakobsson" + }, + { + "Tour": "Missed the boat", + "StartedOn": "Jun 09", + "Location": "Europe, Asia", + "Headliner": "NO", + "TouredBy": "Siri Jakobsson" + }, + { + "Tour": "Equivalent exchange", + "StartedOn": "Feb 06", + "Location": "United States, Europe", + "Headliner": "YES", + "TouredBy": "Siri Jakobsson" + }, + { + "Tour": "Damage control", + "StartedOn": "Oct 11", + "Location": "Australia, United States", + "Headliner": "NO", + "TouredBy": "Siri Jakobsson" + } + ], + "Albums": [ + { + "Album": "Under the bus", + "LaunchDate": "2000-05-14", + "BillboardReview": 67, + "USBillboard200": 67, + "Artist": "Siri Jakobsson", + "Songs": [ + { + "Number": 1, + "Title": "Jack Broke My Heart At Tesco's", + "Released": "2020-01-19", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 2, + "Title": "Cat Deep, Hats High", + "Released": "2019-12-05", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 3, + "Title": "In Snail We Trust", + "Released": "2019-05-31", + "Genre": "hardcore opera", + "Album": "Under the bus" + }, + { + "Number": 4, + "Title": "Liz's Waiting", + "Released": "2019-07-22", + "Genre": "emotional C-jam ", + "Album": "Under the bus" + }, + { + "Number": 5, + "Title": "Lifeless Blues", + "Released": "2019-06-14", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 6, + "Title": "I Spin", + "Released": "2019-03-26", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 7, + "Title": "Ring of Rock", + "Released": "2019-12-12", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 8, + "Title": "Livin' on a Rock", + "Released": "2019-04-17", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 9, + "Title": "Your Lifeless Heart", + "Released": "2019-09-15", + "Genre": "adult calypso-industrial", + "Album": "Under the bus" + }, + { + "Number": 10, + "Title": "The High Street on My Mind", + "Released": "2019-11-11", + "Genre": "calypso and mariachi", + "Album": "Under the bus" + }, + { + "Number": 11, + "Title": "Behind Ugly Curtains", + "Released": "2019-05-08", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 12, + "Title": "Where Have All the Curtains Gone?", + "Released": "2019-06-28", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 13, + "Title": "Ghost in My Apple", + "Released": "2019-12-14", + "Genre": "*", + "Album": "Under the bus" + }, + { + "Number": 14, + "Title": "I Chatter", + "Released": "2019-11-30", + "Genre": "*", + "Album": "Under the bus" + } + ] + } + ] + }, + { + "ID": 9, + "Artist": "Pablo Cambeiro", + "Photo": "https://dl.infragistics.com/x/img/people/names/pablo.png", + "Debut": 2011, + "GrammyNominations": 5, + "GrammyAwards": 0, + "HasGrammyAward": false, + "Tours": [ + { + "Tour": "Beads", + "StartedOn": "May 11", + "Location": "Worldwide", + "Headliner": "NO", + "TouredBy": "Pablo Cambeiro" + }, + { + "Tour": "Concept art", + "StartedOn": "Dec 18", + "Location": "United States", + "Headliner": "YES", + "TouredBy": "Pablo Cambeiro" + }, + { + "Tour": "Glass shoe", + "StartedOn": "Jan 20", + "Location": "Worldwide", + "Headliner": "YES", + "TouredBy": "Pablo Cambeiro" + }, + { + "Tour": "Pushing buttons", + "StartedOn": "Feb 15", + "Location": "Europe, Asia", + "Headliner": "NO", + "TouredBy": "Pablo Cambeiro" + }, + { + "Tour": "Dark matters", + "StartedOn": "Jan 04", + "Location": "Australia, United States", + "Headliner": "YES", + "TouredBy": "Pablo Cambeiro" + }, + { + "Tour": "Greener grass", + "StartedOn": "Sep 09", + "Location": "United States, Europe", + "Headliner": "NO", + "TouredBy": "Pablo Cambeiro" + }, + { + "Tour": "Apparatus", + "StartedOn": "Nov 16", + "Location": "Europe", + "Headliner": "NO", + "TouredBy": "Pablo Cambeiro" + } + ], + "Albums": [ + { + "Album": "Fluke", + "LaunchDate": "2017-08-04", + "BillboardReview": 93, + "USBillboard200": 98, + "Artist": "Pablo Cambeiro", + "Songs": [ + { + "Number": 1, + "Title": "Dancing in the Echo", + "Released": "2019-10-03", + "Genre": "Crunk reggaeton", + "Album": "Fluke" + }, + { + "Number": 2, + "Title": "Dream of Dream", + "Released": "2019-03-03", + "Genre": "*", + "Album": "Fluke" + }, + { + "Number": 3, + "Title": "Calling in the Echo", + "Released": "2019-09-16", + "Genre": "*", + "Album": "Fluke" + }, + { + "Number": 4, + "Title": "Light of Light", + "Released": "2019-05-25", + "Genre": "Electro house Electropop", + "Album": "Fluke" + }, + { + "Number": 5, + "Title": "Bright Light", + "Released": "2019-03-21", + "Genre": "R&B", + "Album": "Fluke" + }, + { + "Number": 6, + "Title": "Storm of Echo", + "Released": "2019-07-17", + "Genre": "Synth-pop R&B", + "Album": "Fluke" + }, + { + "Number": 7, + "Title": "Lonely Calling", + "Released": "2019-04-10", + "Genre": "ethno-tunes", + "Album": "Fluke" + }, + { + "Number": 8, + "Title": "Gentle Falling", + "Released": "2019-11-28", + "Genre": "Synth-pop R&B", + "Album": "Fluke" + }, + { + "Number": 9, + "Title": "Wild Flying", + "Released": "2019-11-26", + "Genre": "Crunk reggaeton", + "Album": "Fluke" + }, + { + "Number": 10, + "Title": "Sky of Dream", + "Released": "2019-05-29", + "Genre": "R&B", + "Album": "Fluke" + } + ] + }, + { + "Album": "Crowd control", + "LaunchDate": "2003-08-26", + "BillboardReview": 68, + "USBillboard200": 84, + "Artist": "Pablo Cambeiro", + "Songs": [ + { + "Number": 1, + "Title": "My Bed on My Mind", + "Released": "2019-03-25", + "Genre": "ethno-tunes", + "Album": "Crowd control" + }, + { + "Number": 2, + "Title": "Bright Blues", + "Released": "2019-09-28", + "Genre": "neuro-tunes", + "Album": "Crowd control" + }, + { + "Number": 3, + "Title": "Sail, Sail, Sail!", + "Released": "2019-03-05", + "Genre": "*", + "Album": "Crowd control" + }, + { + "Number": 4, + "Title": "Hotel My Bed", + "Released": "2019-03-22", + "Genre": "*", + "Album": "Crowd control" + }, + { + "Number": 5, + "Title": "Gonna Make You Mash", + "Released": "2019-05-18", + "Genre": "*", + "Album": "Crowd control" + }, + { + "Number": 6, + "Title": "Straight Outta America", + "Released": "2020-01-16", + "Genre": "hardcore opera", + "Album": "Crowd control" + }, + { + "Number": 7, + "Title": "I Drive", + "Released": "2019-02-23", + "Genre": "emotional C-jam ", + "Album": "Crowd control" + }, + { + "Number": 8, + "Title": "Like a Teddy", + "Released": "2019-08-31", + "Genre": "*", + "Album": "Crowd control" + }, + { + "Number": 9, + "Title": "Teddy Boogie", + "Released": "2019-11-30", + "Genre": "*", + "Album": "Crowd control" + } + ] + } + ] + }, + { + "ID": 10, + "Artist": "Athar Malakooti", + "Photo": "https://dl.infragistics.com/x/img/people/names/athar.png", + "Debut": 2017, + "GrammyNominations": 0, + "GrammyAwards": 0, + "HasGrammyAward": false, + "Tours": [], + "Albums": [ + { + "Album": "Pushing up daisies", + "LaunchDate": "2016-02-24", + "BillboardReview": 74, + "USBillboard200": 77, + "Artist": "Athar Malakooti", + "Songs": [ + { + "Number": 1, + "Title": "Hiding in the Whisper", + "Released": "2019-04-03", + "Genre": "R&B", + "Album": "Pushing up daisies" + }, + { + "Number": 2, + "Title": "Wicked Light", + "Released": "2019-08-21", + "Genre": "R&B", + "Album": "Pushing up daisies" + }, + { + "Number": 3, + "Title": "Flying in the River", + "Released": "2020-02-03", + "Genre": "Synth-pop R&B", + "Album": "Pushing up daisies" + }, + { + "Number": 4, + "Title": "Wicked Hiding", + "Released": "2019-09-15", + "Genre": "Synth-pop R&B", + "Album": "Pushing up daisies" + }, + { + "Number": 5, + "Title": "Lonely Light", + "Released": "2019-05-13", + "Genre": "Electro house Electropop", + "Album": "Pushing up daisies" + }, + { + "Number": 6, + "Title": "Bright Dancing", + "Released": "2019-04-10", + "Genre": "Synth-pop R&B", + "Album": "Pushing up daisies" + }, + { + "Number": 7, + "Title": "Gentle Dream", + "Released": "2019-05-21", + "Genre": "*", + "Album": "Pushing up daisies" + }, + { + "Number": 8, + "Title": "Sky of Echo", + "Released": "2019-06-09", + "Genre": "Synth-pop R&B", + "Album": "Pushing up daisies" + }, + { + "Number": 9, + "Title": "Breaking in the Sky", + "Released": "2019-12-27", + "Genre": "Crunk reggaeton", + "Album": "Pushing up daisies" + }, + { + "Number": 10, + "Title": "Whisper of Shadow", + "Released": "2019-01-04", + "Genre": "ethno-tunes", + "Album": "Pushing up daisies" + } + ] + } + ] + }, + { + "ID": 11, + "Artist": "Marti Valencia", + "Photo": "https://dl.infragistics.com/x/img/people/names/marti.png", + "Debut": 2004, + "GrammyNominations": 1, + "GrammyAwards": 1, + "HasGrammyAward": true, + "Tours": [ + { + "Tour": "Cat eat cat world", + "StartedOn": "Sep 00", + "Location": "Worldwide", + "Headliner": "YES", + "TouredBy": "Marti Valencia" + }, + { + "Tour": "Final straw", + "StartedOn": "Sep 06", + "Location": "United States, Europe", + "Headliner": "NO", + "TouredBy": "Marti Valencia" + } + ], + "Albums": [ + { + "Album": "Nemesis", + "LaunchDate": "2004-06-30", + "BillboardReview": 94, + "USBillboard200": 9, + "Artist": "Marti Valencia", + "Songs": [ + { + "Number": 1, + "Title": "Hiding in the Sky", + "Released": "2019-11-26", + "Genre": "Synth-pop R&B", + "Album": "Nemesis" + }, + { + "Number": 2, + "Title": "Waiting in the Echo", + "Released": "2019-07-10", + "Genre": "ethno-tunes", + "Album": "Nemesis" + }, + { + "Number": 3, + "Title": "Wicked Shadow", + "Released": "2019-07-29", + "Genre": "Synth-pop R&B", + "Album": "Nemesis" + }, + { + "Number": 4, + "Title": "Crying in the Whisper", + "Released": "2019-04-09", + "Genre": "*", + "Album": "Nemesis" + }, + { + "Number": 5, + "Title": "Echo of Storm", + "Released": "2019-11-19", + "Genre": "Crunk reggaeton", + "Album": "Nemesis" + }, + { + "Number": 6, + "Title": "Shadow of Sky", + "Released": "2019-07-24", + "Genre": "Crunk reggaeton", + "Album": "Nemesis" + }, + { + "Number": 7, + "Title": "Golden Hiding", + "Released": "2019-12-12", + "Genre": "Electro house Electropop", + "Album": "Nemesis" + }, + { + "Number": 8, + "Title": "Wild Dancing", + "Released": "2019-08-17", + "Genre": "Synth-pop R&B", + "Album": "Nemesis" + }, + { + "Number": 9, + "Title": "Bright Burning", + "Released": "2019-08-30", + "Genre": "Electro house Electropop", + "Album": "Nemesis" + }, + { + "Number": 10, + "Title": "Flying in the River", + "Released": "2019-09-02", + "Genre": "*", + "Album": "Nemesis" + } + ] + }, + { + "Album": "First chance", + "LaunchDate": "2019-01-07", + "BillboardReview": 96, + "USBillboard200": 19, + "Artist": "Marti Valencia", + "Songs": [ + { + "Number": 1, + "Title": "My Name is Jason", + "Released": "2019-07-12", + "Genre": "*", + "Album": "First chance" + }, + { + "Number": 2, + "Title": "Amazing Andy", + "Released": "2019-03-05", + "Genre": "*", + "Album": "First chance" + }, + { + "Number": 3, + "Title": "The Number of your Knight", + "Released": "2019-12-04", + "Genre": "*", + "Album": "First chance" + }, + { + "Number": 4, + "Title": "I Sail", + "Released": "2019-03-03", + "Genre": "*", + "Album": "First chance" + }, + { + "Number": 5, + "Title": "Goody Two Hands", + "Released": "2019-10-11", + "Genre": "Electro house Electropop", + "Album": "First chance" + }, + { + "Number": 6, + "Title": "Careful With That Knife", + "Released": "2019-12-18", + "Genre": "R&B", + "Album": "First chance" + }, + { + "Number": 7, + "Title": "Four Single Ants", + "Released": "2020-01-18", + "Genre": "*", + "Album": "First chance" + }, + { + "Number": 8, + "Title": "Kiss Forever", + "Released": "2019-08-10", + "Genre": "*", + "Album": "First chance" + }, + { + "Number": 9, + "Title": "Rich's Waiting", + "Released": "2019-03-15", + "Genre": "Synth-pop R&B", + "Album": "First chance" + }, + { + "Number": 10, + "Title": "Japan is Your Land", + "Released": "2019-03-07", + "Genre": "ethno-tunes", + "Album": "First chance" + }, + { + "Number": 11, + "Title": "Pencils in My Banana", + "Released": "2019-06-21", + "Genre": "Crunk reggaeton", + "Album": "First chance" + }, + { + "Number": 12, + "Title": "I Sail in Your Arms", + "Released": "2019-04-30", + "Genre": "Synth-pop R&B", + "Album": "First chance" + } + ] + }, + { + "Album": "God's advocate", + "LaunchDate": "2007-04-29", + "BillboardReview": 66, + "USBillboard200": 37, + "Artist": "Marti Valencia", + "Songs": [ + { + "Number": 1, + "Title": "Wild River", + "Released": "2019-01-11", + "Genre": "*", + "Album": "God's advocate" + }, + { + "Number": 2, + "Title": "Wicked Whisper", + "Released": "2019-02-16", + "Genre": "Electro house Electropop", + "Album": "God's advocate" + }, + { + "Number": 3, + "Title": "Storm of Heart", + "Released": "2019-08-11", + "Genre": "*", + "Album": "God's advocate" + }, + { + "Number": 4, + "Title": "Golden Dancing", + "Released": "2019-03-02", + "Genre": "Crunk reggaeton", + "Album": "God's advocate" + }, + { + "Number": 5, + "Title": "Calling in the Sky", + "Released": "2019-09-10", + "Genre": "Electro house Electropop", + "Album": "God's advocate" + }, + { + "Number": 6, + "Title": "Calling in the Heart", + "Released": "2019-01-12", + "Genre": "ethno-tunes", + "Album": "God's advocate" + }, + { + "Number": 7, + "Title": "Running in the Storm", + "Released": "2019-11-10", + "Genre": "Synth-pop R&B", + "Album": "God's advocate" + }, + { + "Number": 8, + "Title": "Wild Sky", + "Released": "2019-04-10", + "Genre": "R&B", + "Album": "God's advocate" + }, + { + "Number": 9, + "Title": "Crying in the Shadow", + "Released": "2019-03-02", + "Genre": "R&B", + "Album": "God's advocate" + }, + { + "Number": 10, + "Title": "Whisper of River", + "Released": "2019-05-12", + "Genre": "*", + "Album": "God's advocate" + } + ] + } + ] + }, + { + "ID": 12, + "Artist": "Alicia Stanger", + "Photo": "https://dl.infragistics.com/x/img/people/names/alicia.png", + "Debut": 2010, + "GrammyNominations": 1, + "GrammyAwards": 0, + "HasGrammyAward": false, + "Tours": [], + "Albums": [ + { + "Album": "Forever alone", + "LaunchDate": "2005-11-03", + "BillboardReview": 82, + "USBillboard200": 7, + "Artist": "Alicia Stanger", + "Songs": [ + { + "Number": 1, + "Title": "Shadow of Light", + "Released": "2019-03-24", + "Genre": "ethno-tunes", + "Album": "Forever alone" + }, + { + "Number": 2, + "Title": "Running in the Echo", + "Released": "2019-05-03", + "Genre": "Crunk reggaeton", + "Album": "Forever alone" + }, + { + "Number": 3, + "Title": "Gentle Dream", + "Released": "2019-08-24", + "Genre": "Crunk reggaeton", + "Album": "Forever alone" + }, + { + "Number": 4, + "Title": "Furious River", + "Released": "2019-04-24", + "Genre": "ethno-tunes", + "Album": "Forever alone" + }, + { + "Number": 5, + "Title": "Wild Whisper", + "Released": "2019-03-09", + "Genre": "ethno-tunes", + "Album": "Forever alone" + }, + { + "Number": 6, + "Title": "Whisper of Sky", + "Released": "2019-07-24", + "Genre": "Crunk reggaeton", + "Album": "Forever alone" + }, + { + "Number": 7, + "Title": "Lonely Storm", + "Released": "2019-05-01", + "Genre": "Crunk reggaeton", + "Album": "Forever alone" + }, + { + "Number": 8, + "Title": "Dancing in the River", + "Released": "2019-12-17", + "Genre": "*", + "Album": "Forever alone" + }, + { + "Number": 9, + "Title": "Electric Fire", + "Released": "2019-10-17", + "Genre": "Electro house Electropop", + "Album": "Forever alone" + }, + { + "Number": 10, + "Title": "Electric Sky", + "Released": "2019-09-25", + "Genre": "ethno-tunes", + "Album": "Forever alone" + } + ] + } + ] + }, + { + "ID": 13, + "Artist": "Peter Taylor", + "Photo": "https://dl.infragistics.com/x/img/people/names/peter.png", + "Debut": 2005, + "GrammyNominations": 0, + "GrammyAwards": 2, + "HasGrammyAward": true, + "Tours": [ + { + "Tour": "Love", + "StartedOn": "Jun 04", + "Location": "Europe, Asia", + "Headliner": "YES", + "TouredBy": "Peter Taylor" + }, + { + "Tour": "Fault of treasures", + "StartedOn": "Oct 13", + "Location": "North America", + "Headliner": "NO", + "TouredBy": "Peter Taylor" + }, + { + "Tour": "For eternity", + "StartedOn": "Mar 05", + "Location": "United States", + "Headliner": "YES", + "TouredBy": "Peter Taylor" + }, + { + "Tour": "Time flies", + "StartedOn": "Jun 03", + "Location": "North America", + "Headliner": "NO", + "TouredBy": "Peter Taylor" + }, + { + "Tour": "Highest difficulty", + "StartedOn": "Nov 01", + "Location": "Worldwide", + "Headliner": "YES", + "TouredBy": "Peter Taylor" + }, + { + "Tour": "Sleeping dogs", + "StartedOn": "May 04", + "Location": "United States, Europe", + "Headliner": "NO", + "TouredBy": "Peter Taylor" + } + ], + "Albums": [ + { + "Album": "Decisions decisions", + "LaunchDate": "2008-04-10", + "BillboardReview": 85, + "USBillboard200": 35, + "Artist": "Peter Taylor", + "Songs": [ + { + "Number": 1, + "Title": "Calling in the Dream", + "Released": "2019-08-01", + "Genre": "R&B", + "Album": "Decisions decisions" + }, + { + "Number": 2, + "Title": "Electric Burning", + "Released": "2019-09-10", + "Genre": "Electro house Electropop", + "Album": "Decisions decisions" + }, + { + "Number": 3, + "Title": "Dark Flying", + "Released": "2019-04-28", + "Genre": "*", + "Album": "Decisions decisions" + }, + { + "Number": 4, + "Title": "Gentle Sky", + "Released": "2019-11-20", + "Genre": "ethno-tunes", + "Album": "Decisions decisions" + }, + { + "Number": 5, + "Title": "Gentle Calling", + "Released": "2019-01-13", + "Genre": "Crunk reggaeton", + "Album": "Decisions decisions" + }, + { + "Number": 6, + "Title": "Golden Falling", + "Released": "2019-02-14", + "Genre": "Crunk reggaeton", + "Album": "Decisions decisions" + }, + { + "Number": 7, + "Title": "Silent River", + "Released": "2019-02-13", + "Genre": "R&B", + "Album": "Decisions decisions" + }, + { + "Number": 8, + "Title": "Furious Calling", + "Released": "2019-06-11", + "Genre": "Synth-pop R&B", + "Album": "Decisions decisions" + }, + { + "Number": 9, + "Title": "Running in the Echo", + "Released": "2019-11-06", + "Genre": "Electro house Electropop", + "Album": "Decisions decisions" + }, + { + "Number": 10, + "Title": "Furious River", + "Released": "2019-03-12", + "Genre": "*", + "Album": "Decisions decisions" + } + ] + }, + { + "Album": "Climate changed", + "LaunchDate": "2015-06-20", + "BillboardReview": 66, + "USBillboard200": 89, + "Artist": "Peter Taylor", + "Songs": [ + { + "Number": 1, + "Title": "Dark Crying", + "Released": "2019-04-27", + "Genre": "Electro house Electropop", + "Album": "Climate changed" + }, + { + "Number": 2, + "Title": "Dark Waiting", + "Released": "2019-11-14", + "Genre": "Synth-pop R&B", + "Album": "Climate changed" + }, + { + "Number": 3, + "Title": "Furious Waiting", + "Released": "2019-05-23", + "Genre": "*", + "Album": "Climate changed" + }, + { + "Number": 4, + "Title": "Running in the Echo", + "Released": "2019-11-29", + "Genre": "Crunk reggaeton", + "Album": "Climate changed" + }, + { + "Number": 5, + "Title": "Dream of Sky", + "Released": "2019-10-31", + "Genre": "Crunk reggaeton", + "Album": "Climate changed" + }, + { + "Number": 6, + "Title": "Hiding in the Heart", + "Released": "2019-08-09", + "Genre": "R&B", + "Album": "Climate changed" + }, + { + "Number": 7, + "Title": "Sky of Storm", + "Released": "2019-06-01", + "Genre": "R&B", + "Album": "Climate changed" + }, + { + "Number": 8, + "Title": "Light of Storm", + "Released": "2020-01-17", + "Genre": "ethno-tunes", + "Album": "Climate changed" + }, + { + "Number": 9, + "Title": "Light of Sky", + "Released": "2019-05-26", + "Genre": "*", + "Album": "Climate changed" + }, + { + "Number": 10, + "Title": "Golden River", + "Released": "2019-06-19", + "Genre": "*", + "Album": "Climate changed" + } + ] + } + ] + } +] \ No newline at end of file diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/src/index.css b/samples/grids/hierarchical-grid/grid-batch-editing/src/index.css new file mode 100644 index 0000000000..94f5e82799 --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/src/index.css @@ -0,0 +1,39 @@ +/* shared styles are loaded from: */ +/* https://dl.infragistics.com/x/css/samples/shared.v8.css */ + +#grid { + --ig-size: var(--ig-size-medium); +} + +.buttons-wrapper { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 10px 0; +} + +.buttons-right { + display: flex; + gap: 8px; +} + +.dialog-buttons { + display: flex; + gap: 8px; + justify-content: flex-end; +} + +.transaction--add { + color: #6b3; + font-weight: 600; +} + +.transaction--update { + color: #4a71b9; + font-weight: 600; +} + +.transaction--delete { + color: #ee4920; + font-weight: 600; +} diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/src/index.ts b/samples/grids/hierarchical-grid/grid-batch-editing/src/index.ts new file mode 100644 index 0000000000..8875e9f92d --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/src/index.ts @@ -0,0 +1,137 @@ +import 'igniteui-webcomponents-grids/grids/combined'; +import { IgcHierarchicalGridComponent, IgcGridComponent, IgcColumnComponent } from 'igniteui-webcomponents-grids/grids'; +import SingersData from './SingersData.json'; +import { IgcCellTemplateContext } from 'igniteui-webcomponents-grids/grids'; +import { html } from 'lit-html'; + +import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css"; +import 'igniteui-webcomponents/themes/light/bootstrap.css'; +import { defineAllComponents, IgcButtonComponent, IgcDialogComponent } from 'igniteui-webcomponents'; +defineAllComponents(); + +import "./index.css"; + +export class HierarchicalGridBatchEditingSample { + + private grid: IgcHierarchicalGridComponent; + private deleteRowColumn: IgcColumnComponent; + private addRowBtn: IgcButtonComponent; + private undoBtn: IgcButtonComponent; + private redoBtn: IgcButtonComponent; + private commitBtn: IgcButtonComponent; + private discardBtn: IgcButtonComponent; + private dialog: IgcDialogComponent; + private transactionGrid: IgcGridComponent; + private typeColumn: IgcColumnComponent; + private valueColumn: IgcColumnComponent; + private addId: number = 1000; + + constructor() { + this.grid = document.getElementById('grid') as IgcHierarchicalGridComponent; + this.deleteRowColumn = document.getElementById('actionsColumn') as IgcColumnComponent; + this.addRowBtn = document.getElementById('addRowBtn') as IgcButtonComponent; + this.undoBtn = document.getElementById('undoBtn') as IgcButtonComponent; + this.redoBtn = document.getElementById('redoBtn') as IgcButtonComponent; + this.commitBtn = document.getElementById('commitBtn') as IgcButtonComponent; + this.discardBtn = document.getElementById('discardBtn') as IgcButtonComponent; + this.dialog = document.getElementById('dialog') as IgcDialogComponent; + this.transactionGrid = document.getElementById('transactionGrid') as IgcGridComponent; + this.typeColumn = document.getElementById('typeColumn') as IgcColumnComponent; + this.valueColumn = document.getElementById('valueColumn') as IgcColumnComponent; + + this.grid.batchEditing = true; + this.grid.data = this.singersData; + this.deleteRowColumn.bodyTemplate = this.deleteRowColumnTemplate; + this.typeColumn.bodyTemplate = this.typeColumnTemplate; + this.valueColumn.bodyTemplate = this.valueColumnTemplate; + + this.addRowBtn.addEventListener('click', this.onAddRowClick); + this.undoBtn.addEventListener('click', this.onUndoClick); + this.redoBtn.addEventListener('click', this.onRedoClick); + this.commitBtn.addEventListener('click', this.onOpenCommitDialog); + this.discardBtn.addEventListener('click', this.onDiscardClick); + + document.getElementById('dialogCommitBtn')!.addEventListener('click', this.onCommitClick); + document.getElementById('dialogDiscardBtn')!.addEventListener('click', this.onDiscardClick); + document.getElementById('dialogCancelBtn')!.addEventListener('click', this.onCancelClick); + + this.grid.transactions.onStateUpdate.subscribe(() => { + this.undoBtn.disabled = !this.grid.transactions.canUndo; + this.redoBtn.disabled = !this.grid.transactions.canRedo; + const hasChanges = this.grid.transactions.getAggregatedChanges(false).length > 0; + this.commitBtn.disabled = !hasChanges; + this.discardBtn.disabled = !hasChanges; + }); + } + + private _singersData: any[] = SingersData; + public get singersData(): any[] { + return this._singersData; + } + + public deleteRowColumnTemplate = (ctx: IgcCellTemplateContext) => { + return html` this.onDeleteRowClick(ctx.cell.id.rowID)}>Delete`; + } + + public typeColumnTemplate = (ctx: IgcCellTemplateContext) => { + const type = ctx.cell.value as string; + return html`${type.toUpperCase()}`; + } + + public valueColumnTemplate = (ctx: IgcCellTemplateContext) => { + return html`${JSON.stringify(ctx.cell.value)}`; + } + + public onAddRowClick = () => { + this.grid.addRow({ + ID: this.addId++, + Artist: 'New Artist ' + this.randomInt(1, 100), + Debut: this.randomInt(1990, 2025), + GrammyNominations: this.randomInt(0, 20), + GrammyAwards: this.randomInt(0, 10), + HasGrammyAward: this.randomInt(0, 1) === 1, + Albums: [], + Tours: [] + }); + } + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + public onUndoClick = () => { + this.grid.endEdit(true); + this.grid.transactions.undo(); + } + + public onRedoClick = () => { + this.grid.endEdit(true); + this.grid.transactions.redo(); + } + + public onOpenCommitDialog = () => { + this.transactionGrid.data = this.grid.transactions.getAggregatedChanges(true); + this.dialog.show(); + } + + public onCommitClick = () => { + this.grid.transactions.commit(this.grid.data); + this.dialog.hide(); + } + + public onDiscardClick = () => { + this.grid.transactions.clear(); + this.dialog.hide(); + } + + public onCancelClick = () => { + this.dialog.hide(); + } + + public onDeleteRowClick = (rowId: any) => { + this.grid.deleteRow(rowId); + } + +} + +new HierarchicalGridBatchEditingSample(); diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/tsconfig.json b/samples/grids/hierarchical-grid/grid-batch-editing/tsconfig.json new file mode 100644 index 0000000000..02c7f095e6 --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/tsconfig.json @@ -0,0 +1,42 @@ +{ + "compilerOptions": { + "noImplicitReturns": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "noImplicitAny": true, + "declarationDir": "dist/types", + "moduleResolution": "node", + "declaration": true, + "target": "es2015", + "module": "es2015", + "strict": true, + "skipLibCheck": true, + "strictNullChecks": false, + "baseUrl": ".", + "paths": { + "igniteui-webcomponents-core": [ "node_modules/igniteui-webcomponents-core", "node_modules/@infragistics/igniteui-webcomponents-core" ], + "igniteui-webcomponents-charts": [ "node_modules/igniteui-webcomponents-charts", "node_modules/@infragistics/igniteui-webcomponents-charts" ], + "igniteui-webcomponents-gauges": [ "node_modules/igniteui-webcomponents-gauges", "node_modules/@infragistics/igniteui-webcomponents-gauges" ], + "igniteui-webcomponents-datasources": [ "node_modules/igniteui-webcomponents-datasources", "node_modules/@infragistics/igniteui-webcomponents-datasources" ], + "igniteui-webcomponents-excel": [ "node_modules/igniteui-webcomponents-excel", "node_modules/@infragistics/igniteui-webcomponents-excel" ], + "igniteui-webcomponents-inputs": [ "node_modules/igniteui-webcomponents-inputs", "node_modules/@infragistics/igniteui-webcomponents-inputs" ], + "igniteui-webcomponents-grids": [ "node_modules/igniteui-webcomponents-grids", "node_modules/@infragistics/igniteui-webcomponents-grids" ], + "igniteui-webcomponents-maps": [ "node_modules/igniteui-webcomponents-maps", "node_modules/@infragistics/igniteui-webcomponents-maps" ], + "igniteui-webcomponents-spreadsheet": [ "node_modules/igniteui-webcomponents-spreadsheet", "node_modules/@infragistics/igniteui-webcomponents-spreadsheet" ], + "igniteui-webcomponents-spreadsheet-chart-adapter": [ "node_modules/igniteui-webcomponents-spreadsheet-chart-adapter", "node_modules/@infragistics/igniteui-webcomponents-spreadsheet-chart-adapter" ], + "igniteui-webcomponents-grids/*": [ "node_modules/igniteui-webcomponents-grids/*", "node_modules/@infragistics/igniteui-webcomponents-grids/*" ], + "igniteui-webcomponents-grids/grids": [ "node_modules/igniteui-webcomponents-grids/grids", "node_modules/@infragistics/igniteui-webcomponents-grids/grids" ], + "igniteui-webcomponents-grids/grids/*": [ "node_modules/igniteui-webcomponents-grids/grids/*", "node_modules/@infragistics/igniteui-webcomponents-grids/grids/*" ], + "igniteui-webcomponents-grids/grids/combined": [ "node_modules/igniteui-webcomponents-grids/grids/combined", "node_modules/@infragistics/igniteui-webcomponents-grids/grids/combined" ], + "igniteui-webcomponents-layouts": [ "node_modules/igniteui-webcomponents-layouts", "node_modules/@infragistics/igniteui-webcomponents-layouts" ], + "igniteui-webcomponents-dashboards": [ "node_modules/igniteui-webcomponents-dashboards", "node_modules/@infragistics/igniteui-webcomponents-dashboards" ] + } + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/tslint.json b/samples/grids/hierarchical-grid/grid-batch-editing/tslint.json new file mode 100644 index 0000000000..e3b56e93a1 --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/tslint.json @@ -0,0 +1,54 @@ +{ + "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], + "linterOptions": { + "exclude": [ + "node_modules/**/*.ts", + "**/odatajs-4.0.0.js", + "src/images/*.*" + ] + }, + "rules": { + "curly": [false, "ignore-same-line"], + "jsx-no-lambda": false, + "jsx-self-close": false, + "jsx-wrap-multiline": false, + "max-classes-per-file": [true, 10], + "member-ordering": false, + "no-console": false, + "no-string-literal": false, + "no-unused-vars": false, + "no-useless-constructor": false, + "no-trailing-whitespace": false, + "no-var": false, + "no-var-requires": false, + "no-var-keyword": false, + "ordered-imports": false, + "object-literal-sort-keys": false, + "object-literal-shorthand": false, + "only-arrow-functions": false, + "prefer-const": false, + "prefer-for-of": false, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/type-annotation-spacing": "off" + }, + "jsRules": { + "curly": [false, "ignore-same-line"], + "jsx-no-lambda": false, + "jsx-self-close": false, + "jsx-wrap-multiline": false, + "max-classes-per-file": [true, 10], + "no-console": false, + "no-unused-vars": false, + "no-useless-constructor": false, + "no-var-requires": false, + "object-literal-sort-keys": false, + "object-literal-shorthand": false, + "only-arrow-functions": false, + "ordered-imports": false, + "prefer-const": false, + "prefer-for-of": false, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-useless-constructor": "off" + } + } \ No newline at end of file diff --git a/samples/grids/hierarchical-grid/grid-batch-editing/webpack.config.js b/samples/grids/hierarchical-grid/grid-batch-editing/webpack.config.js new file mode 100644 index 0000000000..90d8c30eaa --- /dev/null +++ b/samples/grids/hierarchical-grid/grid-batch-editing/webpack.config.js @@ -0,0 +1,105 @@ +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const path = require('path'); +const webpack = require('webpack'); + +module.exports = env => { + const nodeEnv = process.env.NODE_ENV || 'development'; + const isProd = nodeEnv === 'production'; + const isLegacy = !!process.env.legacy && !(process.env.legacy == "false"); + console.log(">> webpack nodeEnv=" + nodeEnv); + console.log(">> webpack isProd=" + isProd); + console.log(">> webpack isLegacy=" + isLegacy); + const presets = [ + ["@babel/preset-env", { + "useBuiltIns": "usage", + "corejs": 3, + "targets": { + "browsers": isLegacy ? ["defaults"] : [ + "last 2 Chrome versions", + "last 2 Safari versions", + "last 2 iOS versions", + "last 2 Firefox versions", + "last 2 Edge versions"] + } + }], + "@babel/preset-typescript" + ]; + + return { + entry: isLegacy ? [ + path.resolve(__dirname, 'src') + ] : path.resolve(__dirname, 'src'), + devtool: isProd ? false : 'source-map', + output: { + filename: isProd ? '[fullhash].bundle.js' : '[fullhash].bundle.js', + globalObject: 'this', + path: path.resolve(__dirname, 'dist'), + }, + + resolve: { + mainFields: ['esm2015', 'module', 'main'], + extensions: ['.ts', '.js', '.json'], + plugins: [new TsconfigPathsPlugin({ + configFile: './tsconfig.json', + extensions: ['.ts', '.js'], + mainFields: ['esm2015', 'module', 'main'] + })] + }, + + module: { + rules: [ + { test: /\.(png|svg|jpg|gif)$/, use: ['file-loader'] }, + { test: /\.(csv|tsv)$/, use: ['csv-loader'] }, + { test: /\.xml$/, use: ['xml-loader'] }, + { test: /\.css$/, sideEffects: true, use: ['style-loader', 'css-loader'] }, + { + test: /worker\.(ts|js)$/, + use: [ + { loader: 'worker-loader' }, + { + loader: 'babel-loader', options: { + "compact": isProd ? true : false, + "presets": presets, + "plugins": [ + "@babel/plugin-transform-class-static-block", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-runtime" + ] + } + } + ] + }, + { + test: /\.(ts|js)$/, loader: 'babel-loader', + options: { + "compact": isProd ? true : false, + "presets": presets, + "plugins": [ + "@babel/plugin-transform-class-static-block", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-runtime" + ] + }, + exclude: + function (modulePath) { + return /node_modules/.test(modulePath) && + !/igniteui-webcomponents/.test(modulePath) && + !/lit-html/.test(modulePath); + } + }], + }, + + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(nodeEnv) + }), + new HtmlWebpackPlugin({ + title: 'Hierarchical Grid Batch Editing', + template: 'index.html' + }), + new ForkTsCheckerWebpackPlugin() + ] + }; +}; diff --git a/samples/grids/tree-grid/grid-batch-editing/.prettierrc b/samples/grids/tree-grid/grid-batch-editing/.prettierrc new file mode 100644 index 0000000000..15a7c7c6cf --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/.prettierrc @@ -0,0 +1,11 @@ +{ + "printWidth": 250, + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": false, + "trailingComma": "none", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "fluid": false +} \ No newline at end of file diff --git a/samples/grids/tree-grid/grid-batch-editing/ReadMe.md b/samples/grids/tree-grid/grid-batch-editing/ReadMe.md new file mode 100644 index 0000000000..46e4cea940 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/ReadMe.md @@ -0,0 +1,56 @@ + + + +This folder contains implementation of Web Components application with example of Batch Editing feature using [Tree Grid](https://infragistics.com/webcomponentssite/components/general-getting-started.html) component. + + + + + + View Docs + + + View Code + + + Run Sample + + + Run Sample + + + + +## Branches + +> **_NOTE:_** You should use [master](https://github.com/IgniteUI/igniteui-angular-examples/tree/master) branch of this repository if you want to run samples on your computer. Use the [vnext](https://github.com/IgniteUI/igniteui-angular-examples/tree/vnext) branch only when you want to contribute new samples to this repository. + +## Instructions + +To set up this project locally, execute these commands: + +``` +git clone https://github.com/IgniteUI/igniteui-wc-examples.git +git checkout master +cd ./igniteui-wc-examples +cd ./samples/grids/tree-grid/grid-batch-editing +``` + +open above folder in VS Code or type: +``` +code . +``` + +In terminal window, run: + +``` +npm install +npm run start +``` + +Then open http://localhost:4200/ in your browser + + +## Learn More + +To learn more about **Ignite UI for Web Components**, check out the [Web Components documentation](https://infragistics.com/webcomponentssite/components/general-getting-started.html). diff --git a/samples/grids/tree-grid/grid-batch-editing/index.html b/samples/grids/tree-grid/grid-batch-editing/index.html new file mode 100644 index 0000000000..95ae2d2b07 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/index.html @@ -0,0 +1,114 @@ + + + + Tree Grid Batch Editing | Ignite UI | Web Components | infragistics + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + +
+
+ Add Row +
+ Undo + Redo + Discard + Commit +
+
+ + + + + + + +
+ Commit + Discard + Cancel +
+
+
+
+ + + <% if (false) { %><% } %> + + diff --git a/samples/grids/tree-grid/grid-batch-editing/package.json b/samples/grids/tree-grid/grid-batch-editing/package.json new file mode 100644 index 0000000000..2ebd6c4fc1 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/package.json @@ -0,0 +1,60 @@ +{ + "name": "example-ignite-ui-web-components", + "description": "This project provides example of using Ignite UI for Web Components", + "author": "Infragistics", + "version": "1.0.0", + "license": "", + "private": true, + "homepage": ".", + "main": "src/index.ts", + "scripts": { + "build": "npm run build:prod", + "build:dev": "webpack --mode development --config ./webpack.config.js --progress --color --display-error-details", + "build:prod": "webpack --env.NODE_ENV=production --mode production --config ./webpack.config.js --progress --color --display-error-details --bail", + "serve:dev": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --mode development --config ./webpack.config.js --hot --progress --open", + "serve:prod": "webpack-dev-server --env.NODE_ENV=production --mode production --config ./webpack.config.js --port 3000 --host 0.0.0.0 --hot --progress --open --content-base dist/", + "start": "npm run serve:dev", + "build:legacy": "npm run build:prod:legacy", + "build:dev:legacy": "webpack --env.legacy=true --mode development --config ./webpack.config.js --progress --color --display-error-details", + "build:prod:legacy": "webpack --env.NODE_ENV=production --env.legacy=true --mode production --config ./webpack.config.js --progress --color --display-error-details --bail", + "serve:dev:legacy": "node --max-old-space-size=8192 node_modules/webpack-dev-server/bin/webpack-dev-server.js --env.legacy=true --mode development --config ./webpack.config.js --hot --progress --open", + "serve:prod:legacy": "webpack-dev-server --env.NODE_ENV=production --env.legacy=true --mode production --config ./webpack.config.js --port 3000 --host 0.0.0.0 --hot --progress --open --content-base dist/", + "start:legacy": "npm run serve:dev:legacy" + }, + "dependencies": { + "babel-runtime": "^6.26.0", + "igniteui-webcomponents-core": "6.3.1", + "igniteui-webcomponents-grids": "6.3.0-alpha.1", + "igniteui-webcomponents-inputs": "6.3.1", + "igniteui-webcomponents-layouts": "6.3.1", + "lit-html": "^3.3.1", + "tslib": "^2.8.1" + }, + "devDependencies": { + "@babel/cli": "^7.28.3", + "@babel/core": "^7.28.4", + "@babel/plugin-transform-class-properties": "^7.27.1", + "@babel/plugin-transform-class-static-block": "^7.28.3", + "@babel/plugin-transform-runtime": "^7.28.3", + "@babel/preset-env": "^7.28.3", + "@babel/preset-typescript": "^7.27.1", + "@types/source-map": "^0.5.7", + "babel-loader": "^10.0.0", + "babel-plugin-transform-custom-element-classes": "^0.1.0", + "css-loader": "^7.1.2", + "csv-loader": "^3.0.5", + "file-loader": "^6.2.0", + "fork-ts-checker-webpack-plugin": "^9.1.0", + "html-webpack-plugin": "^5.6.4", + "parcel-bundler": "^1.12.5", + "source-map": "^0.7.6", + "style-loader": "^4.0.0", + "tsconfig-paths-webpack-plugin": "^4.2.0", + "typescript": "^5.9.2", + "webpack": "^5.101.3", + "webpack-cli": "^6.0.1", + "webpack-dev-server": "^5.2.2", + "worker-loader": "^3.0.8", + "xml-loader": "^1.2.1" + } +} diff --git a/samples/grids/tree-grid/grid-batch-editing/sandbox.config.json b/samples/grids/tree-grid/grid-batch-editing/sandbox.config.json new file mode 100644 index 0000000000..52c7875103 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/sandbox.config.json @@ -0,0 +1,6 @@ +{ + "infiniteLoopProtection": false, + "hardReloadOnChange": false, + "view": "browser", + "template": "parcel" +} \ No newline at end of file diff --git a/samples/grids/tree-grid/grid-batch-editing/src/EmployeesNestedTreeData.ts b/samples/grids/tree-grid/grid-batch-editing/src/EmployeesNestedTreeData.ts new file mode 100644 index 0000000000..a51b020df3 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/src/EmployeesNestedTreeData.ts @@ -0,0 +1,44 @@ +export class EmployeesNestedTreeDataItem { + public constructor(init: Partial) { + Object.assign(this, init); + } + + public Age: number; + public HireDate: string; + public ID: number; + public Name: string; + public Phone: string; + public OnPTO: boolean; + public ParentID: number; + public Title: string; + +} +export class EmployeesNestedTreeData extends Array { + public constructor(items: Array | number = -1) { + if (Array.isArray(items)) { + super(...items); + } else { + const newItems = [ + new EmployeesNestedTreeDataItem({ Age: 55, HireDate: `2008-03-20`, ID: 1, Name: `Johnathan Winchester`, Phone: `0251-031259`, OnPTO: false, ParentID: -1, Title: `Development Manager` }), + new EmployeesNestedTreeDataItem({ Age: 42, HireDate: `2014-01-22`, ID: 4, Name: `Ana Sanders`, Phone: `(21) 555-0091`, OnPTO: true, ParentID: -1, Title: `CEO` }), + new EmployeesNestedTreeDataItem({ Age: 49, HireDate: `2014-01-22`, ID: 18, Name: `Victoria Lincoln`, Phone: `(071) 23 67 22 20`, OnPTO: true, ParentID: -1, Title: `Accounting Manager` }), + new EmployeesNestedTreeDataItem({ Age: 61, HireDate: `2010-01-01`, ID: 10, Name: `Yang Wang`, Phone: `(21) 555-0091`, OnPTO: false, ParentID: -1, Title: `Localization Manager` }), + new EmployeesNestedTreeDataItem({ Age: 43, HireDate: `2011-06-03`, ID: 3, Name: `Michael Burke`, Phone: `0452-076545`, OnPTO: true, ParentID: 1, Title: `Senior Software Developer` }), + new EmployeesNestedTreeDataItem({ Age: 29, HireDate: `2009-06-19`, ID: 2, Name: `Thomas Anderson`, Phone: `(14) 555-8122`, OnPTO: false, ParentID: 1, Title: `Senior Software Developer` }), + new EmployeesNestedTreeDataItem({ Age: 31, HireDate: `2014-08-18`, ID: 11, Name: `Monica Reyes`, Phone: `7675-3425`, OnPTO: false, ParentID: 1, Title: `Software Development Team Lead` }), + new EmployeesNestedTreeDataItem({ Age: 35, HireDate: `2015-09-17`, ID: 6, Name: `Roland Mendel`, Phone: `(505) 555-5939`, OnPTO: false, ParentID: 11, Title: `Senior Software Developer` }), + new EmployeesNestedTreeDataItem({ Age: 44, HireDate: `2009-10-11`, ID: 12, Name: `Sven Cooper`, Phone: `0695-34 67 21`, OnPTO: true, ParentID: 11, Title: `Senior Software Developer` }), + new EmployeesNestedTreeDataItem({ Age: 44, HireDate: `2014-04-04`, ID: 14, Name: `Laurence Johnson`, Phone: `981-443655`, OnPTO: false, ParentID: 4, Title: `Director` }), + new EmployeesNestedTreeDataItem({ Age: 25, HireDate: `2017-11-09`, ID: 5, Name: `Elizabeth Richards`, Phone: `(2) 283-2951`, OnPTO: true, ParentID: 4, Title: `Vice President` }), + new EmployeesNestedTreeDataItem({ Age: 39, HireDate: `2010-03-22`, ID: 13, Name: `Trevor Ashworth`, Phone: `981-443655`, OnPTO: true, ParentID: 5, Title: `Director` }), + new EmployeesNestedTreeDataItem({ Age: 44, HireDate: `2014-04-04`, ID: 17, Name: `Antonio Moreno`, Phone: `(505) 555-5939`, OnPTO: false, ParentID: 18, Title: `Senior Accountant` }), + new EmployeesNestedTreeDataItem({ Age: 50, HireDate: `2007-11-18`, ID: 7, Name: `Pedro Rodriguez`, Phone: `035-640230`, OnPTO: false, ParentID: 10, Title: `Senior Localization Developer` }), + new EmployeesNestedTreeDataItem({ Age: 27, HireDate: `2016-02-19`, ID: 8, Name: `Casey Harper`, Phone: `0342-023176`, OnPTO: true, ParentID: 10, Title: `Senior Localization` }), + new EmployeesNestedTreeDataItem({ Age: 25, HireDate: `2017-11-09`, ID: 15, Name: `Patricia Simpson`, Phone: `069-0245984`, OnPTO: false, ParentID: 7, Title: `Localization Intern` }), + new EmployeesNestedTreeDataItem({ Age: 39, HireDate: `2010-03-22`, ID: 9, Name: `Francisco Chang`, Phone: `(91) 745 6200`, OnPTO: false, ParentID: 7, Title: `Localization Intern` }), + new EmployeesNestedTreeDataItem({ Age: 25, HireDate: `2018-03-18`, ID: 16, Name: `Peter Lewis`, Phone: `069-0245984`, OnPTO: true, ParentID: 7, Title: `Localization Intern` }), + ]; + super(...newItems.slice(0)); + } + } +} diff --git a/samples/grids/tree-grid/grid-batch-editing/src/index.css b/samples/grids/tree-grid/grid-batch-editing/src/index.css new file mode 100644 index 0000000000..94f5e82799 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/src/index.css @@ -0,0 +1,39 @@ +/* shared styles are loaded from: */ +/* https://dl.infragistics.com/x/css/samples/shared.v8.css */ + +#grid { + --ig-size: var(--ig-size-medium); +} + +.buttons-wrapper { + display: flex; + flex-direction: row; + justify-content: space-between; + padding: 10px 0; +} + +.buttons-right { + display: flex; + gap: 8px; +} + +.dialog-buttons { + display: flex; + gap: 8px; + justify-content: flex-end; +} + +.transaction--add { + color: #6b3; + font-weight: 600; +} + +.transaction--update { + color: #4a71b9; + font-weight: 600; +} + +.transaction--delete { + color: #ee4920; + font-weight: 600; +} diff --git a/samples/grids/tree-grid/grid-batch-editing/src/index.ts b/samples/grids/tree-grid/grid-batch-editing/src/index.ts new file mode 100644 index 0000000000..aca42cc2d4 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/src/index.ts @@ -0,0 +1,142 @@ +import 'igniteui-webcomponents-grids/grids/combined'; +import { IgcTreeGridComponent, IgcGridComponent, IgcColumnComponent } from 'igniteui-webcomponents-grids/grids'; +import { EmployeesNestedTreeData } from './EmployeesNestedTreeData'; +import { IgcCellTemplateContext } from 'igniteui-webcomponents-grids/grids'; +import { html } from 'lit-html'; + +import "igniteui-webcomponents-grids/grids/themes/light/bootstrap.css"; +import 'igniteui-webcomponents/themes/light/bootstrap.css'; +import { defineAllComponents, IgcButtonComponent, IgcDialogComponent } from 'igniteui-webcomponents'; +defineAllComponents(); + +import "./index.css"; + +export class TreeGridBatchEditingSample { + + private grid: IgcTreeGridComponent; + private deleteRowColumn: IgcColumnComponent; + private addRowBtn: IgcButtonComponent; + private undoBtn: IgcButtonComponent; + private redoBtn: IgcButtonComponent; + private commitBtn: IgcButtonComponent; + private discardBtn: IgcButtonComponent; + private dialog: IgcDialogComponent; + private transactionGrid: IgcGridComponent; + private typeColumn: IgcColumnComponent; + private valueColumn: IgcColumnComponent; + private addId: number = 1000; + + constructor() { + this.grid = document.getElementById('grid') as IgcTreeGridComponent; + this.deleteRowColumn = document.getElementById('actionsColumn') as IgcColumnComponent; + this.addRowBtn = document.getElementById('addRowBtn') as IgcButtonComponent; + this.undoBtn = document.getElementById('undoBtn') as IgcButtonComponent; + this.redoBtn = document.getElementById('redoBtn') as IgcButtonComponent; + this.commitBtn = document.getElementById('commitBtn') as IgcButtonComponent; + this.discardBtn = document.getElementById('discardBtn') as IgcButtonComponent; + this.dialog = document.getElementById('dialog') as IgcDialogComponent; + this.transactionGrid = document.getElementById('transactionGrid') as IgcGridComponent; + this.typeColumn = document.getElementById('typeColumn') as IgcColumnComponent; + this.valueColumn = document.getElementById('valueColumn') as IgcColumnComponent; + + this.grid.batchEditing = true; + this.grid.data = this.employeesData; + this.deleteRowColumn.bodyTemplate = this.deleteRowColumnTemplate; + this.typeColumn.bodyTemplate = this.typeColumnTemplate; + this.valueColumn.bodyTemplate = this.valueColumnTemplate; + + this.addRowBtn.addEventListener('click', this.onAddRowClick); + this.undoBtn.addEventListener('click', this.onUndoClick); + this.redoBtn.addEventListener('click', this.onRedoClick); + this.commitBtn.addEventListener('click', this.onOpenCommitDialog); + this.discardBtn.addEventListener('click', this.onDiscardClick); + + document.getElementById('dialogCommitBtn')!.addEventListener('click', this.onCommitClick); + document.getElementById('dialogDiscardBtn')!.addEventListener('click', this.onDiscardClick); + document.getElementById('dialogCancelBtn')!.addEventListener('click', this.onCancelClick); + + this.grid.transactions.onStateUpdate.subscribe(() => { + this.undoBtn.disabled = !this.grid.transactions.canUndo; + this.redoBtn.disabled = !this.grid.transactions.canRedo; + const hasChanges = this.grid.transactions.getAggregatedChanges(false).length > 0; + this.commitBtn.disabled = !hasChanges; + this.discardBtn.disabled = !hasChanges; + }); + } + + private _employeesData: EmployeesNestedTreeData | null = null; + public get employeesData(): EmployeesNestedTreeData { + if (this._employeesData == null) { + this._employeesData = new EmployeesNestedTreeData(); + } + return this._employeesData; + } + + public deleteRowColumnTemplate = (ctx: IgcCellTemplateContext) => { + return html` this.onDeleteRowClick(ctx.cell.id.rowID)}>Delete`; + } + + public typeColumnTemplate = (ctx: IgcCellTemplateContext) => { + const type = ctx.cell.value as string; + return html`${type.toUpperCase()}`; + } + + public valueColumnTemplate = (ctx: IgcCellTemplateContext) => { + return html`${JSON.stringify(ctx.cell.value)}`; + } + + public onAddRowClick = () => { + this.grid.addRow({ + ID: this.addId++, + ParentID: -1, + Name: 'New Employee ' + this.randomInt(1, 100), + Title: 'Employee', + Age: this.randomInt(20, 60), + HireDate: new Date(this.randomInt(2000, 2025), + this.randomInt(0, 11), this.randomInt(1, 25)) + .toISOString().slice(0, 10), + Phone: '555-' + this.randomInt(1000, 9999), + OnPTO: this.randomInt(0, 1) === 1 + }); + } + + private randomInt(min: number, max: number): number { + return Math.floor(Math.random() * (max - min + 1)) + min; + } + + public onUndoClick = () => { + this.grid.endEdit(true); + this.grid.transactions.undo(); + } + + public onRedoClick = () => { + this.grid.endEdit(true); + this.grid.transactions.redo(); + } + + public onOpenCommitDialog = () => { + this.transactionGrid.data = this.grid.transactions.getAggregatedChanges(true); + this.dialog.show(); + } + + public onCommitClick = () => { + this.grid.transactions.commit(this.grid.data); + this.dialog.hide(); + } + + public onDiscardClick = () => { + this.grid.transactions.clear(); + this.dialog.hide(); + } + + public onCancelClick = () => { + this.dialog.hide(); + } + + public onDeleteRowClick = (rowId: any) => { + this.grid.deleteRow(rowId); + } + +} + +new TreeGridBatchEditingSample(); diff --git a/samples/grids/tree-grid/grid-batch-editing/tsconfig.json b/samples/grids/tree-grid/grid-batch-editing/tsconfig.json new file mode 100644 index 0000000000..e7c370def4 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/tsconfig.json @@ -0,0 +1,41 @@ +{ + "compilerOptions": { + "noImplicitReturns": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "noImplicitAny": true, + "declarationDir": "dist/types", + "moduleResolution": "node", + "declaration": true, + "target": "es2015", + "module": "es2015", + "strict": true, + "strictNullChecks": false, + "baseUrl": ".", + "paths": { + "igniteui-webcomponents-core": [ "node_modules/igniteui-webcomponents-core", "node_modules/@infragistics/igniteui-webcomponents-core" ], + "igniteui-webcomponents-charts": [ "node_modules/igniteui-webcomponents-charts", "node_modules/@infragistics/igniteui-webcomponents-charts" ], + "igniteui-webcomponents-gauges": [ "node_modules/igniteui-webcomponents-gauges", "node_modules/@infragistics/igniteui-webcomponents-gauges" ], + "igniteui-webcomponents-datasources": [ "node_modules/igniteui-webcomponents-datasources", "node_modules/@infragistics/igniteui-webcomponents-datasources" ], + "igniteui-webcomponents-excel": [ "node_modules/igniteui-webcomponents-excel", "node_modules/@infragistics/igniteui-webcomponents-excel" ], + "igniteui-webcomponents-inputs": [ "node_modules/igniteui-webcomponents-inputs", "node_modules/@infragistics/igniteui-webcomponents-inputs" ], + "igniteui-webcomponents-grids": [ "node_modules/igniteui-webcomponents-grids", "node_modules/@infragistics/igniteui-webcomponents-grids" ], + "igniteui-webcomponents-maps": [ "node_modules/igniteui-webcomponents-maps", "node_modules/@infragistics/igniteui-webcomponents-maps" ], + "igniteui-webcomponents-spreadsheet": [ "node_modules/igniteui-webcomponents-spreadsheet", "node_modules/@infragistics/igniteui-webcomponents-spreadsheet" ], + "igniteui-webcomponents-spreadsheet-chart-adapter": [ "node_modules/igniteui-webcomponents-spreadsheet-chart-adapter", "node_modules/@infragistics/igniteui-webcomponents-spreadsheet-chart-adapter" ], + "igniteui-webcomponents-grids/*": [ "node_modules/igniteui-webcomponents-grids/*", "node_modules/@infragistics/igniteui-webcomponents-grids/*" ], + "igniteui-webcomponents-grids/grids": [ "node_modules/igniteui-webcomponents-grids/grids", "node_modules/@infragistics/igniteui-webcomponents-grids/grids" ], + "igniteui-webcomponents-grids/grids/*": [ "node_modules/igniteui-webcomponents-grids/grids/*", "node_modules/@infragistics/igniteui-webcomponents-grids/grids/*" ], + "igniteui-webcomponents-grids/grids/combined": [ "node_modules/igniteui-webcomponents-grids/grids/combined", "node_modules/@infragistics/igniteui-webcomponents-grids/grids/combined" ], + "igniteui-webcomponents-layouts": [ "node_modules/igniteui-webcomponents-layouts", "node_modules/@infragistics/igniteui-webcomponents-layouts" ], + "igniteui-webcomponents-dashboards": [ "node_modules/igniteui-webcomponents-dashboards", "node_modules/@infragistics/igniteui-webcomponents-dashboards" ] + } + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/samples/grids/tree-grid/grid-batch-editing/tslint.json b/samples/grids/tree-grid/grid-batch-editing/tslint.json new file mode 100644 index 0000000000..e3b56e93a1 --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/tslint.json @@ -0,0 +1,54 @@ +{ + "extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"], + "linterOptions": { + "exclude": [ + "node_modules/**/*.ts", + "**/odatajs-4.0.0.js", + "src/images/*.*" + ] + }, + "rules": { + "curly": [false, "ignore-same-line"], + "jsx-no-lambda": false, + "jsx-self-close": false, + "jsx-wrap-multiline": false, + "max-classes-per-file": [true, 10], + "member-ordering": false, + "no-console": false, + "no-string-literal": false, + "no-unused-vars": false, + "no-useless-constructor": false, + "no-trailing-whitespace": false, + "no-var": false, + "no-var-requires": false, + "no-var-keyword": false, + "ordered-imports": false, + "object-literal-sort-keys": false, + "object-literal-shorthand": false, + "only-arrow-functions": false, + "prefer-const": false, + "prefer-for-of": false, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-useless-constructor": "off", + "@typescript-eslint/type-annotation-spacing": "off" + }, + "jsRules": { + "curly": [false, "ignore-same-line"], + "jsx-no-lambda": false, + "jsx-self-close": false, + "jsx-wrap-multiline": false, + "max-classes-per-file": [true, 10], + "no-console": false, + "no-unused-vars": false, + "no-useless-constructor": false, + "no-var-requires": false, + "object-literal-sort-keys": false, + "object-literal-shorthand": false, + "only-arrow-functions": false, + "ordered-imports": false, + "prefer-const": false, + "prefer-for-of": false, + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-useless-constructor": "off" + } + } \ No newline at end of file diff --git a/samples/grids/tree-grid/grid-batch-editing/webpack.config.js b/samples/grids/tree-grid/grid-batch-editing/webpack.config.js new file mode 100644 index 0000000000..0e55b75f1b --- /dev/null +++ b/samples/grids/tree-grid/grid-batch-editing/webpack.config.js @@ -0,0 +1,105 @@ +const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); +const path = require('path'); +const webpack = require('webpack'); + +module.exports = env => { + const nodeEnv = process.env.NODE_ENV || 'development'; + const isProd = nodeEnv === 'production'; + const isLegacy = !!process.env.legacy && !(process.env.legacy == "false"); + console.log(">> webpack nodeEnv=" + nodeEnv); + console.log(">> webpack isProd=" + isProd); + console.log(">> webpack isLegacy=" + isLegacy); + const presets = [ + ["@babel/preset-env", { + "useBuiltIns": "usage", + "corejs": 3, + "targets": { + "browsers": isLegacy ? ["defaults"] : [ + "last 2 Chrome versions", + "last 2 Safari versions", + "last 2 iOS versions", + "last 2 Firefox versions", + "last 2 Edge versions"] + } + }], + "@babel/preset-typescript" + ]; + + return { + entry: isLegacy ? [ + path.resolve(__dirname, 'src') + ] : path.resolve(__dirname, 'src'), + devtool: isProd ? false : 'source-map', + output: { + filename: isProd ? '[fullhash].bundle.js' : '[fullhash].bundle.js', + globalObject: 'this', + path: path.resolve(__dirname, 'dist'), + }, + + resolve: { + mainFields: ['esm2015', 'module', 'main'], + extensions: ['.ts', '.js', '.json'], + plugins: [new TsconfigPathsPlugin({ + configFile: './tsconfig.json', + extensions: ['.ts', '.js'], + mainFields: ['esm2015', 'module', 'main'] + })] + }, + + module: { + rules: [ + { test: /\.(png|svg|jpg|gif)$/, use: ['file-loader'] }, + { test: /\.(csv|tsv)$/, use: ['csv-loader'] }, + { test: /\.xml$/, use: ['xml-loader'] }, + { test: /\.css$/, sideEffects: true, use: ['style-loader', 'css-loader'] }, + { + test: /worker\.(ts|js)$/, + use: [ + { loader: 'worker-loader' }, + { + loader: 'babel-loader', options: { + "compact": isProd ? true : false, + "presets": presets, + "plugins": [ + "@babel/plugin-transform-class-static-block", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-runtime" + ] + } + } + ] + }, + { + test: /\.(ts|js)$/, loader: 'babel-loader', + options: { + "compact": isProd ? true : false, + "presets": presets, + "plugins": [ + "@babel/plugin-transform-class-static-block", + "@babel/plugin-transform-class-properties", + "@babel/plugin-transform-runtime" + ] + }, + exclude: + function (modulePath) { + return /node_modules/.test(modulePath) && + !/igniteui-webcomponents/.test(modulePath) && + !/lit-html/.test(modulePath); + } + }], + }, + + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(nodeEnv) + }), + new HtmlWebpackPlugin({ + title: 'Tree Grid Batch Editing', + template: 'index.html' + }), + new ForkTsCheckerWebpackPlugin() + ] + }; +};