ng-computed

Computed properties for angularjs


License
MIT
Install
bower install ng-computed

Documentation

ng-computed

Computed properties for AngularJS, à la Knockout JS.

Features include automatic dependency management, promise unrapping and (optional) batched watches.

bower install ng-computed

Summary

ng-computed lets you write computed properties without worrying about which values to register a $watch on and when.

$scope.string = "hello";
$scope.$computed('computedValue', function() {
    return $scope.$eval('string') + " world!";
});

In this case, $scope.computedValue will take on the value "hello world!", while also reacting to changes to $scope.string.

Example

As an example, this is a simple translation of the KnockoutJS computed observable example:

angular.module("example", ["ngComputed", "ng"])
    .controller("ExampleController", function($scope, $computed, $trackedEval) {
        $scope.$computed = $computed;
        $scope.$eval = $trackedEval;

        $scope.firstName = "George";
        $scope.surname = "Clooney";
        $scope.$computed("fullName", function() {
            return $scope.$eval("firstName") + " " + $scope.$eval("surname");
        });
    });
<html ng-app="example">
    ...
    <div ng-controller="ExampleController">
        <div>
            <input ng-model="firstName">
            <input ng-model="surname">
        </div>
        <div>Hello, {{fullName}}</div>
    </div>
    ...
</html>

See this example on plunker

To do this in plain AngularJS would require us to manage our watches explicitly:

angular.module("example", ["ng"])
    .controller("ExampleController", function($scope) {
        $scope.firstName = "George"; 
        $scope.surname = "Clooney";

        $scope.$watch("firstName", function(firstName) {
            $scope.fullName = firstName + " " + $scope.surname;
        });
        $scope.$watch("surname", function(surname) {
            $scope.fullName = $scope.firstName + " " + surname;
        });
    });

ng-computed will do the work of managing watches for you. See this example to see it in action.

Setup

At the top level we can add our functions to the root scope, even going so far as to replace the functions there:

angular.module('app', ['ngComputed', 'ng'])
    .run(['$rootScope', '$trackedEval', '$computed', function($rootScope, $trackedEval, $computed) {
        // we have to use the prototype, otherwise isolate scopes miss out
        angular.extend($rootScope.constructor.prototype, {
            $eval: $trackedEval,
            $computed: $computed
        });
    }]);

For the majority of the documentation we will assume this setup, although you can also bind to different names on the scope prototype, or bind them on any sub-scope.

Documentation

See /docs/complete.org for our current documentation.