Reputation: 1
I am investigating Angular as a potential framework to use for an upcoming project. The test app I am making consists of an unordered list of which list items can be added to via an add link. Each list item contains a number of checkboxes. The number of checkboxes for a particular list item can be increased or decreased with plus and minus links next to each list item. Observe:
Hopefully that makes sense. Each checkbox has an ng-model
directive binding the value of the checkbox to a property in an object. When the application is in the state above clicking any of the checkboxes fires six checks (one for each checkbox) -- the entire $scope
of the root controller is checked for changes. Ideally, only the $scope
of the relevant list item would be checked for changes. How can I accomplish this? I've attached my test code for reference. I've tried adding ng-click="$event.stopPropagation()"
to the input
node as well as to the li
node but this appears to increase (double) the number of checks in the digest.
HTML:
<div ng-app ng-controller="App">
<ul>
<li ng-repeat="line in lines" ng-controller="LineController">
<input type="checkbox" ng-repeat="box in line.boxes" ng-model="box.on" />
<a ng-show="line.boxes.length > 1" ng-click="removeBox()">-</a>
<a ng-click="addBox()">+</a>
</li>
</ul>
<a ng-click="addLine()">Add</a>
</div>
JavaScript:
function App($scope) {
$scope.lines = [];
$scope.addLine = function () {
$scope.lines.push({
boxes: []
});
};
}
function LineController($scope) {
$scope.addBox = function () {
var box = {};
Object.defineProperty(box, 'on', {
enmerable: true,
get: function () {
console.log('Get!');
return this._on;
},
set: function (on) {
this._on = on;
}
});
$scope.line.boxes.push(box);
};
$scope.removeBox = function () {
$scope.line.boxes.pop();
};
}
Upvotes: 0
Views: 661
Reputation: 77904
What about to use $watch
. We can invoke watch only for specific row. That means if you have 4x4 matrix (4 rows , 4 columns) on any checkbox state change we call watch 4 times
var webApp = angular.module('myModule', []);
webApp.controller('App', function ($scope) {
$scope.lines = [];
$scope.addLine = function () {
console.log("addLine");
$scope.lines.push({
boxes: []
});
};
});
webApp.controller('LineController', function ($scope) {
$scope.addBox = function () {
var box = {};
/* Object.defineProperty(box, 'on', {
enmerable: true,
get: function () {
console.log('Get!');
return this._on;
},
set: function (on) {
this._on = on;
}
});*/
$scope.line.boxes.push(box);
$scope.$watch(function () {
return $scope.line.boxes;
},
function (newValue, oldValue) {
if(newValue == oldValue) return;
console.log('Get new checkbox!');
}, true);
};
$scope.removeBox = function () {
$scope.line.boxes.pop();
};
});
Demo Fiddle
Upvotes: 1
Reputation: 1425
If your concern is that AnguarJS dirty checking is going to be too slow for your needs, your question really need to be "is AngularJS going to be to slow to build X?" If X is a 3D game with lots of constant rendering then the answer is probably yes, AngularJS is not what you want. If X is "a scalable business/consumer oriented single page application", then the dirty checking algorithm is not going to be your bottle neck.
This SO answer has a good explanation of how data binding works and talks a bit about performance concerns.
Upvotes: 1