0

I have an array of objects and mapping them while inserting a dynamic html content (it works and displays properly):

this.arr.map(function(val) {
        val.about = val.about.substring(0,150) + " <span ng-click='showMoreInfo()' class='show-more-info'>...more</span>";
    });

I searched a couple of topics and tried to do sth like this:

var element = angular.element(document.querySelector('.show-more-info'));
    element.bind('click', $scope.showMoreInfo);

showMoreInfo() is supposed to just show an alert.

How can I make this work?

Shepherd
  • 273
  • 1
  • 2
  • 12

3 Answers3

0

Instead of injection html, you can simply do this: having vals array and trim in $scope.trim function an do your stuff in showMoreInfo

 <span ng-repeat="val in vals" ng-click='showMoreInfo()' class='show-more-info'>{{trim(val)}}</span>
asdf_enel_hak
  • 7,474
  • 5
  • 42
  • 84
  • It's not about trimming anything. I have a JSON file and one of the key contains a really long string. So I want to take some part of it (substring) and add a clickable span that will expand the text. I can't do it in the template, it must go dynamically from the controller but the binding doesn't work – Shepherd Dec 13 '16 at 12:18
0

You can send all info through click method as parameter. Try this instead.

this.arr.map(function(val) {
        var abt = val.about;
        val.about = val.about.substring(0,150) + " <span ng-click='showMoreInfo('"+ abt +"')' class='show-more-info'>...more</span>";
    });

Click method

$scope.showMoreInfo = function (about) {
    alert(about);
}
digit
  • 4,479
  • 3
  • 24
  • 43
  • That's not the case. The case is that the click event doesn't fire whatsoever. – Shepherd Dec 13 '16 at 13:33
  • Oh, i thought you have an issue with sending info to the click method. There is other way you can do it. Just use ng-repeat in table row and put ng-click in the row instead of doing that way. – digit Dec 13 '16 at 14:02
  • Btw, if you insisted doing that way, i think it is more complicated when u need to use angular directive to compile new dom element. I refer to this link -> [link](http://stackoverflow.com/questions/19267979/ng-click-not-working-from-dynamically-generated-html) – digit Dec 13 '16 at 14:09
0

Your ng-click="showMoreInfo()" isn't firing because the ng-click directive isn't being compiled (angular is totally unaware of it) so the click behavior is never fired.

You want to read up on the $compile service if you're going heavy on dynamic content with angular directives.

Here's a plunkr that demonstrates $compile and why your code isn't working.

Here's the script from the demo plunk. The "win" directive correctly handles changes to the DOM, and the "fail" directive does not.

app = angular.module("app", [])
  .controller("myController",function($scope) {
     $scope.showMoreInfo = function() {
          alert("Win Moar!");
        }
  })
  .directive("win", ['$compile', function($compile) {
    return {
      restrict: "E",
      scope: {
        appendToId: "@",
      },
      template: "<button ng-click='click()'>ng-click's Inserted From Here Wins!</button>",
      link: function(scope, elem, attrs) {
        scope.click = function() {
          let target = angular.element(document.querySelector("#" + scope.appendToId)),
            content = target.html()
            ;
          content += ("<p><span ng-click='showMoreInfo()' class='show-more-info'>...more</span></p>");
          target.html(content);
          /**
           * The $compile service compiles an HTML string or DOM into a 
           * template and produces a template function, 
           * which can then be used to link scope and the template together.
           * 
           * Because the html of target is compiled  it's directives are going 
           * to get compiled, namely ng-click='showMoreInfo()'
           * 
           * Note the passing target.scope() instead of scope...
           */
          $compile(target)(target.scope());
        }
      }
    }
  }]).directive("fail", function() {
    return {
      restrict: "E",
      scope: {
        appendToId: "@",
      },
      template: "<button ng-click='click()'>ng-click's Inserted From Here Fail :(</button>",
      link: function(scope, elem, attrs) {
        scope.click = function() {
          let target = angular.element(document.querySelector("#" + scope.appendToId)),
            content = target.html()
            ;
          content += ("<p><span ng-click='showMoreInfo()' class='show-more-info'>...more</span></p>");
          /**
           * Changing the DOM doesn't cause angular to process changes 
           * e.g. compile directives like ng-click so the ng-click in 
           * the content doesn't work.
           */
          target.html(content);
        }
      }
    }
  })

As an aside, it is generally considered bad practice to perform DOM manipulations from controllers.

Community
  • 1
  • 1
RamblinRose
  • 4,883
  • 2
  • 21
  • 33