我有一个angular.js指令来创建一个按钮(悬停类,左图和右图等)。我正在通过scope: { uiButtonIconLeft: '@', uiButtonIconRight: '@' }
使用按钮的左右图标的自动绑定,以便我可以将这些值绑定到父作用域的数据。但是,这会导致angularjs创建一个“隔离”范围,这意味着在这样的情况下使用我的指令不起作用:
<div ng-controller='someController'>
<a ng-repeat='thing in things'
ui-button
ui-button-icon-left='{{thing.icon}}'
ng-click='someMethodTheControllerPutOnTheScope(thing.id)'
>
I don't work, don't bother clicking me
</a>
</div>
我必须这样做:
<div ng-controller='someController'>
<a ng-repeat='thing in things'
ui-button
ui-button-icon-left='{{thing.icon}}'
ng-click='$parent.someMethodTheControllerPutOnTheScope($parent.thing.id)'
>
Holy leaky abstractions, Batman, it works!
</a>
</div>
我的问题是:这是惯用的吗?应该这样吗?我做错了吗?我们的英雄可以在他的标记中清除多余的,重复的,恼人的额外$parent.<whatever>
吗?
修改
我为我的按钮“widget”确定的答案是避免使用隔离范围并通过attributes.$observe(...)
观察左右图标的属性值,而不是通过范围进行绑定。
答案 0 :(得分:10)
有一种方法可以在不使用显式范围的情况下完成它,如果您正在编写一个不专门处理范围内元素的指令,最好这样做:
function MyDirective () {
return {
link: function (scope, iElement, iAttrs) {
iAttrs.$observe("uiButtonLeft", function (val) {
if (val) {
iElement.attr(src, val); // whatever you want to do
}
});
}
}
<img ui-button ui-button-left="{{item.leftBtn}}"></img>
有时候使用{{val}}
变得很麻烦,无论是对于干净的代码,还是您可能还想要更改val
。这是你如何做到的。
function MyDirective () {
return {
link: function (scope, iElement, iAttrs) {
iAttrs.$observe("uiButtonLeft", function (val) {
scope.$watch(val, function (valInScope) {
if (valInScope) {
iElement.attr(src, valInScope); // whatever you want to do
// the following statement updates the value in scope
// it's kinda weird, but it works.
scope.$apply(val + "= Hello"); // if you are out of angularjs, like jquery event
scope.$eval(val + = "Hello"); // if you are in angualrjs
// $apply can handle string, it's like ngClick
// you use in templates. It updates the value correctly.
}
}
});
}
}
<img ui-button ui-button-left="item.leftBtn"></img>
答案 1 :(得分:5)
@
仅适用于本地范围属性。请尝试使用&
,这允许您在父作用域的上下文中执行表达式。
来自http://docs.angularjs.org/guide/directive
,即可获得价值
&
或&attr
- 提供了一种在上下文中执行表达式的方法 父范围。如果未指定attr名称,则为属性名称 假定与本地名称相同。给定<widget my-attr="count = count + value">
和范围的小部件定义:{ localFn:'&myAttr' }
,然后隔离范围属性localFn
将指向count = count + value
表达式的函数包装器。经常 希望通过表达式从隔离范围传递数据 对于父作用域,可以通过传递本地地图来完成 变量名和值到表达式包装器fn中。例如, 如果表达式为increment(amount)
,那么我们可以指定amount
将localFn
称为localFn({amount: 22})
John Lindquist在他的网站egghead.io视频的17,18和19上详细介绍了这一点。
答案 2 :(得分:2)
我想我明白你要做什么。在您的指令中,只需将隔离范围配置为通过ng-click属性映射到您想要的功能。
scope: {
uiButtonIconLeft: '@',
uiButtonIconRight: '@',
clicky: '&ngClick'
}
答案 3 :(得分:2)
如果您希望您的指令使用隔离范围,并且您想要从HTML /标记中的同一元素调用父/控制器范围上定义的方法,那么使用$ parent就可以了。
通常,您不必在ng-repeat中使用$ parent,因为ng-repeat通常会创建一个原型继承父/控制器范围的子范围。因此,在ng-repeat中调用一个方法跟随原型链到父范围以找到方法。
由于您的指令创建了隔离范围,因此每个ng-repeat迭代都被强制使用相同的隔离范围而不是通常使用的范围,因为它们是在同一元素上定义的。获取父作用域(从HTML)定义的方法的唯一方法是使用$ parent,因为没有原型链可以从隔离范围中跟随。
我们编写的任何自定义指令都需要记录创建哪种范围。例如,Angular文档指出哪些指令创建新范围。有关此问题的更多讨论,请参阅此答案的评论:https://stackoverflow.com/a/14345214/215945
您的另一个选择是将指令更改为不使用隔离范围,并使用属性指示指令应检查的范围属性。