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
改变
'<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>'
到
'<button id="createHost" class="btn btn-mini btn-success" onclick="angular.element(this).scope().create()"><b>Create</b></button>'
不错
【讨论】:
我们可以在没有范围的情况下执行此操作吗?我已经在工厂创建弹出窗口时声明了我的弹出模板。 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 在 ajax 数据表 + codeigniter 中不起作用