Two way binding, shallow $watch, isolate scope not working together

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

Please refer to this fiddle for the questions. http://jsfiddle.net/AQR55/

1) Why a watch that is attached to an isolate scope property – which is bidirectionally bound to a parent property, is not triggering on changing the parent scope property.

In the fiddle, the below metioned watch is not getting triggered, on changing the parent scope property to which it is bound.

$scope.$watch('acts', function(neww ,old){
                    console.log(neww)
                })

2) ng-click="addaction()" addaction="addaction()". Can this code be put in more elegant way? Because, to perform an action in isolated scope, it seems we need to set bidirectional binding and the attach to ng-click.

3)Can i declare methods inside the isolated scope like shown below? If i do like this, I’m getting .js error.

<isolate-scope-creating-cmp ng-click="isolateCmpClickHandler()"></isolate-scope-creating-cmp>
scope:{
    isolateCmpClickHandler:function(){
      //If i do like this, I'm getting .js error

    }
}

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

Question 1.
Since you are adding a item to the acts array, you need to set the third parameter in $watch() to true

$scope.$watch('acts', function (neww, old) {
    console.log(neww)
}, true);

Demo: Fiddle

Question 2.
Since there is an isolated scope, you need to call the $parent scope’s function

<input type="button" bn="" acts="acts" ng-click="$parent.addaction()" value="Add Action" />

Demo: Fiddle

Question 3.
Yes you can, but you need to use a controller

animateAppModule.directive('bn', function () {
    return {
        restrict: "A",
        scope: {
            acts: '='
        },
        link: function ($scope, iElement, iAttrs) {
            $scope.$watch('acts', function (neww, old) {
                console.log(neww)
            }, true)
        },
        controller: function($scope){
            $scope.dosomething = function(){
                console.log('do something')
            }
        }
    }
})

Demo: Fiddle

An overall solution could look like

<input type="button" bn="" acts="acts" addaction="addaction()" value="Add Action" />

JS

animateAppModule.controller('tst', function ($scope) {
    $scope.acts = [];
    $scope.addaction = function () {
        $scope.acts.push({
            a: "a,b"
        })
    }
})

animateAppModule.directive('bn', function () {
    return {
        restrict: "A",
        scope: {
            acts: '=',
            addaction: '&'
        },
        link: function ($scope, iElement, iAttrs) {
            $scope.$watch('acts', function (neww, old) {
                console.log(neww)
            }, true);
            iElement.click(function(){
                $scope.$apply('addaction()')
            })
        }
    }
})

Demo: Fiddle

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