我最近选择了AngularJS而不是ember.js来处理我正在进行的项目,并且到目前为止对它非常满意。关于ember的一个好处是它内置了对具有自动数据绑定的“计算属性”的支持。我已经能够使用下面的代码在Angular中完成类似的操作,但我不确定这是否是最好的方法。
// Controller
angular.module('mathSkills.controller', [])
.controller('nav', ['navigation', '$scope', function (navigation, $scope) {
// "Computed Property"
$scope.$watch(navigation.getCurrentPageNumber, function(newVal, oldVal, scope) {
scope.currentPageNumber = newVal;
});
$scope.totalPages = navigation.getTotalPages();
}]);
// 'navigation' service
angular.module('mathSkills.services', [])
.factory('navigation', function() {
var currentPage = 0,
pages = [];
return {
getCurrentPageNumber: function() {
return currentPage + 1;
},
getTotalPages: function() {
return pages.length;
}
};
});
// HTML template
<div id=problemPager ng-controller=nav>
Problem {{currentPageNumber}} of {{totalPages}}
</div>
我希望只要currentPage
服务的navigation
发生更改,UI就会更新,上面的代码会完成。
这是解决AngularJS中此问题的最佳方法吗?使用$watch()
这样的(重要)性能影响是什么?使用自定义事件和$emit()
或$broadcast()
?
答案 0 :(得分:26)
虽然你的自我回答有效,但它实际上并没有实现计算属性。您只需通过调用绑定中的函数来解决问题,从而强制绑定变得贪婪。我并非100%确定它在所有情况下都能正常工作,并且在某些情况下贪婪可能会产生不必要的性能特征。
我为类似于EmberJS的依赖关系计算了属性的解决方案:
function ngCreateComputedProperty($scope, computedPropertyName, dependentProperties, f) {
function assignF($scope) {
var computedVal = f($scope);
$scope[computedPropertyName] = computedVal;
};
$scope.$watchCollection(dependentProperties, function(newVal, oldVal, $scope) {
assignF($scope);
});
assignF($scope);
};
// in some controller...
ngCreateComputedProperty($scope, 'aSquared', 'a', function($scope) { return $scope.a * $scope.a } );
ngCreateComputedProperty($scope, 'aPlusB', '[a,b]', function($scope) { return $scope.a + $scope.b } );
现场直播:http://jsfiddle.net/apinstein/2kR2c/3/
值得注意的是$ scope。$ watchCollection是有效的 - 我验证了“assignF()”只被调用一次,即使多个依赖项同时更改(相同的$ apply循环)。 “
答案 1 :(得分:23)
我想我找到了答案。此示例可以大大简化为:
// Controller
angular.module('mathSkills.controller', [])
.controller('nav', ['navigation', '$scope', function (navigation, $scope) {
// Property is now just a reference to the service's function.
$scope.currentPageNumber = navigation.getCurrentPageNumber;
$scope.totalPages = navigation.getTotalPages();
}]);
// HTML template
// Notice the first binding is to the result of a function call.
<div id=problemPager ng-controller=nav>
Problem {{currentPageNumber()}} of {{totalPages}}
</div>
答案 2 :(得分:4)
请注意,使用ECMAScript 5,您现在也可以执行以下操作:
// Controller
angular.module('mathSkills.controller', [])
.controller('nav', function(navigation, $scope) {
$scope.totalPages = navigation.getTotalPages();
Object.defineProperty($scope, 'currentPageNumber', {
get: function() {
return navigation.getCurrentPageNumber();
}
});
]);
//HTML
<div ng-controller="nav">Problem {{currentPageNumber}} of {{totalPages}}</div>