Javascript 带隔离作用域的AngularJS指令-我真的必须到处调用$parent吗?
我有一个angular.js指令来创建按钮(悬停类、左图标和右图标等)。我通过Javascript 带隔离作用域的AngularJS指令-我真的必须到处调用$parent吗?,javascript,angularjs,Javascript,Angularjs,我有一个angular.js指令来创建按钮(悬停类、左图标和右图标等)。我通过作用域:{uiButtonIconLeft:'@',uiButtonIconRight:'@'}使用按钮左右图标的自动绑定,以便将这些值绑定到父作用域中的数据。然而,这会导致angularjs创建一个“隔离”范围,这意味着在这样的情况下使用我的指令不起作用: <div ng-controller='someController'> <a ng-repeat='thing in things'
作用域:{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.
吗?
编辑
我为我的按钮“widget”确定的答案是避免使用隔离作用域,并通过
属性查看左右图标的属性值。$observe(…)
而不是通过作用域绑定。@
仅适用于本地作用域属性。请尝试&
,这样可以在父作用域的上下文中执行表达式
引自
&
或&attr
-提供在
父范围。如果未指定属性名,则属性名
假定与本地名称相同。给定
和小部件范围定义:{
localFn:'&myAttr'}
,然后隔离作用域属性localFn
将指向
count=count+value
表达式的函数包装器。经常
希望通过表达式从隔离范围传递数据
对于父作用域,这可以通过传递本地
将变量名和值放入表达式包装器fn中。例如
如果表达式是increment(amount)
,那么我们可以指定amount
通过调用localFn
作为localFn({amount:22})
约翰·林德奎斯特(John Lindquist)在其网站视频的17、18和19中对此进行了详细介绍。我想我理解你的意图。在您的指令中,只需配置隔离作用域,以便通过ng click属性映射到父级上所需的函数
scope: {
uiButtonIconLeft: '@',
uiButtonIconRight: '@',
clicky: '&ngClick'
}
有一种不使用显式作用域的方法,如果您编写的指令没有专门处理作用域中的元素,最好这样做:
function MyDirective () {
return {
link: function (scope, iElement, iAttrs) {
iAttrs.$observe("uiButtonLeft", function (val) {
if (val) {
iElement.attr(src, val); // whatever you want to do
}
});
}
}
如果希望指令使用隔离作用域,并且希望从HTML/标记中的同一元素调用父/控制器作用域上定义的方法,则可以使用$parent 通常,您不必在ng repeat中使用$parent,因为ng repeat通常创建一个子作用域,该子作用域通常从父/控制器作用域继承。因此,在ng repeat中调用一个方法会沿着原型链一直到父范围来查找该方法 由于您的指令创建了一个隔离作用域,每个ng repeat迭代都必须使用相同的隔离作用域,而不是它通常使用的作用域,因为它们是在同一元素上定义的。获取父作用域上定义的方法(从HTML)的唯一方法是使用$parent,因为在隔离作用域中没有可遵循的原型链 我们编写的任何自定义指令都需要记录创建的范围类型。例如,Angular文档指示哪些指令创建新范围。有关此问题的更多讨论,请参阅此答案的评论:
您的另一个选择是将指令更改为不使用隔离作用域,并使用属性指示指令应检查哪些作用域属性。尽可能避免使用
$parent
,这会降低灵活性。如果你深入,那么你必须做$parent.$parent.$parent…
,这是非常痛苦的。看看我的答案,没有隔离作用域,我不想要隔离作用域。我还是不太明白当初拥有它们的原因。我想我可以使用$scope.watch(…)
来达到我想要的效果,而不是编写指令来使用隔离作用域。@FMM,如果您想编写一个可重用的组件/指令来创建自己的作用域属性,隔离作用域非常有用。对于隔离作用域,您不必担心意外使用(父)作用域中已存在的作用域属性名称。因此,隔离作用域提供了安全性(作用域安全性)。如果不需要隔离作用域,有两个选项:1)不创建任何作用域-恢复元素的作用域2)使用scope:true
创建原型继承的子作用域。这两个选项都不需要使用$parent。感谢您的额外输入,它提供了非常丰富的信息。您获得了一个向上投票,但属性。$observe(…)
是我真正需要的。避免隔离范围似乎是我需要的,谢谢!我在指令#2中遇到了“$digest ready in progress”错误:刚开始熟悉AngularJS,这是我真正不喜欢的第一件事,因为我可能在某个时候在指令中有嵌套指令和更多控制器-非常棒的解决方案,谢谢!val+=“Hello”
应该做什么?这甚至不是有效的JavaScript语法。。。
<img ui-button ui-button-left="{{item.leftBtn}}"></img>
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>