ng-click 在动态生成的 HTML 中不起作用

Posted

技术标签:

【中文标题】ng-click 在动态生成的 HTML 中不起作用【英文标题】:ng-click not working from dynamically generated HTML 【发布时间】:2013-10-16 13:45:01 【问题描述】:

HTML

<table data-ng-table="tableParams" class="table table-bordered table-hover " style="border-collapse:collapse" data-ng-init="host.editSave = false" >
    <tr id="newTransaction">
    </tr>
    <tr data-ng-repeat="host in hosts|filter:search:strict" >
       <td class="hostTableCols" data-ng-hide="host.editSave">host.hostCd</td>
       <td class="hostTableCols" data-ng-hide="host.editSave">host.hostName</td>
    </tr>
</table>

jQuery

$('#newTransaction').append(
 '<td contenteditable><input type="text" class="editBox" value=""/></td>'+ 
 '<td contenteditable><input type="text" class="editBox" value=""/></td>'+
 '<td>'+
    '<span>'+
        '<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>'+
    '</span>'+
 '</td>'
);

角度脚本

$scope.create = function() 
       alert("Hi");
    ;

这里在 AngularJS 的控制器部分中调用的函数没有从 ng-click 事件中获得触发。 html 已成功附加,但 ng-click 不起作用。告诉我解决方案以使其发挥作用

【问题讨论】:

您需要编译新的 dom 元素才能使 angularjs 工作...您是否在可以访问范围的指令/控制器中进行此操作 @ArunPJohny:我正在从控制器调用该函数。但是我应该把编译功能放在哪里?在指令中?? 我不知道确切的场景,但你可以使用ng-include 和模板来做类似的事情。 【参考方案1】:

不是一个完美的修复,仍然!!! - 只是为了展示如何进行动态编译

app.controller('AppController', function ($scope, $compile) 

    var $el = $('<td contenteditable><input type="text" class="editBox" value=""/></td>' +
        '<td contenteditable><input type="text" class="editBox" value=""/></td>' +
        '<td>' +
        '<span>' +
        '<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>' +
        '</span>' +
        '</td>').appendTo('#newTransaction');
    $compile($el)($scope);

    $scope.create = function()
        console.log('clicked')
    
)

演示:Fiddle

不要使用控制器进行 dom 操作 - 必须借助指令来完成

【讨论】:

这个方法我已经试过了,不知道$compile...所以从jquery试了 @MaximShoustin: 我们不应该使用控制器的 DOM 操作吗?有什么原因吗? @KiranKumar 可用性、代码清晰性、维护性。控制器应该关注业务逻辑,而不是界面操作。 如果您通过 $scope 不可用的服务添加 HTML,如何实现? @trainoasis 您可以尝试使用父元素范围,例如$('#newTransaction').scope()$compile($el)($('#newTransaction').scope());【参考方案2】:

要使ng-click 工作,我们需要使用$compile 服务编译这个源代码。 Angular 应该知道新生成的 HTML,因此应该包含这个 HTML 来消化循环,以便触发 ng-click 和其他事件。

Fiddle

创建“编译器”:

.directive( 'compileData', function ( $compile ) 
  return 
    scope: true,
    link: function ( scope, element, attrs ) 

      var elmnt;

      attrs.$observe( 'template', function ( myTemplate ) 
        if ( angular.isDefined( myTemplate ) ) 
          // compile the provided template against the current scope
          elmnt = $compile( myTemplate )( scope );

            element.html(""); // dummy "clear"

          element.append( elmnt );
        
      );
    
  ;
);

之后,创建一个虚拟的factory 来模拟你的附加

.factory( 'tempService', function () 
  return function ()  
    return '<td contenteditable><input type="text" class="editBox" value=""/></td>'+ 
            '<td contenteditable><input type="text" class="editBox" value=""/></td>'+
             '<td>'+
                '<span>'+
         '<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>'+
              '</span>'+
            '</td>';
  ;
);

最后这样称呼它:

<div compile-data template="mainPage"></div> 

在控制器中:

$scope.newTransaction= tempService();

你的例子应该是这样的:

<table data-ng-table="tableParams" class="table table-bordered table-hover " style="border-collapse:collapse" data-ng-init="host.editSave = false" >
    <tr compile-data template="newTransaction">
    </tr>
    <tr data-ng-repeat="host in hosts|filter:search:strict" >
       <td class="hostTableCols" data-ng-hide="host.editSave">host.hostCd</td>
       <td class="hostTableCols" data-ng-hide="host.editSave">host.hostName</td>
    </tr>
</table>

顺便说一句,现在您可以在代码上使用相同的指令并编译任何动态 HTML。

【讨论】:

我应该实现从指令中追加 html 而不是通过 jquery 来实现吗? 正如我在示例中展示的那样,使用 Service 并添加控制器 $scope.newTransaction= tempService(); @KiranKumar 添加了 Fiddle 以让您了解它的工作原理 分享一下我的情况,我使用 Handlebar 为表格加载模板,因为当数据变重时 ng-repeat 会很慢。我将@Maxim Shoustin 解决方案与$compile( handleCompiledContent )( scope ); 一起应用,然后将其附加到DOM,然后使用jQuery 将其插入。它即时工作。但需要指出的一点是,如果在对象或数组循环下渲染,ng-click will 的把手中的this 将不起作用。它在句柄中引用对象/数组变量。 如果我可以使用给定的 compile-data 指令预定义 div 怎么办,因为服务会创建它?并且也无法通过服务内的 $scope 进行编译...我会插入带有 compile-data 指令的 div,但谁会先编译它以识别指令...那对我来说同样的问题?【参考方案3】:

你可以使用angular.element(this).scope()而不使用ng-click

改变

'&lt;button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"&gt;&lt;b&gt;Create&lt;/b&gt;&lt;/button&gt;'

'&lt;button id="createHost" class="btn btn-mini btn-success" onclick="angular.element(this).scope().create()"&gt;&lt;b&gt;Create&lt;/b&gt;&lt;/button&gt;' 不错

【讨论】:

我们可以在没有范围的情况下执行此操作吗?我已经在工厂创建弹出窗口时声明了我的弹出模板。 init如何发送参数? @Sana angular.element(this).scope().init(1,'false');这么简单 我正在使用它,但它说视频未定义。任何想法返回 '';跨度> 您不能将 ng-repeat 迭代项作为参数传递给函数。【参考方案4】:

我需要让 Cordova 在新窗口中打开动态链接,所以我的解决方案是将 ng-click 放在父元素上并查看 event.target 以查看点击了什么:

<p ng-bind-html="foo.barhtml" ng-click="generalClick($event)"></p>

然后

.controller('FooCtrl', function ($scope) 
    var html = '<a href="http://www.google.com">google.com</a>';

    $scope.foo.barhtml = html.replace(/href/g, 'data-href');

    $scope.generalClick = function(event)
        // have Cordova open the link in a browser window
        window.open(event.target.attributes['data-href'].value, '_system');
    
)

【讨论】:

【参考方案5】:

您需要在此处添加 $compile 服务,它将诸如 ng-click 之类的角度指令绑定到您的控制器范围。类似于:

var divTemplate = '..your div template';
var temp = $compile(divTemplate)($scope); 

然后将其附加到 HTML:

angular.element(document.getElementById('foo')).append(temp);

您还可以将事件绑定到 div,如下所示:

var div = angular.element("divID");
div.bind('click', $scope.addPhoto());

【讨论】:

如果您出于某种原因在服务中添加 HTML,将无法正常工作。

以上是关于ng-click 在动态生成的 HTML 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

ng-click 在指令中不起作用

ng-click 在 ajax 数据表 + codeigniter 中不起作用

Angular Ng-click 功能在按钮中不起作用

AngularJS 设置禁用/启用按钮而不使用 ng-disabled 和 ng-click 动态生成的 html

样式在 Gmail 中不起作用

以编程方式添加按钮在 API 级别 23 中不起作用。我需要动态生成按钮。我该如何添加它们?