Problem
The Kendo grid has a method select(). Which according to the API:
Gets or sets the table rows (or cells) which are selected.So I tried to call select in a ng-click directive, and I get an error:
$apply already in progressSome of you AngularJs experts will already know that $apply() is called by AngularJs to apply changes in the model (aka presentation model), to the view (aka presentation). And it cannot be called recursively; ie. you cannot call $apply() while another $apply is already in progress.
So here's a how my code looked like (the code that gave the "$apply already in progress" error):
<button ng-click="selectRow()">test</button>
And in my controller:
$scope.selectRow = function () { // ... some code ... $scope.myGrid.select( aRow ); };
After some digging, I found out that almost all code that's in the controller will be in an $apply() call.
- ng-click="..."
- ng-blur="..."
- $scope.$watch(...)
- $scope.$on(...)
AngularJs docs blame the 3rd party code.
Another Problem
And this is Kendo's grid does not have ng-model support. That means you can't do this:
<div kendo-grid ng-model="selectedRow"></div>
You have to do this:
<div kendo-grid k-on-change="selectedRow = data"></div>
So even if I workaround the first problem above, I can't simply do this in my controller and hope the grid selects the row itself:
$scope.selectRow = function () { // ... some code ... $scope.selectedRow = aRow; };
Solution
Apparently the accepted way to do it is
- Wrap the data in a kendo.data.ObservableArray object.
- Add the CSS class "k-state-selected" to the row.
- Manually update the model with the row.
1. Wrap the data in a kendo.data.ObservableArray object
What this does is to provide true binding of each element of the array to each row of the grid. But a secondary effect of this is to wrap each element of the array in a kendo.data.ObservableObject object. This causes each array element to have a uid field automatically generated. And when the Grid renders, it will add a data-uid attribute to the HTML of the Grid row:
<tr class="k-alt ng-scope" data-uid="ac5be667-5483-4c52-bf2a-3a8f85bb5eeb" role="row"> ... </tr>
Perfect.
2. Add the CSS class "k-state-selected" to the row
This is done using jQuery:
$scope.selectRow = function () { // ... some code // "item" now contains the kendo.data.ObservableObject $('[data-uid=' + item.uid + ']').addClass('k-state-selected'); };
3. Manually update the model with the row
This is done like so
$scope.selectRow = function () { // ... some code ... $scope.selectedRow = item; };
So our final selectRow function looks like this:
$scope.selectRow = function () { // ... some code ... // "item" now contains the kendo.data.ObservableObject $('[data-uid=' + item.uid + ']').addClass('k-state-selected'); $scope.workingScreenState.selectedRow = item; };