10

I have been trying to figure out the solution but I think i hit a dead end.

So here is my directive

directives.directive('postprocess', function($compile)
{
    return {
        restrict : 'E',
        require: '^ngModel',
        scope: {
            ngModel: '='
        },
        link: function(scope, element, attrs) {
            var parsed = scope.ngModel;
            el = $compile(parsed)(scope);
            element.html("");
            //add some other html entities/styles.
            element.append(el);
            console.log(parsed);
        }  
    };
});

The html

<postprocess ng-model="some_model.its_property" style="padding-top: 10px;" />

Somewhere in the controller, I update the model property

some_model.its_property = 'Holla';

But it doesn't update the corresponding directive. It works perfectly when loading which tells me that it might not be entirely a scoping issue.

3 Answers 3

16

It's much simpler, so I have removed some extra code you had there.

Please take a look at the code below or working Plunker:

<!doctype html>
<html lang="en" ng-app="myApp">
    <head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>

    <script>
        var myApp = angular.module('myApp', []);
        myApp.directive('postprocess', function ($timeout) {
            return {
                restrict : 'E',
                transclude: 'true',
                scope: {
                    myVariable: '='
                },
                link: function(scope, element, attrs) {
                    $timeout(function () {
                        scope.myVariable = 'Bye bye!'
                    }, 200);
                }  
            };
        });

        myApp.controller('myAppCtrl', ['$scope', '$timeout', function ($scope, $timeout) {
            $scope.myVariable = {
                value : 'Holla'
            };

            console.log($scope.myVariable.value); // -> prints initial value
            $timeout(function () {
                console.log($scope.myVariable.value); // -> prints value after it is changed by the directive
            }, 2000);
        }])
    </script>

    </head>
    <body ng-controller="myAppCtrl">
        <postprocess my-variable="myVariable.value" style="padding-top: 10px;" />
    </body>
</html>
  1. The controller sets the initial value to 'Holla'
  2. The directive receives that value by the my-variable attribute
  3. Using two way data-binding any changes made to scope.myVariable updates the $scope.myVariable of the main controller
  4. After few seconds $scope.myVariable changes to 'Bye Bye'
  5. Take a look at your console.log

$watch and $apply

Angular's two-way data binding is the root of all awesome in Angular. However, it's not magic, and there are some situations where you need to give it a nudge in the right direction.

When you bind a value to an element in Angular using ng-model, ng-repeat, etc., Angular creates a $watch on that value. Then whenever a value on a scope changes, all $watches observing that element are executed, and everything updates.

Sometimes, usually when you're writing a custom directive, you will have to define your own $watch on a scope value to make the directive react to changes.

On the flip side, sometimes you change a scope value in some code but the app doesn't react to it. Angular checks for scope variable changes after pieces of your code have finished running; for example, when ng-click calls a function on your scope, Angular will check for changes and react. However, some code is outside of Angular and you'll have to call scope.$apply() yourself to trigger the update. This is most commonly seen in event handlers in custom directives.

Sign up to request clarification or add additional context in comments.

11 Comments

thanks for the prompt response. Changing value inside of the directive works as I expected but not the other way around. See this fiddle jsfiddle.net/T7cqV/3
It does work the way around too! I have updated your jsfiddle (jsfiddle.net/denisonluz/T7cqV/8). You need to add a scope.$watch so you can track the changes made by the controller to the $scope.
@Sai, in fact there's no reason "to avoid watch". This implementation is completely normal and expected. I have updated my answer about with some text from AngularJS FAQ explaining the use of $watch and $apply. Take a look.
@Sai, that's a really good question and it normally starts a good debate too :) There's no one better than the AngularJS's father to answer that. You can see his answer here (stackoverflow.com/a/9693933/1310945)
@DenisonLuz This is awesome! This issue was driving me nuts. Wasted so much time.... The moment I put "value" key in the controller, everything started working. Thanks a bunch!
|
1

Some help from angularjs irc, & dluz, updated. Though I wish there was an easier way for the directive to be called, since the link function contains behavior and there should be a way to call that.

http://jsfiddle.net/T7cqV/5/

Comments

1

be sure that you use the dot rule

http://jimhoskins.com/2012/12/14/nested-scopes-in-angularjs.html

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.