最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ng-bind happend after my directive so I don't have the value - Stack Overflow

programmeradmin4浏览0评论

I have a div element with ng-bind directive:

<div ng-bind="sometext"></div>

I have a directive that gets an element, checks its value / text and adds a color to the element according to the content. I am using this directive like that:

<div ng-bind="sometext" my-directive></div>

The problem is that on the time the directive is executing, there is no value or text on the div because ng-bind didn't happened yet.
I am getting the text using element.text().
Any idea how to make the text available inside my directive?

I have a div element with ng-bind directive:

<div ng-bind="sometext"></div>

I have a directive that gets an element, checks its value / text and adds a color to the element according to the content. I am using this directive like that:

<div ng-bind="sometext" my-directive></div>

The problem is that on the time the directive is executing, there is no value or text on the div because ng-bind didn't happened yet.
I am getting the text using element.text().
Any idea how to make the text available inside my directive?

Share Improve this question asked Jan 11, 2014 at 20:20 NaorNaor 24.1k50 gold badges155 silver badges270 bronze badges 4
  • you will need to change the priority of your directive so that it runs after ng-bind. I've never done anything with priorities yet, so I can't give you too much help though. – Matt Greer Commented Jan 11, 2014 at 20:24
  • @MattGreer: I thought the solution will be something like that. I saw angularJS code and there is no priority to ng-bind. I need to set less priority then ng-bind because I want my directive to run last.Any idea? – Naor Commented Jan 11, 2014 at 20:33
  • I had a similar problem last week which I solved by wrapping $timeout around part of my code, so it's evaluated the next digest cycle when the binding has happened. I'm not entirely happy with that solution, but perhaps it suffices for your needs. – towr Commented Jan 11, 2014 at 20:36
  • @Naor have you tried adding priority: 1 to your directive? just as a curiosity, maybe it really is that simple? – Matt Greer Commented Jan 11, 2014 at 20:43
Add a comment  | 

3 Answers 3

Reset to default 13

Your directive may be running before ngBind has bound it's value - both your directive and ngBind are priority 0 so either could run first, more on that in a moment- but let's look at the ngBind source code to see the root of the problem:

var ngBindDirective = ngDirective(function(scope, element, attr) {
  element.addClass('ng-binding').data('$binding', attr.ngBind);

  scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
    element.text(value == undefined ? '' : value);
  });

});

We see that ngBind doesn't immediately update the DOM, but rather places a watch on the ngBind attribute. So the element won't be updated until that watch is run on the next $digest cycle (which is why a $timeout works).

So one option is to mimic ngBind and place your own watch on it's attribute- then you'll be updated whenever the ngBind result changes:

angular.module('myApp').directive('myDirective', function() { 
    return {
        priority: 1,
        link: function(scope,element,attrs) {
            scope.$watch(attrs.ngBind, function(newvalue) {
              console.log("element ",element.text());
            });           
        }
    };      
});

You'll note I set priority to 1. You do need to be sure that this directive's watch is placed after the ngBind watch in the watch queue. That will ensure the element has been updated by ngBind first.

By default a directive's link function runs post-link, so as the $compile docs note:

Directives with greater numerical priority are compiled first. Pre-link functions are also run in priority order, but post-link functions are run in reverse order.

Therefore, since ngBind is priority 0, anything over 0 will ensure your directive's watch will come after the ngBind watch..

demo fiddle

Edit 2

The other option is to use ng-class or ng-style for changing the color of the text. Then you don't have to create a new directive at all.

Original Answer

I would not depend on the ng-bind directive at all... This seems much cleaner in my opinion.

<div ng-bind="someModel" my-directive="someModel"></div>

And then define your directive as...

angular.module('myApp').directive('myDirective', function() { 
    return {
        link: function(scope, element, attrs) {
            scope.$watch(attrs.myDirective, function(newValue, oldValue) {
              // Your Code here...
            });           
        }
    };      
});

This way you can use your directive even if you don't have an ng-bind on the element (for example, if you use curly braces instead).

<div my-directive="someModel">{{someModel}}</div>

Alternatively you can use attrs.$observe(...) (documentation) instead of scope.$watch(...).

<div ng-bind="someModel" my-directive="{{someModel}}"></div>

and

angular.module('myApp').directive('myDirective', function() { 
    return {
        link: function(scope, element, attrs) {
            attrs.$observe('myDirective', function(interpolatedValue) {
              // Your Code here...
            });           
        }
    };      
});

You can find more information about the differences between scope.$watch(...) and attrs.$observe() here.

Edit

Given that your directive is basically mutating the DOM after the ng-bind directive, why not skip the ng-bind all together?

<div my-directive="{{someModel}}"></div>

and

angular.module('myApp').directive('myDirective', function() { 
    return {
        link: function(scope, element, attrs) {
            attrs.$observe('myDirective', function(interpolatedValue) {
              if (interpolatedValue) {
                // Modify interpolatedValue if necessary...
              }
              element.text(interpolatedValue == undefined ? '' : interpolatedValue);
            });           
        }
    };      
});

You could use a scope.$watch in you link function and watch for model changes. Each time the value changes ng-bind will fire and your directive will be fired as well, independent to the bg-bind directive and dependent only to the modle itself.

Sorry i cant presnt you with sample code as im on a tablet while answering your question.

发布评论

评论列表(0)

  1. 暂无评论