2012-06-26 122 views
21

我最近選擇了AngularJS over ember.js作爲我正在開發的一個項目,並且迄今爲止一直非常滿意。關於ember的一個好處是它內置了支持自動數據綁定的「計算屬性」。我已經能夠用下面的代碼在Angular中完成類似的事情,但我不確定這是否是最好的方式。AngularJS中的「計算屬性」

// 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> 

我想爲更新每當的navigation服務變化currentPage,其中,上述代碼完成的UI。

這是在AngularJS中解決這個問題的最好方法嗎?使用這樣的$watch()會有(重大)性能影響嗎?像這樣的事情會更好地完成使用自定義事件和$emit()$broadcast()

回答

22

我想我找到了答案。這個例子可以大大簡化爲:

// 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> 
+0

這是更好地確實 不過,你爲什麼堅持一切融合在一起 也許你應該嘗試分開你的模塊?你的控制器聲明? – Nimaen

+1

那麼,模塊是控制器的模塊,而不是保留一個最高級別的控制器 – ithkuil

24

雖然你的自我回答的作品,它並沒有實際實現計算屬性。你只需通過在你的綁定中調用一個函數來解決這個問題來強制綁定是貪婪的。我不是100%肯定它會在所有情況下都能正常工作,而且在某些情況下,貪婪可能具有不希望的性能特徵。

我工作了一個解決方案的計算性能W¯¯類似於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/

值得一提的是,$範圍$ watchCollection是有效的 - - 即使多個依賴關係同時發生更改(相同的$ apply週期),我也驗證過「assignF()」僅被調用一次。 「

+1

好極了,只是想知道在什麼對象下你聲明瞭這些自定義函數(與全局對象相比)?有一個推薦的做法,這在角? – CodeToad

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>