4

When apply angular syntax {{}} on element, directive attrs.$set will not work.

Edit: My question is could anyone explain why?

If {{}} parsed and then link, why wouldn't the element been modified by link?

If link first, {{}} should be removed, both condition will not result like this.

Here is the code pen

<div ng-app="ngApp" ng-controller="global">
  <a aaa href="http://{{::lan}}/4567">has syntax</a>
  <a aaa href="http://nosyntax/4567">no syntax</a>
</div>

angular.module('ngApp',[])
  .directive('aaa',function(){
  return {
    link:function(scope, ele, attr){
      attr.$set('href','http://fromdirective');
    }
  }
}).controller('global',function($scope){
  $scope.lan = 'en-gb';
})
Sing
  • 3,942
  • 3
  • 29
  • 40

3 Answers3

2

Since you are leveraging link, the framework has already attached data to the element in question, parsing the {{}}syntax (digest cycle). If you want to set this value before the element is compiled, you can leverage compile in place of link as such...

.directive('aaa',function(){
  return {
    compile: function(tElement, tAttributes, transcludeFn) {

      // -- just a jqLite object at this point
      tAttributes.$set('href','http://fromdirective');
    }
  }

updated pen

Unsure if this is your intention, but this is why it is happening. As others have suggested, $timeout will avoid the digest issue as well, but after link has initially digested - you'll need to determine which is more appropriate per your use case.

See SO question What is the difference between compile and link function in angularjs for some more discussion on this topic. Also check out the ngHref directive - perhaps this could be useful.

Community
  • 1
  • 1
scniro
  • 16,844
  • 8
  • 62
  • 106
  • 1
    Thanks your answer, the compile function did the work to override the `{{}} ` syntax, however why the link function can not modify after {{}} has been parsed? – Sing Mar 09 '16 at 15:50
  • 1
    @AndyChen my best guess is because there is a lock of sort which forces you to wait in the midst of this digest cycle, or do it before. I'm guessing you'll need to dig through the framework to find your exact answer, since it's very specific and not commonly looked further into more than "`$timeout` works - good enough" (guilty myself) – scniro Mar 09 '16 at 15:56
  • @AndyChen did you make any more progress on this? – scniro Mar 10 '16 at 23:25
1

Is it what you are looking for?

angular.module('ngApp',[])
  .directive('aaa',['$timeout',function($timeout){
  return {
    link:function(scope, ele, attr){
      $timeout(function() {
      attr.$set('href','http://fromdirective');
      },0);
    }
  }
}]).controller('global',function($scope){
  $scope.lan = 'en-gb';
})
alexey
  • 1,381
  • 9
  • 19
1

Use $timeout to push the change to the end of the digest cycle

angular.module('ngApp',[])
  .directive('aaa',function($timeout){
  return {
    link:function(scope, ele, attr){
      $timeout(function(){
         attr.$set('href','http://fromdirective');
      });         
    }
  }
});
charlietfl
  • 170,828
  • 13
  • 121
  • 150
  • 1
    Thank you for your answer, but I want to know why will behave like this ? – Sing Mar 09 '16 at 15:27
  • 1
    because of digest cycles. More than one digest occurs in a cycle and you are changing it while angular is still aware of the original binding internally – charlietfl Mar 09 '16 at 15:29