2012-06-26 11 views
21

Recentemente ho scelto AngularJS su ember.js per un progetto su cui sto lavorando e ne sono stato molto contento fino ad ora. Una cosa carina di ember è il supporto per "proprietà calcolate" con l'associazione automatica dei dati. Sono stato in grado di realizzare qualcosa di simile in Angular con il codice sottostante, ma non sono sicuro che sia il modo migliore per farlo."Proprietà calcolate" in 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> 

desidero per l'interfaccia utente per aggiornare ogniqualvolta il currentPage delle navigation cambiamenti di servizio, che il codice precedente compie.

È questo il modo migliore per risolvere questo problema in AngularJS? Ci sono (significative) implicazioni sulle prestazioni per l'utilizzo di $watch() in questo modo? Sarebbe meglio realizzare qualcosa del genere usando eventi personalizzati e $emit() o $broadcast()?

risposta

22

Penso di aver trovato la risposta. Questo esempio può essere notevolmente semplificato in:

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

Questo è meglio anzi Tuttavia, perché ti infili tutto insieme Forse si dovrebbe cercare di separare il modulo e? le dichiarazioni del controllore? – Nimaen

+1

Bene, il modulo è il modulo per il controller, invece di mantenere un controller di primo livello – ithkuil

24

Mentre l'auto-risposta funziona, in realtà non implementa le proprietà calcolate. Hai semplicemente risolto il problema chiamando una funzione nell'associazione per forzare l'associazione ad essere avida. Non sono sicuro al 100% che funzioni in tutti i casi e l'avidità potrebbe avere caratteristiche di prestazioni indesiderate in alcune situazioni.

Ho lavorato su una soluzione per una proprietà calcolate w/dipendenze simile a quello che EmberJS ha:

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 }); 

vederla dal vivo:. http://jsfiddle.net/apinstein/2kR2c/3/

Vale la pena notare che $ portata $ watchCollection è efficiente - - Ho verificato che "assignF()" è chiamato una sola volta anche se dipendenze multiple vengono cambiate simultaneamente (stesso ciclo di domanda $). "

+1

Eccellente. Mi chiedo solo sotto quale oggetto dichiarate queste funzioni personalizzate (rispetto all'oggetto globale nell'esempio)? esiste una pratica raccomandata per questo in angolare? – CodeToad

4

Si noti che con ECMAScript 5 è ora possibile anche fare qualcosa di simile:.

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