AngularJS 自定义指令两种方式绑定
Posted
技术标签:
【中文标题】AngularJS 自定义指令两种方式绑定【英文标题】:AngularJS Custom Directive Two Way Binding 【发布时间】:2013-09-23 19:33:11 【问题描述】:如果我有一个没有模板的 AngularJS 指令,并且我希望它在当前范围内设置一个属性,那么最好的方法是什么?
例如,计算按钮点击次数的指令:
<button twoway="counter">Click Me</button>
<p>Click Count: counter </p>
使用指令将点击计数分配给双向属性中的表达式:
.directive('twoway', [
'$parse',
function($parse)
return
scope: false,
link: function(scope, elem, attrs)
elem.on('click', function()
var current = scope.$eval(attrs.twoway) || 0;
$parse(attrs.twoway).assign(scope, ++current);
scope.$apply();
);
;
])
有没有更好的方法来做到这一点?从我读过的内容来看,一个孤立的范围会过大,但我需要一个子范围吗?除了使用$parse
之外,还有没有更简洁的方法可以写回指令属性中定义的范围变量。我只是觉得这太难了。
完整的 Plunker here.
【问题讨论】:
这个问题似乎跑题了,因为它是关于代码审查的。 或者代码架构。我认为这是一个很好的问题。 【参考方案1】:将模板更改为:
<button twoway bind="counter">Click Me</button>
<p>Click Count: counter.val </p>
和指令:
.directive('twoway',
function()
return
scope:
localValue: '=?bind'
,
link: function(scope, elem, attrs)
scope.localValue =
val: 0
;
elem.on('click', function()
scope.localValue.val = scope.localValue.val + 1;
scope.$apply();
);
;
);
【讨论】:
你能解释一下这个问题的答案吗? 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高答案的长期价值。【参考方案2】:应用双向绑定的一个好方法是使用指令组件。这是我的解决方案。它允许使用 ng-repeat 和可扩展的数据绑定。
View Plunker
HTML
<body ng-controller='MainCtrl'>
Data: data
<hr>
<mydirective name='data[0]'></mydirective>
<hr>
<mydirective name='data[1]'></mydirective>
</body>
控制器
app.controller('MainCtrl', function($scope)
$scope.data = [];
$scope.data[0] = 'Marco';
$scope.data[1] = 'Billy';
);
指令
app.directive("mydirective", function()
return
restrict: "EA",
scope: name: '=',
template: "<div>Your name is : name</div>"+
"Change your name : <input type='text' ng-model='name' />"
;
);
在计数器的情况下,可以使用相同的方法。
【讨论】:
如何在我的指令控制器中访问 data[1] 以进行 HTTP get 调用 您可以将controller : myDirectivecontroller
作为返回对象的一部分添加到您的指令中,并让它在指令控制器中处理您的数据。我建议将所有 RESTful 请求保存在一个服务中,并在控制器中引用该服务,如下所示:function myDirectivecontroller(ServiceName) var ctrl = this; ...
@n.bharath 我用组件写了这个:plnkr.co/edit/4wOdA3OYkxS9vXAWfSxZ?p=preview
从 我很惊讶没有人提到ng-model
,这是执行两个数据绑定的默认指令。可能不是那么广为人知,但是链接函数还有第四个参数:
angular.module('directive-binding', [])
.directive('twoway',
function()
return
require: '?ngModel',
link: function(scope, elem, attrs, ngModel)
elem.on('click', function()
var counter = ngModel.$viewValue ? ngModel.$viewValue : 0
ngModel.$setViewValue(++counter);
scope.$apply();
);
;
);
在你看来
<button twoway ng-model="counter">Click Me</button>
<p>Click Count: counter </p>
第四个参数是ngModelController 的 API,它在处理(例如解析和格式化)以及在指令和作用域之间共享数据方面有很多用途。
这是更新后的Plunker。
【讨论】:
我希望在 ngshow/nghide 之类的东西之后对指令语法进行建模,它直接在其属性值中获取模型属性。不过,我很欣赏使用 ngModel 的实现——我还没有深入探索过。 然后去隔离范围,见道格的回答。【参考方案4】:不使用$parse
,你绝对可以像这样简化它
angular.module('directive-binding', []).directive('twoway', [function ()
return
scope: false,
link: function (scope, elem, attrs)
elem.on('click', function ()
scope[attrs.twoway] = scope[attrs.twoway] == null ? 1 : scope[attrs.twoway] + 1;
scope.$apply();
);
;
]);
【讨论】:
如果您在模型中使用“嵌套”对象,这似乎不起作用。例如,如果我使用“counter.val”而不是“counter”,这似乎不起作用。 Here's a Plunker -- 我的 JS 技能不是最好的,所以我可能错过了一些东西。 @DavidFaivre 您需要在控制器中初始化它,例如$scope.counter=; $scope.counter.val = 0
如果您有兴趣,请参阅this 通过字符串访问“嵌套”对象。这是这个解决方案的根本问题——你必须编写某种解析器。 $parser 服务或嵌套范围映射在 Angular 世界中为我们处理。
@DavidFaivre 您没有提到要在原始问题中使用嵌套对象。当您提出问题时,请确保您提出的问题清楚。【参考方案5】:
为什么隔离作用域过大了?它对这种事情非常有用:
scope:
"twoway": "=" // two way binding
,
这是这个问题的一个非常惯用的角度解决方案,所以这是我坚持的。
【讨论】:
Doug T。我本来想离开this SO post,但我可能只理解了四分之一。 这个答案的关键补充是你传递给这个指令的变量,例如counter
,必须是一个对象,例如obj.counter
否则您将无法获得正确的引用来更新父范围。以上是关于AngularJS 自定义指令两种方式绑定的主要内容,如果未能解决你的问题,请参考以下文章
在自定义指令的范围绑定中使用符号“@”、“&”、“=”和“>”:AngularJS