AngularJs 指令:如何在 ng-repeat 元素上动态设置属性
AngularJs Directive: How to dynamically set attributes on ng-repeat element
我对 AngularJS 比较陌生。在尝试创建指令时,我遇到了这个问题:How to dynamically add / remove attributes on the children of the directive's element when these children are dynamically added with 'ng-repeat'?
首先,我想到了这个解决方案:
模板
...
a.list-group-item(ng-repeat='playlist in playlists', ng-click='addToPlaylist(playlist, track)', ng-href='playlist/{{ playlist._id }})
...
*指令
link: function(scope, elm, attrs) {
var listItems = angular.element(element[0].getElementsByClassName('list-group-item')
angular.forEach(listItems, function(item, index) {
'add' in attrs ? item.removeAttr('href') : item.removeAttr('ng-click');
listItems[index] = item;
}
...
结果
事实证明,我的代码从未进入这个 angular.forEach
循环,因为 listItems 是空的。我想这是因为 ng-repeat
正在等待 scope.playlists 填充通过 $resource.
对服务器的异步调用的数据
临时修复
在指令定义中,我添加了一个布尔变量来检查元素属性中是否存在 'add':var adding = 'add' in attrs ? true : false;
然后在模板中,
a.list-group-item(ng-if='adding', ng-repeat='playlist in playlists', ng-click='addToPlaylist(playlist, track)')
a.list-group-item(ng-if='!adding', ng-repeat='playlist in playlists', ng-href='playlist/{{playlist._id }}')
虽然它工作正常,但显然一点也不干。帮助!
您尝试做事的方式可能不是最Angularish(Angularist?Angularyist?)方式。当您在此处尝试使用 angular.element()
到 select 子元素时,您可以确保子元素已准备就绪,如下所示:
link: function(scope, elm, attrs) {
elm.ready(function() {
var listItems = angular.element(element[0].getElementsByClassName('list-group-item')
angular.forEach(listItems, function(item, index) {
'add' in attrs ? item.removeAttr('href') : item.removeAttr('ng-click');
listItems[index] = item;
}
});
}
但是,这不太可能适用于您的情况,因为 。如果您想避免使用您已有的解决方案(我认为这比您的第一次尝试更好),您将不得不完全重新实现您的代码。
我建议使用指令定义对象的 require
属性 定义一个附加指令 communicates with its parent directive。新指令可以访问父指令的 add
属性(父指令的 控制器 中的 this.add
)并且可以被编程为相应的行为.该解决方案的实施超出了此答案的范围。
更新:
我决定尝试一下实现。该示例已高度简化,但它完成了您想要做的事情:根据传递给它的属性更改指令的模板。请参阅示例 here。
该示例使用 Angular 1 中的新功能:components. You can read more about injectable templates and components here。本质上,组件允许您使用可以访问元素及其属性的函数来定义模板,如下所示:
app.component('playlistComponent', {
// We can define out template as a function that returns a string:
template: function($element, $attrs) {
var action = 'add' in $attrs
? 'ng-click="$ctrl.addToPlaylist(playlist, track)"'
: 'ng-href="playlist/{{playlist._id}}"';
return '<a class="list-group-item" ng-repeat="playlist in playlists" ' +
action + '></a>';
},
// Components always use controllers rather than scopes
controller: ['playlistService', function(playlists) {
this.playlists = playlists;
this.addToPlaylist = function(playlist, track) {
// Some logic
};
}]
});
不要删除属性,而是更改您的点击处理程序。
将$event
添加到参数列表中并有条件地使用preventDefault()
。
<a ng-click='addToPlaylist($event,playlist)' ng-href='playlist'>CLICK ME</a>
在您的控制器中:
$scope.addToPlaylist = function(event,playlist) {
if (!$scope.adding) return;
//otherwise
event.preventDefault();
//do add operation
};
不添加时,取函数returns和href。否则默认值被阻止,点击处理程序执行添加操作。
来自文档:
$event
Directives like ngClick
and ngFocus
expose a $event
object within the scope of that expression. The object is an instance of a jQuery Event Object when jQuery is present or a similar jqLite object.
我对 AngularJS 比较陌生。在尝试创建指令时,我遇到了这个问题:How to dynamically add / remove attributes on the children of the directive's element when these children are dynamically added with 'ng-repeat'?
首先,我想到了这个解决方案:
模板
...
a.list-group-item(ng-repeat='playlist in playlists', ng-click='addToPlaylist(playlist, track)', ng-href='playlist/{{ playlist._id }})
...
*指令
link: function(scope, elm, attrs) {
var listItems = angular.element(element[0].getElementsByClassName('list-group-item')
angular.forEach(listItems, function(item, index) {
'add' in attrs ? item.removeAttr('href') : item.removeAttr('ng-click');
listItems[index] = item;
}
...
结果
事实证明,我的代码从未进入这个 angular.forEach
循环,因为 listItems 是空的。我想这是因为 ng-repeat
正在等待 scope.playlists 填充通过 $resource.
临时修复
在指令定义中,我添加了一个布尔变量来检查元素属性中是否存在 'add':var adding = 'add' in attrs ? true : false;
然后在模板中,
a.list-group-item(ng-if='adding', ng-repeat='playlist in playlists', ng-click='addToPlaylist(playlist, track)')
a.list-group-item(ng-if='!adding', ng-repeat='playlist in playlists', ng-href='playlist/{{playlist._id }}')
虽然它工作正常,但显然一点也不干。帮助!
您尝试做事的方式可能不是最Angularish(Angularist?Angularyist?)方式。当您在此处尝试使用 angular.element()
到 select 子元素时,您可以确保子元素已准备就绪,如下所示:
link: function(scope, elm, attrs) {
elm.ready(function() {
var listItems = angular.element(element[0].getElementsByClassName('list-group-item')
angular.forEach(listItems, function(item, index) {
'add' in attrs ? item.removeAttr('href') : item.removeAttr('ng-click');
listItems[index] = item;
}
});
}
但是,这不太可能适用于您的情况,因为
我建议使用指令定义对象的 require
属性 定义一个附加指令 communicates with its parent directive。新指令可以访问父指令的 add
属性(父指令的 控制器 中的 this.add
)并且可以被编程为相应的行为.该解决方案的实施超出了此答案的范围。
更新:
我决定尝试一下实现。该示例已高度简化,但它完成了您想要做的事情:根据传递给它的属性更改指令的模板。请参阅示例 here。
该示例使用 Angular 1 中的新功能:components. You can read more about injectable templates and components here。本质上,组件允许您使用可以访问元素及其属性的函数来定义模板,如下所示:
app.component('playlistComponent', {
// We can define out template as a function that returns a string:
template: function($element, $attrs) {
var action = 'add' in $attrs
? 'ng-click="$ctrl.addToPlaylist(playlist, track)"'
: 'ng-href="playlist/{{playlist._id}}"';
return '<a class="list-group-item" ng-repeat="playlist in playlists" ' +
action + '></a>';
},
// Components always use controllers rather than scopes
controller: ['playlistService', function(playlists) {
this.playlists = playlists;
this.addToPlaylist = function(playlist, track) {
// Some logic
};
}]
});
不要删除属性,而是更改您的点击处理程序。
将$event
添加到参数列表中并有条件地使用preventDefault()
。
<a ng-click='addToPlaylist($event,playlist)' ng-href='playlist'>CLICK ME</a>
在您的控制器中:
$scope.addToPlaylist = function(event,playlist) {
if (!$scope.adding) return;
//otherwise
event.preventDefault();
//do add operation
};
不添加时,取函数returns和href。否则默认值被阻止,点击处理程序执行添加操作。
来自文档:
$event
Directives like
ngClick
andngFocus
expose a$event
object within the scope of that expression. The object is an instance of a jQuery Event Object when jQuery is present or a similar jqLite object.