Trying to implement a directive for a grid, I encountered an issue where passing in a column definition that includes an HTML control with ng-model and ng-click directives resulted in an error: "Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!" And the ng-model was not binding as expected. To see this problem in action, check out a simple Plunker example here: https://plnkr.co/edit/ue1lQqvrUE0M5zZXsg8a?p=preview.
// Code snippet
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('MyCtrl', function($scope) {
$scope.myGridConfig = {};
$scope.myGridConfig.columnDefs = [{
field: 'facility',
headerName: 'Facility'
}, {
field: 'code',
headerName: 'Code'
}, {
field: 'cost',
headerName: 'Cost'
}, {
field: 'conditionRating',
headerName: 'Conditional Rating'
}, {
field: 'extent',
headerName: 'Extent'
}, {
field: 'planYear',
headerName: 'Plan Year',
cellRenderer: function(row, de) {
return '<input type="checkbox" ng-model="row.selected" />';
}
}];
$scope.myGridConfig.rowCollection = [{
facility: "Atlanta",
code: "C-RD34",
cost: 540000,
conditionRating: 52,
extent: 100,
planYear: 2014
}, {
facility: "Seattle",
code: "CRDm-4",
cost: 23000,
conditionRating: 40,
extent: 88,
planYear: 2014
}, {
facility: "Austin",
code: "GR-5",
cost: 1200000,
conditionRating: 92,
extent: 90,
planYear: 2014
}];
});
myApp.directive('cellRender', function($compile) {
var directive = {};
directive.restrict = 'A';
directive.scope = {
cellRender: "="
};
directive.replace = true;
//directive.template = "<div>{{renderThis(cellRender.row, cellRender.def)}}</div>";
directive.template = "<div>{{renderThis()}}</div>";
directive.link = function(scope, ele, attrs) {
scope.renderThis = function() {
if (scope.cellRender.def.cellRenderer) {
ele.html(scope.cellRender.def.cellRenderer(scope.cellRender.row, scope.cellRender.def));
$compile(ele.contents())(scope);
}
return scope.cellRender.row[scope.cellRender.def.field];
};
/*scope.renderThis = function(r, d) {
if (d.cellRenderer)
{
ele.html(d.cellRenderer(r,d));
$compile(ele.contents())(scope);
}
return r[d.field];
};*/
};
return directive;
});
myApp.directive('grid', function($compile) {
var directive = {};
directive.restrict = 'EA';
directive.scope = {
gridConfig: "="
};
directive.template = "<table style='border: 1px solid black;'>\n" +
"<thead>\n" +
"<tr>\n" +
"<th ng-repeat=\"def in gridConfig.columnDefs\" >{{def.headerName}}</th>\n" +
"</tr>\n" +
"</thead>\n" +
"<tbody>\n" +
"<tr ng-repeat=\"row in gridConfig.rowCollection\">\n" +
"<td ng-repeat=\"def in gridConfig.columnDefs\" ><div cell-render=\"{'row': row, 'def' :def}\"></div></td>\n" +
"</tr>\n" +
"</tbody>\n" +
"</table>";
directive.link = function(scope, ele, attrs) {
angular.forEach(scope.gridConfig.rowCollection, function(rr) {
rr.selected = true;
});
};
return directive;
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Test dynamic ngModel</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.29/angular.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.29/angular-sanitize.js"></script>
<script type="text/javascript" src="script.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<div grid="" grid-config="myGridConfig"></div>
<div>Row 2 selected: {{myGridConfig.rowCollection[1].selected}}</div>
</div>
</body>
</html>