【问题标题】:Angular - injecting dynamic content with ng-click from controllerAngular - 使用控制器的 ng-click 注入动态内容
【发布时间】:2016-12-13 12:04:01
【问题描述】:

我有一个对象数组并在插入动态 html 内容时映射它们(它可以正常工作并显示):

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

我搜索了几个主题并尝试这样做:

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

showMoreInfo() 应该只显示警报。

我怎样才能做到这一点?

【问题讨论】:

    标签: angularjs


    【解决方案1】:

    您可以简单地执行以下操作,而不是注入 html:在 $scope.trim 函数中使用 vals 数组和修剪,然后在 showMoreInfo 中完成您的工作

     <span ng-repeat="val in vals" ng-click='showMoreInfo()' class='show-more-info'>{{trim(val)}}</span>
    

    【讨论】:

    • 这不是修剪任何东西。我有一个 JSON 文件,其中一个键包含一个很长的字符串。所以我想取其中的一部分(子字符串)并添加一个可点击的跨度来扩展文本。我不能在模板中做到这一点,它必须从控制器动态地去,但绑定不起作用
    【解决方案2】:

    您可以通过click方法作为参数发送所有信息。试试这个吧。

    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>";
        });
    

    点击方式

    $scope.showMoreInfo = function (about) {
        alert(about);
    }
    

    【讨论】:

    • 事实并非如此。情况是 click 事件不会触发。
    • 哦,我以为您在向 click 方法发送信息时遇到了问题。还有其他方法可以做到这一点。只需在表格行中使用 ng-repeat 并将 ng-click 放在行中,而不是这样做。
    • 顺便说一句,如果你坚持这样做,我认为当你需要使用 angular 指令来编译新的 dom 元素时会更复杂。我参考这个链接->link
    【解决方案3】:

    你的 ng-click="showMoreInfo()" 没有被触发,因为 ng-click 指令没有被编译(角度完全不知道它)所以点击行为永远不会被触发。

    如果您对带有角度指令的动态内容很感兴趣,您想阅读$compile service

    Here's a plunkr 演示 $compile 以及为什么您的代码无法正常工作。

    这是来自演示 plunk 的脚本。 “win”指令正确处理对 DOM 的更改,而“fail”指令不能。

    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);
            }
          }
        }
      })
    

    顺便说一句,通常认为bad practice 从控制器执行 DOM 操作。

    【讨论】: