0

The following works and console dot logs the "post" object, but how do I pass the url of the anchor tag in the directive to the controller function "itemClicked"?

HTML:

<div ng-repeat="post in posts" >
    <div find-urls link-clicked="itemClicked(post)" ng-bind="post.content"><div>
</div>

Controller:

$scope.itemClicked = function(post) {
  console.log(post);
};

Directive:

function findUrls($compile) {
  return {
    restrict: 'AC',
    scope: {
        linkClickedCallback: '&linkClicked'
    },
    link: function (scope, elem, attrs) {
      if (attrs.ngBind) {
        scope.$watch(attrs.ngBind, _.debounce(wrapUrls));
      }
      if (attrs.ngBindHtml) {
        scope.$watch(attrs.ngBindHtml, _.debounce(wrapUrls));
      }

      function wrapUrls(text) {
        var linkPatterns = new Array({
          pattern: /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig,
          template: '&nbsp;<a class="absolute_link" href="$1" target="_blank">$1</a>'
        },
        {
          pattern: /(^|[^\/])(www\.[\S]+(\b|$))/ig,
          template: '&nbsp;<a class="absolute_link" href="http://$2" ng-click="linkClickedCallback();" target="_blank">$2</a>'
        },
        {
          pattern: /([a-z0-9._-]+@[a-z0-9._-]+\.[a-zA-Z0-9._-]+)/ig,
          template: '&nbsp;<a class="absolute_link" href="mailto:$1" ng-click="linkClickedCallback();" target="_blank">$1</a>'
        },
        {
          pattern: /(^|[^a-z0-9@\\\/._-])([a-z0-9]{0,256}\.(com|net|org|edu)([a-z0-9\/?=\-_#]{0,256})?(\b|$))/ig,
          template: '&nbsp;<a class="absolute_link" href="http://$2" ng-click="linkClickedCallback();" target="_blank">$2</a>'
        });

        var html = elem.html();
        var newHtml = html;

        linkPatterns.forEach((item) => {
          newHtml = newHtml.replace(item.pattern, item.template);
        });

        if (html !== newHtml) {
          elem.html(newHtml);
          $compile(elem.contents())(scope);
        }
      }
    }
  };
}
Hungry Beast
  • 3,677
  • 7
  • 49
  • 75
  • Possible duplicate of [Easiest way to pass an AngularJS scope variable from directive to controller?](https://stackoverflow.com/questions/13318726/easiest-way-to-pass-an-angularjs-scope-variable-from-directive-to-controller) – Maher May 27 '17 at 05:00
  • I think it's slightly different. In my case I need to make the ng-click of the HTML elements trigger the controller function call and pass in an argument. That's what I can't get to work. – Hungry Beast May 28 '17 at 04:08
  • that mean you try send argument from Html like this: `link-clicked="itemClicked('etc')"` – Maher May 28 '17 at 04:29
  • Ok, let fix it together.. but before that what do mean of 'url of the anchor '? can you sample it please – Maher May 28 '17 at 04:35
  • @Maher Thanks for trying to help me out and offer to work through it! As I was cleaning up my post and following up with you I figured it out. Thanks again – Hungry Beast May 30 '17 at 02:11

2 Answers2

0

It's easy to implement with $scope.$emit and $scope.$on.

In your directive:

scope.$emit('passUrl', urlToPass);

In your controller:

$scope.$on('passUrl', function (event, data) {
  $log.debug(data); // received urlToPass variable from directive
})
P.S.
  • 15,970
  • 14
  • 62
  • 86
0

It looks like what I was missing was how to pass the arguments into the linkClickedCallback function on the controller. You need to pass in arguments to the function through an object {arg1: 5, arg2: 10} and then add them to the function in the HTML in the same order to pass them along to the controller.

I have created the object {link: 1} to pass into linkedClickedCallback where 1 is a hard coded value. When the example runs it outputs 1 and on the following line the "post" object defined in the HTML.

HTML:

<div ng-repeat="post in posts" >
    <div find-urls link-clicked="itemClicked(link, post)" ng-bind="post.content"><div>
</div>

Controller:

$scope.itemClicked = function(link, post) {
  console.log(link);
  console.log(post);
};

Directive:

function findUrls($compile) {
  return {
    restrict: 'AC',
    scope: {
        linkClickedCallback: '&linkClicked'
    },
    link: function (scope, elem, attrs) {
      if (attrs.ngBind) {
        scope.$watch(attrs.ngBind, _.debounce(wrapUrls));
      }
      if (attrs.ngBindHtml) {
        scope.$watch(attrs.ngBindHtml, _.debounce(wrapUrls));
      }

      function wrapUrls(text) {
        var linkPatterns = new Array(
        {
          pattern: /(^|[^\/])(www\.[\S]+(\b|$))/ig,
          template: '&nbsp;<a class="absolute_link" href="http://$2" ng-click="linkClickedCallback({link: 1});" target="_blank">$2</a>'
        },
        {
          pattern: /([a-z0-9._-]+@[a-z0-9._-]+\.[a-zA-Z0-9._-]+)/ig,
          template: '&nbsp;<a class="absolute_link" href="mailto:$1" ng-click="linkClickedCallback({link: 1});" target="_blank">$1</a>'
        },
        {
          pattern: /(^|[^a-z0-9@\\\/._-])([a-z0-9]{0,256}\.(com|net|org|edu)([a-z0-9\/?=\-_#]{0,256})?(\b|$))/ig,
          template: '&nbsp;<a class="absolute_link" href="http://$2" ng-click="linkClickedCallback({link: 1});" target="_blank">$2</a>'
        });

        var html = elem.html();
        var newHtml = html;

        linkPatterns.forEach((item) => {
          newHtml = newHtml.replace(item.pattern, item.template);
        });

        if (html !== newHtml) {
          elem.html(newHtml);
          $compile(elem.contents())(scope);
        }
      }
    }
  };
}

I still need to do some work to capture the link value and pass that along instead of the hard coded "1" but this shows how it needs to be done.

Hungry Beast
  • 3,677
  • 7
  • 49
  • 75