AngularJS如何操作渲染后动态生成的元素

前言:

jQuery中,动态生成的一个元素,想要进行后续操作,可通过delegate/on/live方法(在jquery3.0中已经废除了bind方法)。

AngularJS的事件监听机制针对的是已经生成的DOM进行操作,而在指令中动态生成的DOM节点或其他方式后添加的DOM,是不能被JS事件监听到。
换言之,非动态插入DOM的情况下,ng-click指令之所以生效,是因为AngularJS在编译阶段将绑定了ng-click的DOM绑定到了当前作用域。而在AngularJS编译阶段之后插入的DOM,当前作用域对于这个指令是未知的,所以不会生效。

实例:

1
2
3
4
5
6
7
8
9
10
var app = angular.module('app',[]);
app.directive('nav',function(){
return{
restrict:'AC',
template:'<div ng-click="navbar()">This is navbar.</div>',
link:function(scope,el,attr){
...
}
}
})

显而易见,这段代码会生成新的DOM:

1
<div ng-click="navbar()">This is navbar.</div>

但是,直接操作上述绑定的ng-click是不会生效的,原因就是前言中叙述的问题。

解决方法:

一、$compile
通过手动调用$compile服务,将DOM对象绑定到当前作用域,编译DOM,实现动态元素的事件绑定。

1
2
var template:'<div ng-click="navbar()">This is navbar.</div>',
var content = $compile(template)($scope);

或者这样:

1
2
3
4
5
6
7
8
9
// 在某个controller中,用jQuery删除动态生成的DOM
$compile($(this).remove())($scope);
// 用jQuery动态插入DOM
$('demo').html(
$compile(
'<div ng-click="nav()">' + 'nav' + '</div>'
)($scope)
);

原理是先编译DOM,然后编译后的DOM插入到静态节点中,便可实现动态元素的事件绑定。
而直接插入DOM至页面中,AngularJS并没有编译,所以ng指令绑定都是无效的。

同时不要忘了$compile服务注入:

1
2
3
app.directive('nav',function($compile){
})

二、ng-repeat
还有一种方式是不需要手动调用$compile服务,而是利用ng-repeat指令,比如:

1
2
3
4
<div class="form-control" ng-repeat="nav in navbar">
<p ng-click="lay()">@{{nav.text}}</p>
</div>
//项目后端使用的laravel框架所以需要在模版标签前加上`@`符号,防止后端框架编译。

由于ng-repeat会自动将数据内容插入至DOM中,且其本身也会重新编译DOM,相当于替换了手动调用$compile服务的过程,后续操作时只需给navbar数组添加数据即可。