<!DOCTYPE html>
<html>
<head>
<title>Angular2-bound Kendo Grid Template Column</title>
<script data-require="jquery@*" data-semver="2.2.0" src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script data-require="bootstrap@*" data-semver="3.3.6" src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="style.css" />
<link data-require="bootstrap-css@*" data-semver="3.3.6" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.css" />
<link data-require="font-awesome@*" data-semver="4.5.0" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.css" />
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.1.226/styles/kendo.common.min.css" />
<link rel="stylesheet" href="http://kendo.cdn.telerik.com/2016.1.226/styles/kendo.flat.min.css" />
<link rel="stylesheet" href="style.css" />
<script src="https://code.angularjs.org/2.0.0-beta.0/angular2-polyfills.js"></script>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="config.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.0/Rx.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.0/angular2.min.js"></script>
<script src="https://code.angularjs.org/2.0.0-beta.0/http.min.js"></script>
<script src="http://kendo.cdn.telerik.com/2016.1.226/js/kendo.all.min.js"></script>
<script>
System.import('app')
.catch(console.error.bind(console));
</script>
</head>
<body>
<my-app>
loading...
</my-app>
</body>
</html>
/* Stylings to allow for dropdown to appear outside of grid cell */
/*
This creates column alignment issues...suggestions welcome!
*/
.k-grid-content {
overflow: visible;
}
.k-grid-content td {
overflow: visible;
text-align: center;
}
.k-grid-header th,
.k-filter-row > th {
border-bottom-width: 0;
text-align: center;
overflow: visible
}
.k-grid-header-wrap,
.k-grid-footer-wrap {
overflow: visible;
}
### Kendo Grid templated column, bound by Angular 2
Click the blue action buttons in the right column to see the Kendo Grid rows' Unique Id (uid) values appear in the console
NOTICE: This is a proof of concept, and it may have performance issue or go against Angualr 2 or TypeScript best practices
If you find errors or have suggestions, please e-mail aaronjessen[at]gmail.com tweet to @aaronjessen
System.config({
//use typescript for compilation
transpiler: 'typescript',
//typescript compiler options
typescriptOptions: {
emitDecoratorMetadata: true
},
//map tells the System loader where to look for things
map: {
app: "./src"
},
//packages defines our app package
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
}
}
});
//main entry point
import {DynamicComponentLoader} from 'angular2/core';
import {FORM_PROVIDERS} from 'angular2/common';
import {bootstrap} from 'angular2/platform/browser';
import {App} from './app';
bootstrap(App, [])
.catch(err => console.error(err));
//our root app component
import {Component, DynamicComponentLoader, ElementRef, OnInit, View} from 'angular2/core'
import {KendoGridExample} from './kendo-grid-example';
@Component({
selector: 'my-app',
providers: [],
template: `
<div style="padding: 0 15px;">
<h2>ng2-bound Kendo Grid Template Column</h2>
<h4>Click the actions in the column dropdown and watch the row's unique id (uid) appear in the Output log</h4>
<kendo-grid-example></kendo-grid-example>
<div class="alert alert-info"
style="margin: 15px 0; overflow-y: scroll; height: 200px;">
<h4>Output (newest on top)</h4>
<div id="log"></div>
</div>
`,
directives: [KendoGridExample]
})
export class App {
constructor() {
//
}
}
import {AfterViewInit, Component, DynamicComponentLoader, ElementRef} from 'angular2/core'
import {CustomActionDropdown} from './custom-action-dropdown';
/**
* Main Kendo Grid Component
*/
@Component({
directives: [ CustomActionDropdown /* templated column dropdown */ ],
selector: 'kendo-grid-example',
template: ``
})
export class KendoGridExample implements AfterViewInit {
_that = this;
/**
* Static array of items for the grid
* TODO: Declare dynamic Kendo DataSource inside of an Angular 2 Service
*/
customers:Array<any> = [
{
_id: 1,
firstName: 'Tom',
lastName: 'Williams'
},
{
_id: 2,
firstName: 'Sally',
lastName: 'Smith'
},
{
_id: 3,
firstName: 'Joe',
lastName: 'Johnson'
}
];
/**
* Here's an extensive collection of grid settings, if you're interested
*/
gridOptions = {
autoBind: true,
columns: [
{
field: '_id',
filterable: false,
hidden: false,
title: 'ID',
width: '10%'
},
{
field: 'firstName',
filterable: {
cell: {
dataTextField: 'year',
delay: 0,
enabled: true,
minLength: 0,
operator: 'contains',
showOperators: true,
suggestionOperator: 'contains'
},
extra: true,
mode: 'menu, row'
},
title: 'First Name',
width: '25%'
},
{
field: 'lastName',
filterable: {
cell: {
delay: 0,
enabled: true,
minLength: 0,
operator: 'contains',
showOperators: true,
suggestionOperator: 'contains'
}
},
title: 'Last Name',
width: '45%'
},
{
attributes: {
class: 'grid-action-column'
},
template: ``,
title: 'Actions',
width: '10%'
}
],
columnMenu: {
columns: false,
filterable: true,
messages: {
columns: 'Choose Columns',
filter: 'Apply Filter',
sortAscending: 'Sort Ascending',
sortDescending: 'Sort Descending'
},
sortable: true
},
dataSource: {
data: this.customers,
pageSize: 5 // setting pageSize inside the dataSource prevents "NaNn-NaN of 3" for paging
},
dataBound: this.gridDataBound.bind(this._that), // bind the local 'this' scope (is this kosher?)
editable: {
confirmation: 'Are you sure you want to drop this prospect?',
createAt: 'top',
destroy: true,
mode: 'popup', // inline | incell | popup
update: true
},
filterable: {
//extra: true,
messages: {
and: 'and',
or: 'or',
filter: 'Apply Filter',
clear: 'Clear Filter',
isFalse: 'False',
isTrue: 'True',
selectValue: 'Select'
},
mode: 'row'
},
groupable: true,
messages: {
filterempty: 'The applied filter has returned 0 results.'
},
mobile: {
return false;
},
navigatable: false,
pageable: {
buttonCount: 5,
info: true,
input: true,
messages: {
display: 'Showing {0}-{1} of {2} prospects',
empty: 'No listings available for display',
first: 'First page',
itemsPerPage: 'prospects per page',
last: 'Last page',
next: 'Next page',
of: 'of {0}',
previous: 'Previous Page',
page: 'Go to',
refresh: 'Refresh the grid'
},
pageSizes: [1, 5, 10, 15, 20],
previousNext: true,
numeric: false,
refresh: true
},
pageSize: 5,
remove: function (e) {
//console.log('removing', e.model.firstName);
},
save: function (e) {
//
},
saveChanges: function (e) {
if (!confirm('Are you sure you want to save all changes?')) {
e.preventDefault();
}
},
scrollable: {
virtual: false,
},
selectable: 'multiple, row',
sortable: {
allowUnsort: true,
mode: 'multiple'
}
};
/**
* Pass in the elementRef and dynamic component loader for binding the column template
*/
constructor(public elementRef:ElementRef, public loader:DynamicComponentLoader) {
}
/**
* Instantite the grid using jQuery
* Note: This also works appears to work inside ngOnInit()
*/
ngAfterViewInit() {
// use jQuery to create the Kendo Grid as usual
jQuery(this.elementRef.nativeElement).kendoGrid(this.gridOptions);
}
/**
* Kendo-UI type definitions for GridDataBoundEvent available from
* https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/kendo-ui
*/
gridDataBound(e: GridDataBoundEvent) {
//var columns = e.sender.columns; // showing one way to access columns
/*
Search for the index of the template column by class name
(which is assigned inside this.gridOptions' columns declaration)
*/
var actionColumnIndex = e.sender.wrapper.find('.grid-action-column').index();
var rows = e.sender.tbody.children();
/*
Iterate through the rows to bind the template column with a dynamic loader
(is this a performance issue for large datasets?)
*/
$.each(rows, (index, item) => {
var row = jQuery(item);
var dataItem = e.sender.dataItem(row);
var cell = row.children('td').eq(actionColumnIndex);
/*
Use the DynamicComponentLoader to load the CustomActionDropdown Component
inside of the grid cells
*/
this.loader.loadNextToLocation(CustomActionDropdown, this.elementRef)
.then((result) => {
/*
Example showing how to access methods on the templated Component.
For this example, it's passing in the row's uid to the setUid()
method of the CustomActionDropdown Component
*/
result.instance.setUid(dataItem.uid);
// append the action button to the grid cell
cell.append(result.location.nativeElement);
});
});
}
}
import {Component, OnInit, View} from 'angular2/core'
/**
* Example of a templated grid column with access to Component event functions
**/
@Component({
selector: 'action-bar'
})
@View({
/**
* Templated dropown with click events tied to Component functions
*/
template: `
<div class="dropdown">
<button class="btn btn-default dropdown-toggle"
type="button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="true">
<i class="fa fa-cog"></i>
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right"
aria-labelledby="dropdownMenu1">
<li class="dropdown-header">Customer Actions</li>
<li>
<a href="#"
(click)="contactCustomer($event)">
<i class="fa fa-user"></i> Contact
</a>
</li>
<li>
<a href="#"
(click)="editCustomer($event)">
<i class="fa fa-pencil"></i> Edit
</a>
</li>
<li role="separator" class="divider"></li>
<li>
<a href="#"
(click)="removeCustomer($event)">
<i class="fa fa-times"></i> Remove
</a>
</li>
</ul>
</div>
`
})
export class CustomActionDropdown implements OnInit {
public uid:string;
constructor() {
//
}
// receives and stores the grid row's unique id (uid) for later use
setUid(uid) {
this.uid = uid;
}
ngOnInit() {
//
}
/**
* Contact Customer
* Event triggered by the button in the grid's template column
*/
contactCustomer(e) {
console.log('Contact Customer UID:', this.uid);
$('#log').html(`<i class="fa fa-user"></i> Contact Customer UID: ${this.uid} </br/>` + $('#log').html());
}
/**
* Edit Customer
*/
editCustomer(e) {
console.log('Edit Customer UID:', this.uid);
$('#log').html(`<i class="fa fa-pencil"></i> Edit Customer UID: ${this.uid} </br/>` + $('#log').html());
}
/**
* Remove Customer
*/
removeCustomer(e) {
console.log('Remove Customer UID:', this.uid);
$('#log').html(`<i class="fa fa-times"></i> Remove Customer UID: ${this.uid} </br/>` + $('#log').html());
}
}