Skip to content

Commit cf9f35a

Browse files
authored
Merge pull request #76 from dkamburov/master
Implement nested Column and Feature directives for IgGrid
2 parents 8e3914e + c05b173 commit cf9f35a

File tree

6 files changed

+319
-10
lines changed

6 files changed

+319
-10
lines changed

index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ <h2>Samples</h2>
208208
<ul class="dropdown-menu" role="menu">
209209
<li><a href="samples/igGrid/igGrid.html">Default</a></li>
210210
<li><a href="samples/igGrid-TopLevelOpts/igGrid-TopLevelOpts.html">Top-level template options</a></li>
211+
<li><a href="samples/igGrid-ComplexOpts/igGrid-ComplexOpts.html">Complex template options</a></li>
211212
</ul>
212213
</div>
213214
<a class="btn btn-default" href="samples/igHierarchicalGrid/igHierarchicalGrid.html">igHierarchicalGrid</a>

samples/igGrid-ComplexOpts/app.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import {Component, Directive, Inject, ElementRef, EventEmitter, HostListener} from '@angular/core';
2+
import {IgGridComponent, Column, Feature} from "../../src/igniteui.angular2.ts";
3+
import {Northwind} from "./../data/northwind.ts";
4+
import {bootstrap } from '@angular/platform-browser-dynamic';
5+
import {FORM_DIRECTIVES} from '@angular/common';
6+
7+
declare var jQuery: any;
8+
9+
@Component({
10+
selector: 'my-app',
11+
templateUrl: "./igGrid-ComplexOptsTemplate.html",
12+
directives: [FORM_DIRECTIVES, IgGridComponent, Column, Feature ]
13+
})
14+
export class AppComponent {
15+
private cols: Array<any>;
16+
private id: string;
17+
private data: any;
18+
private w: string;
19+
private h: string;
20+
private pKey: string;
21+
private isReadOnly: boolean = true;
22+
private cs: Array<any> = [{columnKey: "ProductID", readOnly: this.isReadOnly}];
23+
private pi: number = 0;
24+
private idHeaderText: string = "Id";
25+
private pages: Array<number> = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
26+
27+
constructor() {
28+
this.data = Northwind.getData();
29+
30+
this.id ='grid1';
31+
this.w = '100%';
32+
this.h = '400px';
33+
this.pKey = 'ProductID';
34+
35+
this.cols = [
36+
{ key: "ProductID", headerText: "Product ID", width:"50px", dataType:"number" },
37+
{ key: "ProductName", headerText: "Name", width:"250px", dataType:"string" },
38+
{ key: "QuantityPerUnit", headerText: "Quantity per unit", width:"250px", dataType:"string" },
39+
{ key: "UnitPrice", headerText: "Unit Price", width:"100px", dataType:"number" }
40+
];
41+
}
42+
}
43+
44+
bootstrap(AppComponent);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Angular 2 IgniteUI custom component</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" type="text/css" />
8+
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css" type="text/css" />
9+
<link href="http://cdn-na.infragistics.com/igniteui/latest/css/themes/infragistics/infragistics.theme.css" rel="stylesheet" type="text/css" />
10+
<link href="http://cdn-na.infragistics.com/igniteui/latest/css/structure/infragistics.css" rel="stylesheet" type="text/css" />
11+
<link rel="stylesheet" href="../sample.css" />
12+
13+
</head>
14+
<body class="container">
15+
16+
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
17+
<div class="container">
18+
<div class="navbar-header">
19+
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
20+
<span class="sr-only">Toggle navigation</span>
21+
<span class="icon-bar"></span>
22+
<span class="icon-bar"></span>
23+
<span class="icon-bar"></span>
24+
</button>
25+
<a class="navbar-brand" href="/">Ignite UI Angular 2 components <span class="badge alert-info">Preview</span></a>
26+
</div>
27+
<div class="navbar-collapse collapse">
28+
<ul class="nav navbar-nav">
29+
<li><a href="/igniteui-angular2/index.html">Home</a></li>
30+
<li><a href="https://github.com/IgniteUI/igniteui-angular2">View on GitHub <i class="fa fa-github"></i></a></li>
31+
</ul>
32+
</div>
33+
</div>
34+
</div>
35+
<div>
36+
<h1 class="push-down-md"><a href="http://igniteui.com/grid/overview" target="_blank">igGrid</a></h1>
37+
38+
<div class="row description">
39+
<div class="col-md-12">
40+
<p class="lead">This sample demonstrates how AngularJS components are used to initialize the igGrid complex options though the template.</p>
41+
<p><a href="https://github.com/IgniteUI/igniteui-angular2/blob/master/samples/igGrid/igGrid.html" class="btn btn-default btn-lg btn-primary" target="_blank"><i class="fa fa-code fa-lg"></i> Explore the Code</a></p>
42+
</div>
43+
</div>
44+
45+
<my-app>Loading...</my-app>
46+
47+
48+
</div>
49+
<footer>
50+
<p>
51+
<a href="/igniteui-angular2/index.html">Home</a> |
52+
<a href="https://github.com/IgniteUI/igniteui-angular2/issues">Feedback &amp; Questions</a> |
53+
<a href="https://github.com/IgniteUI/igniteui-angular2">Clone &amp; Fork</a>
54+
</p>
55+
<p class="small">For more information or to download a trial of Ignite UI, please visit: <a href="http://www.igniteui.com">http://www.igniteui.com</a></p>
56+
</footer>
57+
58+
<!-- 1. Load libraries -->
59+
<script src="http://code.jquery.com/jquery-1.12.3.js"></script>
60+
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script>
61+
<!-- IE required polyfills, in this exact order -->
62+
<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.0/es6-shim.min.js"></script>
63+
<script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.20/system-polyfills.js"></script>
64+
<script src="https://npmcdn.com/angular2/es6/dev/src/testing/shims_for_IE.js"></script>
65+
66+
<script src="https://npmcdn.com/[email protected]?main=browser"></script>
67+
<script src="https://npmcdn.com/[email protected]/lib/typescript.js"></script>
68+
<script src="https://npmcdn.com/[email protected]"></script>
69+
<script src="https://npmcdn.com/[email protected]/dist/system.src.js"></script>
70+
<script src="./../../systemjs.config.js"></script>
71+
<!-- Ignite UI Required Combined JavaScript Files -->
72+
<script src="http://cdn-na.infragistics.com/igniteui/latest/js/infragistics.core.js"></script>
73+
<script src="http://cdn-na.infragistics.com/igniteui/latest/js/infragistics.lob.js"></script>
74+
75+
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.js"></script>
76+
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
77+
<script>
78+
System.import('app.ts')
79+
.then(null, console.error.bind(console));
80+
</script>
81+
</body>
82+
</html>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<div class="row">
2+
<div class="col-md-12">
3+
<ig-grid [widgetId]='id' [width]='w' [autoCommit]='true' [dataSource]='data' [height]='h' [autoGenerateColumns]='false' [primaryKey]='"ProductID"'>
4+
<column [key]="'ProductID'" [(headerText)]="idHeaderText" [width]="'165px'" [dataType]="'number'"></column>
5+
<column [key]="'ProductName'" [headerText]="'Product Name'" [width]="'250px'" [dataType]="'string'"></column>
6+
<column [key]="'QuantityPerUnit'" [headerText]="'Quantity per unit'" [width]="'250px'" [dataType]="'string'"></column>
7+
<column [key]="'UnitPrice'" [headerText]="'Unit Price'" [width]="'100px'" [dataType]="'number'"></column>
8+
<feature [name]="'Paging'" [(currentPageIndex)]="pi" [pageSize]="'2'"></feature>
9+
</ig-grid>
10+
11+
<br>
12+
<label for="pageIndex">Current Page Index:</label>
13+
<select [(ngModel)]="pi" name="pageIndex">
14+
<option *ngFor="let i of pages">{{i}}</option>
15+
</select>
16+
<br>
17+
<label for="headerText">First column header text:</label><input name="headerText" [(ngModel)]="idHeaderText">{{idHeaderText}}
18+
</div>
19+
20+
</div>

src/igniteui.angular2.ts

Lines changed: 136 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {Component, Directive, Inject, ElementRef, EventEmitter, Output, Input, Query, QueryList, Renderer, OnChanges, NgZone,
2-
SimpleChange, ChangeDetectionStrategy, IterableDiffers, DoCheck, Optional} from '@angular/core';
2+
SimpleChange, ChangeDetectionStrategy, IterableDiffers, DoCheck, Optional, ContentChildren, AfterContentInit} from '@angular/core';
33
import {NgModel, ControlValueAccessor} from '@angular/common';
44

55
declare var jQuery: any;
@@ -46,6 +46,118 @@ var NODES = {
4646
"ig-tile-manager": "div"
4747
};
4848

49+
module IgUtil {
50+
export function extractAllGridFeatureOptions() {
51+
let allWidgets = jQuery.ui;
52+
let options = ['name'];
53+
let widget: any;
54+
for (widget in allWidgets) {
55+
if (widget.substring(0, 6) === "igGrid" && widget !== "igGrid") {
56+
options = options.concat(Object.keys(jQuery.ui[widget].prototype.options));
57+
}
58+
}
59+
return options;
60+
}
61+
62+
export function extractAllGridColumnProperties() {
63+
return ['headerText', 'key', 'formatter', 'format', 'dataType', 'width', 'hidden', 'template', 'unbound', 'group', 'rowspan', 'formula', 'unboundValues', 'unboundValuesUpdateMode', 'headerCssClass', 'columnCssClass'];
64+
}
65+
}
66+
67+
@Directive({
68+
selector: 'column',
69+
inputs: IgUtil.extractAllGridColumnProperties()
70+
})
71+
export class Column {
72+
public _settings: any = {};
73+
private _el: any;
74+
75+
constructor(el: ElementRef) {
76+
this._el = el;
77+
let self = this;
78+
let i, settings = IgUtil.extractAllGridColumnProperties();
79+
for(i = 0; i < settings.length; i++) {
80+
Object.defineProperty(self, settings[i], {
81+
set: self.createColumnsSetter(settings[i]),
82+
get: self.createColumnsGetter(settings[i]),
83+
enumerable: true,
84+
configurable: true
85+
});
86+
}
87+
}
88+
89+
createColumnsSetter(name) {
90+
return function (value) {
91+
let grid = jQuery(this._el.nativeElement.parentElement).find("table[role='grid']");
92+
this._settings[name] = value;
93+
94+
if (jQuery.ui["igGrid"] &&
95+
jQuery.ui["igGrid"].prototype.options &&
96+
jQuery.ui["igGrid"].prototype.options.hasOwnProperty("columns") &&
97+
grid.data("igGrid")) {
98+
grid["igGrid"]("option", "columns", this._settings);
99+
}
100+
}
101+
}
102+
103+
createColumnsGetter(name) {
104+
return function () {
105+
return this._settings[name];
106+
}
107+
}
108+
}
109+
110+
@Directive({
111+
selector: 'feature',
112+
inputs: IgUtil.extractAllGridFeatureOptions()
113+
})
114+
115+
export class Feature {
116+
private _el: any;
117+
public _settings: any = {};
118+
public initSettings: {};
119+
private name: string;
120+
121+
constructor(el: ElementRef) {
122+
this._el = el;
123+
}
124+
125+
ngOnInit() {
126+
var self = this;
127+
this.initSettings = jQuery.extend(true, {}, this);
128+
let featureName = "igGrid" + this.name;
129+
for (var setting in jQuery.ui[featureName].prototype.options) {
130+
Object.defineProperty(self, setting, {
131+
set: self.createFeatureSetter(setting),
132+
get: self.createFeatureGetter(setting),
133+
enumerable: true,
134+
configurable: true
135+
});
136+
}
137+
}
138+
139+
createFeatureSetter(name) {
140+
return function (value) {
141+
let grid = jQuery(this._el.nativeElement.parentElement).find("table[role='grid']");
142+
let featureName = "igGrid" + this.name;
143+
this._settings[name] = value;
144+
145+
if (jQuery.ui[featureName] &&
146+
jQuery.ui[featureName].prototype.options &&
147+
jQuery.ui[featureName].prototype.options.hasOwnProperty(name) &&
148+
grid.data(featureName)) {
149+
grid[featureName]("option", name, value);
150+
}
151+
}
152+
}
153+
154+
createFeatureGetter(name) {
155+
return function () {
156+
return this._settings[name];
157+
}
158+
}
159+
}
160+
49161
export function IgComponent(args: any = {}) {
50162

51163
return function (cls) {
@@ -66,7 +178,7 @@ export function IgComponent(args: any = {}) {
66178
});
67179

68180
var evt = [];
69-
var opts = [];
181+
var opts = ["options", "widgetId", "changeDetectionInterval"];
70182
if (jQuery.ui[contrName]) {
71183
for (var propt in jQuery.ui[contrName].prototype.events) {
72184
evt.push(propt);
@@ -86,16 +198,16 @@ export function IgComponent(args: any = {}) {
86198
}
87199

88200
export class IgControlBase<Model> implements DoCheck {
89-
private _opts: any = {};
90201
private _differs: any;
202+
protected _opts: any = {};
91203
protected _el: any;
92204
protected _widgetName: string;
93205
protected _differ: any;
94206
protected _config: any;
95207
protected _events: Map<string, string>;
96208
protected _allowChangeDetection = true;
97209

98-
@Input() set options(v: Model) {
210+
set options(v: Model) {
99211
this._config = jQuery.extend(true, v, this._opts);
100212
if (this._opts.dataSource) {
101213
// _config.dataSource should reference the data if the data is set as a top-level opts
@@ -108,8 +220,8 @@ export class IgControlBase<Model> implements DoCheck {
108220
delete this._opts.dataSource;
109221
}
110222
};
111-
@Input() widgetId: string;
112-
@Input() changeDetectionInterval: number;
223+
public widgetId: string;
224+
public changeDetectionInterval: number;
113225

114226
constructor(el: ElementRef, renderer: Renderer, differs: IterableDiffers) {
115227
this._differs = differs;
@@ -132,11 +244,13 @@ export class IgControlBase<Model> implements DoCheck {
132244
createSetter(name) {
133245
return function (value) {
134246
this._opts[name] = value;
247+
if (this._config) {
248+
this._config[name] = value;
249+
}
135250
if (jQuery.ui[this._widgetName] &&
136251
jQuery.ui[this._widgetName].prototype.options &&
137252
jQuery.ui[this._widgetName].prototype.options.hasOwnProperty(name) &&
138253
jQuery(this._el).data(this._widgetName)) {
139-
this._config[name] = value;
140254
jQuery(this._el)[this._widgetName]("option", name, value);
141255
}
142256
}
@@ -300,15 +414,28 @@ export class IgControlBase<Model> implements DoCheck {
300414
}
301415
}
302416

303-
export class IgGridBase<Model> extends IgControlBase<Model> {
417+
export class IgGridBase<Model> extends IgControlBase<Model> implements AfterContentInit {
304418
protected _dataSource: any;
305419
protected _changes: any;
420+
@ContentChildren(Column) _columns: QueryList<Column>;
421+
@ContentChildren(Feature) _features: QueryList<Feature>;
306422

307423
constructor(el: ElementRef, renderer: Renderer, differs: IterableDiffers) { super(el, renderer, differs); }
308424

309425
ngOnInit() {
426+
this._dataSource = this._opts.dataSource ?
427+
JSON.parse(JSON.stringify(this._opts.dataSource)) :
428+
JSON.parse(JSON.stringify(this._config.dataSource));
429+
}
430+
431+
ngAfterContentInit() {
432+
if (this._columns.length) {
433+
this._opts["columns"] = this._columns.map((c) => c._settings);
434+
}
435+
if (this._features.length) {
436+
this._opts["features"] = this._features.map((c) => c.initSettings);
437+
}
310438
super.ngOnInit();
311-
this._dataSource = JSON.parse(JSON.stringify(this._config.dataSource));
312439
}
313440

314441
deleteRow(id) {

0 commit comments

Comments
 (0)