javascriptangularjsangular-directiveangularjs-ng-href

Change href can't update the data which bind to ng-src or ng-href


Html

<div class="result" ng-controller="test">
    <div>{{result}}</div>
    <a ng-href="{{result}}"></a>
</div>

JS

App.controller('AppCtrl', function AppCtrl($scope){
    $scope.result = "www.google.com";
}

In a jquery file I can't modify because of some reason, some code changed the value of href, like:

$('.result>a').attr('href','www.youtube.com');

I want the value of $scope.result in the controller also changed from "www.google.com" to "www.youtube.com". But the result value in the div didn't change after the jquery code. Do I need write directive to watch the href attribute by myself? Or there are some other way to use ng-href? I try to write the directive by myself, but it didn't work. I hope you can give me a small example. Thanks :)

Update:

This is my directive, it didn't work, after something like $('.result>a').attr('href','www.youtube.com'), the console didn't print "change!" and the $scope.result didn't change:

APP.directive('result', function() {
    return {
        restrict: 'E',
        scope: {
            ngModel: '='
        },
        template: "<div class='result'><a ng-href='{{ngModel}}' href=''></a></div>",
        replace: true,
        require: 'ngModel',
        link: function(scope, element, attrs) {
            var $element = $(element.children()[0]);
            scope.$watch($element.attr('href'), function(newValue) {
                console.log("change!");
                scope.ngModel = newValue;
            })
        }
    };
});

Update Again: Still can't work...

Html:

<div class="result">
    <a ng-href="{{result}}" ng-model="result" class="resulta"></a>
</div>

JS:

APP.directive('resulta', function() {
    return {
        restrict: 'C',
        scope: {
            ngModel: '='
        },
        link: function(scope, element, attrs) {
            scope.$watch(attrs.href, function(newValue) {
                console.log("change!");
                scope.ngModel = newValue;
            })
        }
    };
});

Solution

  • You can indeed create a custom directive to do it. See the example. I use transclude scope so you can put whatever you like in the link. I set 'replace: true' so the directive is removed and replaced with the <a>.

    UPDATE Using MutationObserver to watch for changes to the <a href>

    var app = angular.module("MyApp", []);
    
    app.directive("myHref", function() {
      return {
        restrict: 'E',
        replace: true,
        transclude: true,
        link: function(scope, elem, attrs) {
          var observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
              scope.$parent.result = mutation.target.href;
              scope.$apply();
            });
          });
    
          // configuration of the observer:
          var config = {
            attributes: true,
            childList: true,
            characterData: true
          };
    
          observer.observe(elem[0], config);
    
        },
        scope: {
          myHref: '='
        },
        template: '<a target="_blank" ng-transclude href="{{myHref}}"></a>'
      };
    });
    
    app.controller('AppCtrl', function($scope) {
      $scope.result = "http://www.yahoo.com";
      $scope.$watch('result', function() {
        alert($scope.result);
      });
    });
    
    
    
    setTimeout(function() {
      $('.result > a ').attr('href', 'http://www.youtube.com');
    }, 1000);
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <div ng-app="MyApp">
      <div class="result" ng-controller="AppCtrl">
        <my-href my-href="result">My Link</my-href>
      </div>
    </div>