What is the analog for Knockout's writable computed observable in AngularJS?

All we need is an easy explanation of the problem, so here it is.

I use KnockoutJS in my projects, but want to learn AngularJS as it has a lot of tasty features that Knockout doesn’t have.
So I’m interested in rewriting some of my code using Angular. But I don’t understand how to do some simple things that I use in Knockout.
For example, Knockout has a feature of computed observables. It’s cool!
I’ve already found that I can use a simple function instead. But Knockout provides “write” function to a computed observables, like:

var first_name = ko.observable('John'),
    last_name = ko.observable('Smith'),
    full_name = ko.computed({
        read: function(){
            return first_name() + ' ' + last_name();
        },
        write: function(new_value){
            var matches = new_value.match(/^(\w+)\s+(\w+)/);

            first_name(matches[1]);
            last_name(matches[2]);
        }
    });

This code on JSFiddle: http://jsfiddle.net/Girafa/QNebV/1/

This code allows me to update the “first_name” and “last_name” observables when I change the “full_name” one. How it can be done using AngularJS? A function with an argument being checked for existence? Something like this?

first_name = 'John';
last_name = 'Smith';
full_name = function(value){
    if (typeof value != 'undefined')
    {
        // do the same as in the Knockout's write function
    }
    else
    {
        // do the same as in the Knockout's read function
    }
}

What is the best practice?

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

I’ve found such a solution: http://jsfiddle.net/Girafa/V8BNc/

Instead of using angular $watch method, we set native javascript getter and setter of the fullName property:

Object.defineProperty($scope, 'fullName', {
    get: function(){
        #...
    },
    set: function(newValue){
        #...
    }
})

Think this is more convenient as I don’t need to make any special watchers in the code. But I don’t know about browser support of this solution.

Method 2

Sorry about that. It’s true, this is simpler in knockout because a function is called whereas a property is used in angular. This is the way I could resolve it, but I would like to know if there is a better way.

I fixed this time Plunker

app.controller('Ctrl', function($scope) {
    $scope.firstName = 'John';
    $scope.lastName  = 'Smith';

    $scope.getFullName = function() {
        $scope.fullName = $scope.firstName + ' ' + $scope.lastName;
        return $scope.fullName;
    }

    $scope.$watch('fullName', function(newValue, oldValue) {
        var names = newValue.split(' ');
        $scope.firstName = names[0];
        $scope.lastName  = names[1];  
    });
});

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply