From b3fea0d999ae8d2a77eb1360841fe7df836f5378 Mon Sep 17 00:00:00 2001 From: Deyan Kamburov Date: Fri, 3 Feb 2017 17:46:43 +0200 Subject: [PATCH] Recreate the component if new set of options are being applied --- README.md | 45 +++ samples/igDataChart/app.ts | 30 ++ samples/igDataChart/igDataChartTemplate.html | 6 +- src/igniteui.angular2.ts | 19 +- tests/unit/igdatachart/chart.spec.ts | 46 ++- tests/unit/iggrid/grid.spec.ts | 364 +++++++++++++------ 6 files changed, 383 insertions(+), 127 deletions(-) diff --git a/README.md b/README.md index 6f1c97a..611b36b 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,51 @@ when there are overlapping properties. Also changing top-level attribute will ap } } +### Aply new set of Control Options + +In order to change the more options at once (or recreate the component with another set of options), the new configuration can be applied to the `options` property. + +#### Example: + + @Component({ + selector: 'my-app', + template: ``, + directives: [IgGridComponent] + }) + export class AppComponent { + private gridOptions: IgGrid; + private id: string; + private data: any; + + constructor() { + this.data = Northwind.getData(); + this.id ='grid1'; + this.gridOptions = { + dataSource: this.data, + width: "100%", + height: "400px", + autoGenerateColumns: true + }; + } + + recreateGrid() { + this.gridOptions = { + dataSource: Northwind.getAnotherData(), + width: "700px", + autoGenerateColumns: true, + features: [ + { name: "Paging" } + ] + }; + } + } + +In this example `options` attribute points to `gridOptions` and changing in reference will destroy the grid, combine the old options with new ones and create the grid with the combined options. +Also note that the new grid will have height of 400px, even though it's not defined into the new options, because of the combination with new options. +If disabling an option is required set it to `null`, `undefined`, `[]` or `{}`. + ### Handling events Binding to control events is achieved by assigning attributes where the name of the attribute is the name of the control's event name surrounded by parenthesis and the value is the name of the event handler. diff --git a/samples/igDataChart/app.ts b/samples/igDataChart/app.ts index 4fc75f3..ad88468 100644 --- a/samples/igDataChart/app.ts +++ b/samples/igDataChart/app.ts @@ -45,6 +45,36 @@ export class AppComponent { target: "#datachart1" }; } + + changeZB() { + let opts = {}; + + opts = { + target: "#datachart1", + clone: { + dataSource: this.data, + gridMode: "none", + axes: [{ + name: "NameAxis", + type: "categoryX", + labelVisibility: "collapsed" + }, + { + name: "PopulationAxis", + type: "numericY", + labelVisibility: "collapsed" + }], + series: [{ + name: "2015Population", + type: "line", + xAxis: "NameAxis", + yAxis: "PopulationAxis", + valueMemberPath: "Pop2015" + }] + } + }; + this.zoombarOptions = opts; + } } @NgModule({ diff --git a/samples/igDataChart/igDataChartTemplate.html b/samples/igDataChart/igDataChartTemplate.html index 3437498..ba75b1d 100644 --- a/samples/igDataChart/igDataChartTemplate.html +++ b/samples/igDataChart/igDataChartTemplate.html @@ -1,2 +1,4 @@ - - \ No newline at end of file + + +
+ \ No newline at end of file diff --git a/src/igniteui.angular2.ts b/src/igniteui.angular2.ts index cccd6e2..81f6305 100644 --- a/src/igniteui.angular2.ts +++ b/src/igniteui.angular2.ts @@ -209,13 +209,20 @@ export class IgControlBase implements DoCheck { protected _allowChangeDetection = true; set options(v: Model) { - this._config = jQuery.extend(true, v, this._opts); - if (this._opts.dataSource) { - // _config.dataSource should reference the data if the data is set as a top-level opts - // to allow two-way data binding - this._config.dataSource = this._opts.dataSource; + if (this._config !== undefined && this._config !== null) { + //if the options are alrealy set recreate the component + jQuery(this._el)[this._widgetName]("destroy"); + this._config = jQuery.extend(false, this._config, v); + jQuery(this._el)[this._widgetName](this._config); + } else { + this._config = jQuery.extend(true, v, this._opts); + if (this._opts.dataSource) { + // _config.dataSource should reference the data if the data is set as a top-level opts + // to allow two-way data binding + this._config.dataSource = this._opts.dataSource; + } + this._differ = this._differs.find([]).create(null); } - this._differ = this._differs.find([]).create(null); this._opts = jQuery.extend(true, {}, this._config); if (this._opts.dataSource) { delete this._opts.dataSource; diff --git a/tests/unit/igdatachart/chart.spec.ts b/tests/unit/igdatachart/chart.spec.ts index ece89b8..15ff3e7 100644 --- a/tests/unit/igdatachart/chart.spec.ts +++ b/tests/unit/igdatachart/chart.spec.ts @@ -28,6 +28,24 @@ export function main() { }); }); + it('should recreate correctly', (done) => { + var template = '
'; + TestBed.overrideComponent(TestComponent, { + set: { + template: template + } + }); + TestBed.compileComponents().then(() => { + let fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + fixture.componentInstance.opts = fixture.componentInstance.opts1; + fixture.detectChanges(); + expect($(fixture.debugElement.nativeElement).find("#datachart1").igDataChart("option", "series")[0].type) + .toBe("line"); + done(); + }); + }); + it('Zoombar should initialize correctly', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { @@ -51,7 +69,8 @@ export function main() { template: '
' //"Component 'TestComponent' must have either 'template' or 'templateUrl' set." }) class TestComponent { - private opts: any; + public opts: any; + public opts1: any; private zoombarOpts: any; private data: Array; private cdi: number; @@ -91,6 +110,31 @@ class TestComponent { valueMemberPath: "Pop2015" }] }; + + this.opts1 = { + dataSource: this.data, + axes: [{ + name: "NameAxis", + type: "categoryX", + title: "Country", + label: "CountryName" + }, + { + name: "PopulationAxis", + type: "numericY", + minimumvalue: 0, + title: "Milions of People" + }], + series: [{ + name: "2015Population", + type: "line", + isHighlightingEnabled: true, + isTransitionInEnabled: true, + xAxis: "NameAxis", + yAxis: "PopulationAxis", + valueMemberPath: "Pop2015" + }] + }; this.zoombarOpts = { target: "#datachart1" }; diff --git a/tests/unit/iggrid/grid.spec.ts b/tests/unit/iggrid/grid.spec.ts index c9df792..61229e4 100644 --- a/tests/unit/iggrid/grid.spec.ts +++ b/tests/unit/iggrid/grid.spec.ts @@ -15,26 +15,53 @@ export function main() { it('should initialize correctly', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) .toBe(true); - done(); + done(); + }); + }); + + it('should recreate correctly when setting new set of options', (done) => { + var template = '
'; + TestBed.overrideComponent(TestComponent, { + set: { + template: template + } + }); + TestBed.compileComponents().then(() => { + let fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + fixture.componentInstance.opts = fixture.componentInstance.opts2; + fixture.detectChanges(); + + expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridFiltering") !== undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridUpdating") === undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container").height() === 400) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container tr[data-header-row] th").length) + .toBe(2); + done(); }); }); it('should initialize correctly using top level options ', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -44,13 +71,43 @@ export function main() { }); }); + it('should recreate correctly when there are top level options ', (done) => { + var template = '
'; + TestBed.overrideComponent(TestComponent, { + set: { + template: template + } + }); + TestBed.compileComponents().then(() => { + let fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) + .toBe(true); + + fixture.componentInstance.opts = fixture.componentInstance.opts2; + fixture.detectChanges(); + + expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridFiltering") !== undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridUpdating") === undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container").height() === 400) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container tr[data-header-row] th").length) + .toBe(2); + done(); + }); + }); + it('should initialize correctly with both approaches - top level and default', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -65,10 +122,10 @@ export function main() { it('should allow changing top level options', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -85,10 +142,10 @@ export function main() { it('should detect and apply changes from model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -96,7 +153,7 @@ export function main() { setTimeout(() => { fixture.detectChanges(); expect($(fixture.debugElement.nativeElement).find("#grid1 tr:first td[aria-describedby='grid1_Name']").text()) - .toBe("Mr. Smith"); + .toBe("Mr. Smith"); done(); }, 10); }); @@ -105,18 +162,18 @@ export function main() { it('should detect and apply deleting records from model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); - fixture.componentInstance.data.splice(2,1); + fixture.componentInstance.data.splice(2, 1); setTimeout(() => { fixture.detectChanges(); expect($(fixture.debugElement.nativeElement).find("#grid1 tbody tr").length) - .toBe(2); + .toBe(2); done(); }, 10); }); @@ -125,10 +182,10 @@ export function main() { it('should detect and apply adding records from model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -136,7 +193,7 @@ export function main() { setTimeout(() => { fixture.detectChanges(); expect($(fixture.debugElement.nativeElement).find("#grid1 tbody tr").length) - .toBe(4); + .toBe(4); done(); }, 10); }); @@ -145,10 +202,10 @@ export function main() { it('should detect and apply changes to model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -156,7 +213,7 @@ export function main() { $(fixture.debugElement.nativeElement).find("#grid1").igGridUpdating("setCellValue", 2, "Name", "Mary Jackson"); $(fixture.debugElement.nativeElement).find("#grid1_container #grid1_updating_done").click(); expect(fixture.debugElement.componentInstance.data[1].Name) - .toBe("Mary Jackson"); + .toBe("Mary Jackson"); done(); }); }); @@ -164,16 +221,16 @@ export function main() { it('should detect and apply deleting records to model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); $(fixture.debugElement.nativeElement).find("#grid1").igGridUpdating("deleteRow", 2); expect(fixture.debugElement.componentInstance.data.length) - .toBe(2); + .toBe(2); done(); }); }); @@ -181,16 +238,16 @@ export function main() { it('should detect and apply adding records to model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); $(fixture.debugElement.nativeElement).find("#grid1").igGridUpdating("addRow", { "Id": 4, "Name": "Bob Ferguson", "Age": 33 }); expect(fixture.debugElement.componentInstance.data.length) - .toBe(4); + .toBe(4); done(); }); }); @@ -198,10 +255,10 @@ export function main() { it('should allow defining events', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -221,10 +278,10 @@ export function main() { it('should allow changing options', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -232,7 +289,7 @@ export function main() { setTimeout(() => { fixture.detectChanges(); expect($(fixture.debugElement.nativeElement).find("#grid1_container").outerHeight()) - .toBe(400); + .toBe(400); done(); }, 10); }); @@ -241,10 +298,10 @@ export function main() { it('should allow column templates', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -252,7 +309,7 @@ export function main() { setTimeout(() => { fixture.detectChanges(); expect($(fixture.debugElement.nativeElement).find("#grid1 tr[data-id='1'] td[aria-describedby='grid1_Age']").text()) - .toBe("Age: 42"); + .toBe("Age: 42"); done() }, 10); }); @@ -261,10 +318,10 @@ export function main() { it('should detect and apply changes of date columns to model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -272,18 +329,18 @@ export function main() { $(fixture.debugElement.nativeElement).find("#grid1").igGridUpdating("setCellValue", 2, "HireDate", "11/11/2016"); $(fixture.debugElement.nativeElement).find("#grid1_container #grid1_updating_done").click(); expect(fixture.debugElement.componentInstance.data[1].HireDate.getTime()) - .toBe(new Date("11/11/2016").getTime()); + .toBe(new Date("11/11/2016").getTime()); done(); }); }); - + it('should detect and apply changes of dates columns from model', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -291,7 +348,7 @@ export function main() { setTimeout(() => { fixture.detectChanges(); expect($(fixture.debugElement.nativeElement).find("#grid1 tr:first td[aria-describedby='grid1_HireDate']").text()) - .toBe("11/11/2016"); + .toBe("11/11/2016"); done(); }, 10); }); @@ -303,12 +360,12 @@ export function main() { "" + "" + "" + - ""; + ""; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -336,12 +393,12 @@ export function main() { "" + "" + "" + - ""; + ""; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); @@ -363,26 +420,88 @@ export function main() { }); }); + it('should recreate the grid when there are nested directives with options', (done) => { + var template = "" + + "" + + "" + + "" + + "" + + ""; + TestBed.overrideComponent(TestComponent, { + set: { + template: template + } + }); + TestBed.compileComponents().then(() => { + let fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + fixture.componentInstance.opts1 = fixture.componentInstance.opts2; + fixture.detectChanges(); + + expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridFiltering") !== undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridPaging") === undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container").height() === 400) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container tr[data-header-row] th").length) + .toBe(2); + done(); + }); + }); + + it('should recreate the grid when there are nested directives with options(No change)', (done) => { + var template = "" + + "" + + "" + + "" + + "" + + ""; + TestBed.overrideComponent(TestComponent, { + set: { + template: template + } + }); + TestBed.compileComponents().then(() => { + let fixture = TestBed.createComponent(TestComponent); + fixture.detectChanges(); + fixture.componentInstance.opts1 = fixture.componentInstance.opts3; + fixture.detectChanges(); + + expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1").data("igGridPaging") !== undefined) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container").height() === 400) + .toBe(true); + expect($(fixture.debugElement.nativeElement).find("#grid1_container tr[data-header-row] th").length) + .toBe(3); + done(); + }); + }); + it('should allow filtering after new data is applied', (done) => { var template = '
'; TestBed.overrideComponent(TestComponent, { - set: { - template: template - } - }); + set: { + template: template + } + }); TestBed.compileComponents().then(() => { let fixture = TestBed.createComponent(TestComponent); fixture.detectChanges(); expect(fixture.debugElement.componentInstance.viewChild instanceof Infragistics.IgGridComponent) .toBe(true); fixture.componentInstance.data1 = [ - {"Id":"4", "Date":"\/Date(1235088000000)\/"}, - {"Id":"5", "Date":"\/Date(1250809200000)\/"}, - {"Id":"6", "Date":"\/Date(1335394800000)\/"} + { "Id": "4", "Date": "\/Date(1235088000000)\/" }, + { "Id": "5", "Date": "\/Date(1250809200000)\/" }, + { "Id": "6", "Date": "\/Date(1335394800000)\/" } ]; setTimeout(() => { fixture.detectChanges(); - $(fixture.debugElement.nativeElement).find("#grid1").igGridFiltering("filter", ([{fieldName: "Date", expr: "\/Date(704678400000)\/", cond: "notOn"}])); + $(fixture.debugElement.nativeElement).find("#grid1").igGridFiltering("filter", ([{ fieldName: "Date", expr: "\/Date(704678400000)\/", cond: "notOn" }])); expect($(fixture.debugElement.nativeElement).find("#grid1_container .ui-iggrid-results").text()) .toBe("3 matching records"); done(); @@ -397,9 +516,10 @@ export function main() { template: '
' //"Component 'TestComponent' must have either 'template' or 'templateUrl' set." }) class TestComponent { - private opts: any; + public opts: any; public opts1: any; public opts2: any; + public opts3: any; private gridID: string; public data: Array; public data1: Array; @@ -417,16 +537,16 @@ class TestComponent { this.idHeaderText = "Product Id"; this.pi = 1; this.data = [ - { "Id": 1, "Name": "John Smith", "Age": 45, "HireDate": "\/Date(704678400000)\/" }, - { "Id": 2, "Name": "Mary Johnson", "Age": 32, "HireDate": "\/Date(794678400000)\/" }, - { "Id": 3, "Name": "Bob Ferguson", "Age": 27, "HireDate": "\/Date(834678400000)\/" } - ]; + { "Id": 1, "Name": "John Smith", "Age": 45, "HireDate": "\/Date(704678400000)\/" }, + { "Id": 2, "Name": "Mary Johnson", "Age": 32, "HireDate": "\/Date(794678400000)\/" }, + { "Id": 3, "Name": "Bob Ferguson", "Age": 27, "HireDate": "\/Date(834678400000)\/" } + ]; this.data1 = [ - {"Id":"1", "Date":"\/Date(1250809200000)\/"}, - {"Id":"2", "Date":"\/Date(1335394800000)\/"}, - {"Id":"3", "Date":"\/Date(1235088000000)\/"} + { "Id": "1", "Date": "\/Date(1250809200000)\/" }, + { "Id": "2", "Date": "\/Date(1335394800000)\/" }, + { "Id": "3", "Date": "\/Date(1235088000000)\/" } ]; - this.opts = { + this.opts = { primaryKey: "Id", dataSource: this.data, autoCommit: true, @@ -452,25 +572,33 @@ class TestComponent { ] }; + this.opts3 = { + width: "100%", + height: "400px", + autoCommit: true, + autoGenerateColumns: false, + primaryKey: "Id" + }; + this.opts2 = { - width: "100%", - height: "400px", - autoCommit: true, - autoGenerateColumns: false, - columns: [ - { key: "Id", headerText: "ID", width: "20%", dataType: "string" }, - { key: "Date", headerText: "Date", dataType: "date", width: "80%", format: "dd/MM/yyyy" }, - ], - primaryKey: "Id", - features: [ - { - name: "Filtering", - type: "local", - mode: "simple", - filterDialogContainment: "window" - } - ] - }; + width: "100%", + height: "400px", + autoCommit: true, + autoGenerateColumns: false, + columns: [ + { key: "Id", headerText: "ID", width: "20%", dataType: "string" }, + { key: "Date", headerText: "Date", dataType: "date", width: "80%", format: "dd/MM/yyyy" }, + ], + primaryKey: "Id", + features: [ + { + name: "Filtering", + type: "local", + mode: "simple", + filterDialogContainment: "window" + } + ] + }; } public cellClickHandler(evt) {