2012-06-26 10 views
21

私は最近、私が取り組んでいるプロジェクトでember.jsよりAngularJSを選択しました。これまでに非常に満足しています。 emberについての素晴らしい点の1つは、自動データバインディングを使用した「計算されたプロパティ」のサポートが組み込まれていることです。私は以下のコードでAngularで同様のことを達成することができましたが、それが最良の方法であるかどうかはわかりません。AngularJSの "Computed Properties"

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

UIは、上記のコードが実現navigationサービスの変更のたびにcurrentPageを更新するために、私はたいです。

これは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%確信していませんし、状況によっては貪欲が望ましくないパフォーマンス特性を持つかもしれません。

私は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回だけ呼び出されることを確認しました。 ECMAScriptの5とあなたは今も、このような何かができることを 「

+1

優れています(これらのカスタム関数をこの例のグローバルオブジェクトと比較して宣言していますか?このために推奨される練習がありますか? – CodeToad

4

注:?確かに良いでしょう

// 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> 
関連する問題