title | page_title | description | slug | position |
---|---|---|---|---|
Grid Settings and Usage |
Grid Settings and Usage | AngularJS Directives |
Learn the tips and tricks about how to use Kendo UI Grid widget in AngularJS. |
grid_settings_angularjs_directives |
4 |
The Grid is one of the most complex Kendo UI widgets. This article outlines some of its particularities regarding the AngularJS integration supported by Kendo UI.
Important
AngularJS evaluates a template expression placed as
column.title
content. To avoid this behavior, set ang-non-bindable
attribute through theheaderAttributes
so that AngularJS skips the expression evaluation.
The example below demonstrates how to use the headerAttributes
to prevent the execution of expressions inside the title content.
<div id="example" ng-app="KendoDemos">
<div ng-controller="MyCtrl">
<kendo-grid options="mainGridOptions">
</kendo-grid>
</div>
</div>
<script>
angular.module("KendoDemos", [ "kendo.directives" ])
.controller("MyCtrl", function($scope){
$scope.mainGridOptions = {
dataSource: {
type: "odata",
transport: {
read: "//demos.telerik.com/kendo-ui/service/Northwind.svc/Employees"
}
},
columns: [{
field: "FirstName",
title: "First Name {% raw %}{{1+1}}{% endraw %}",
headerAttributes: {"ng-non-bindable": true},
width: "180px"
},{
field: "LastName",
title: "Last Name",
width: "120px"
},{
field: "Country",
width: "120px"
},{
field: "City",
width: "120px"
}]
};
});
</script>
If you assign a k-on-change
event handler, it is evaluated in a scope, which contains additional local variables:
kendoEvent
—Thechange
event as triggered by Kendo UI.selected
—The selected elements (a jQuery object).data
—The selected data items (an array of models).
Important
The
selected
object is a jQuery one which references DOM elements. As of AngularJS 1.2.24 release this is disallowed in template expressions "for security reasons". Therefore, the following will not work with Angular 1.2.24:k-on-change="myChangeHandler(selected)"
The workaround is to pass it in an object or in an array. For example:
k-on-change="myChangeHandler({ selected: selected })"
Obviously, the handler function needs to take that into account.
When the Grid is not in a multiple selection mode, the data
above will not be an array, but a single data item, and that item is also accessible as dataItem
. When the cell selection is allowed, an additional columns
variable is present. This variable is an array containing the indexes of the columns where cells are selected. Choose the grid's selection mode and then select items from the grid and see what variables are available.
The example below demonstrates how to handle the change
event in AngularJS.
<div ng-app="app" ng-controller="MyCtrl">
<label>Select mode: <select kendo-dropdownlist ng-model="gridOptions.selectable">
<option value="row">Row</option>
<option value="cell">Cell</option>
<option value="multiple, row">Multiple, row</option>
<option value="multiple, cell">Multiple, cell</option>
</select></label>
<div kendo-grid k-options="gridOptions" k-rebind="gridOptions.selectable"
k-on-change="handleChange(data, dataItem, columns)"></div>
<pre>
data: {% raw %}{{ data | json }}{% endraw %}
columns: {% raw %}{{ columns | json }}{% endraw %}
<span ng-show="gridOptions.selectable == 'row' || gridOptions.selectable == 'cell'">DataItem: {% raw %}{{ dataItem | json }}{% endraw %}</span>
</pre>
</div>
<script>
angular.module("app", ["kendo.directives"]).controller("MyCtrl", function($scope) {
var data = new kendo.data.DataSource({
data: [
{ text: "Foo", id: 1 },
{ text: "Bar", id: 2 },
{ text: "Baz", id: 3 }
]
});
$scope.handleChange = function(data, dataItem, columns) {
$scope.data = data;
$scope.columns = columns;
$scope.dataItem = dataItem;
};
$scope.gridOptions = {
dataSource: data,
selectable: "row",
columns: [
{ field: "text", title: "Text" },
{ field: "id", title: "Id" }
]
};
});
</script>
When you need to, say, load a column definition from the server, you need to postpone the widget initialization until the data is available, because the Grid does not support the option to define columns once the widget is created. That is where the k-ng-delay
attribute comes in handy. You can use $timeout
to emulate networking as the data is asynchronously set in scope.
The example below demonstrates how to dynamically set the Grid columns in AngularJS.
<div ng-app="app" ng-controller="MyCtrl">
<div kendo-grid k-options="gridOptions" k-ng-delay="gridOptions"></div>
</div>
<script>
angular.module("app", ["kendo.directives"]).controller("MyCtrl", function($scope, $timeout) {
$timeout(function(){
$scope.gridOptions = {
sortable: true,
selectable: true,
dataSource: [
{ text: "Foo", id: 1 },
{ text: "Bar", id: 2 },
{ text: "Baz", id: 3 }
],
columns: [
{ field: "text", title: "Text" }
]
};
}, 500);
});
</script>
The Grid supports a lot of user-customizable templates. You can define the rowTemplate
if you want to completely customize the way each row is displayed, or define individual cell templates by adding a template
property to your column definitions. The difference from applying plain Kendo is that when the Grid is created with the AngularJS directive, the templates can contain live \{\{angular\}\}
bits. The rowTemplate
, columns.template
and columns.groupFooterTemplate
are compiled with AngularJS in a scope containing a dataItem
variable, which points to the data model of the current item. The dataItem
in a groupFooterTemplate
is an object with fields and their corresponding aggregates.
The example below demonstrates how to set the Grid row template (rowTemplate
) in AngularJS via markup. It is also possible to define it in the Grid options object, as when not using Angular.
<div ng-app="app" ng-controller="MyCtrl">
<div kendo-grid k-options="gridOptions" k-ng-delay="gridOptions">
<table>
<tr k-row-template data-uid="#: uid #">
<td colspan="2" style="text-align:center">This is <strong>{% raw %}{{dataItem.text}}{% endraw %}</strong>
and has an ID of {% raw %}{{dataItem.id}}{% endraw %}</td>
</tr>
<tr k-alt-row-template class="k-alt" data-uid="#: uid #">
<td colspan="2" style="text-align:center">This is <strong>{% raw %}{{dataItem.text}}{% endraw %}</strong>
and has an ID of {% raw %}{{dataItem.id}}{% endraw %}</td>
</tr>
</table>
</div>
</div>
<script>
angular.module("app", ["kendo.directives"]).controller("MyCtrl", function($scope) {
var data = new kendo.data.DataSource({
data: [
{ text: "Foo", id: 1 },
{ text: "Bar", id: 2 },
{ text: "Baz", id: 3 }
]
});
$scope.gridOptions = {
dataSource: data,
sortable: true,
selectable: true,
columns: [
{ field: "text", title: "Text" },
{ field: "id", title: "Id" }
]
};
});
</script>
When you use aggregates, the column
and aggregate
information becomes available in the footerTemplate
of the Grid through {% raw %}{{ column }}{% endraw %}
and {% raw %}{{ aggregate }}{% endraw %}
respectively.
To access the aggregates of the columns in the groupFooterTemplate
use the dataItem
variable with the dataItem.field.aggregate
syntax.
The example below demonstrates how to use the sum
aggregate in a footerTemplate
and a groupFooterTemplate
and apply an Angular currency pipe to it.
<script src="http://demos.telerik.com/kendo-ui/content/shared/js/products.js"></script>
<div id="example" ng-app="KendoDemos">
<div ng-controller="MyCtrl">
<kendo-grid options="mainGridOptions" k-data-source="ds"></kendo-grid>
</div>
</div>
<script>
angular.module("KendoDemos", [ "kendo.directives" ])
.controller("MyCtrl", function($scope){
$scope.ds = new kendo.data.DataSource({
pageSize: 20,
data: products,
group: {
field: "CategoryID", aggregates: [
{ field: "UnitPrice", aggregate: "sum" },
{ field: "UnitsInStock", aggregate: "sum" }
]
},
aggregate: [
{ field: "UnitPrice", aggregate: "sum" },
{ field: "UnitsInStock", aggregate: "sum" }
]});
$scope.mainGridOptions = {
height: 500,
columns: [
{ field: "ProductName", title: "Product Name", width: 200,
template: "{% raw %}{{ dataItem.ProductName }}{% endraw %}"
},
{ field: "UnitPrice", title: "Unit Price", width: 80,
footerTemplate: "{% raw %}{{ column.title }}{% endraw %} : {% raw %}{{ aggregate.sum | currency }}{% endraw %}",
groupFooterTemplate:"{% raw %}{{ dataItem.UnitPrice.sum | currency }}{% endraw %}"
},
{ field: "UnitsInStock", title: "Units In Stock", width: 80,
aggregates: ["sum"],
footerTemplate: "{% raw %}{{ column.title }}{% endraw %} : {% raw %}{{ aggregate.sum }}{% endraw %}",
groupFooterTemplate: "{% raw %}{{ dataItem.UnitsInStock.sum }}{% endraw %}"
}
]
};
});
</script>
Important
When using
rowTemplate
, include thedata-uid="#: uid #"
attribute in the toplevel row element as described in the [Grid documentation]({% slug howto_use_dates_inside_row_template_grid %}). You must not use an AngularJS template likedata-uid="{% raw %}{{dataItem.uid}}{% endraw %}"
because it is compiled after the grid is displayed and the widget cannot discriminate between the different rows and the data items they belong to.
To take full control on the logic that performs the request to the server, all you have to do is to define the different transport operations as functions. Inside the function you can use the $http
or the $.ajax
methods to perform what is needed. When done (inside the success callback), just pass the result to the success
function part of the events arguments object.
The example below demonstrates how to use $http
to bind the Grid.
<div ng-app="app" ng-controller="MyCtrl">
<div kendo-grid k-options="gridOptions"></div>
</div>
<script>
angular.module("app", ["kendo.directives"]).controller("MyCtrl", function($scope, $http) {
$scope.gridOptions = {
columns: [ { field: "ProductID" }, { field: "ProductName" } ],
pageable: true,
dataSource: {
pageSize: 5,
transport: {
read: function (e) {
$http.jsonp('http://demos.telerik.com/kendo-ui/service/Products?callback=JSON_CALLBACK')
.then(function success(response) {
e.success(response.data)
}, function error(response) {
alert('something went wrong')
console.log(response);
})
}
}
}
}
});
</script>
Other articles on AngularJS directives and integration with Kendo UI:
- [AngularJS Integration Overview]({% slug angularjs_integration_directives %})
- [Global Events]({% slug global_events_angularjs_directives %})
- [Directives with DataSource]({% slug datasource_updates_angularjs_directives %})
- [ng-* Directives in Widget Markup]({% slug ngrepeat_ngif_ngbind_support_angularjs %})
- [Memory Leaks]({% slug memory_leaks_angularjs_directives %})
- [How to Load View in Window]({% slug window_service_angularjs_directives %})
- [How to Nest Widgets]({% slug nest_widgets_angularjs_directives %})
- [Troubleshooting: Common Issues]({% slug common_issues_support_angularjs %})
- Angular 2 Migration Guide