我需要推迟嵌套在另一个指令中的指令的处理,直到嵌套指令执行异步操作。这很容易用两行JQuery完成,但我想知道是否有纯粹的Angular方法来做同样的事情,也许使用$ q。
在http://jsfiddle.net/4smtgs3f/1/中,你可以找到我的意思的一个例子:
<div ng-controller="MyCtrl">
<loadData url="http://ip.jsontest.com/">
<transformAndOutput/>
</loadData>
</div>
loadData正在从某个URI加载数据,而一个或多个转换器处理数据的处理和显示。顺便说一下,在JSFiddle中我使用两个不同的loadData指令:loadData1异步使用 $ http 并且无法及时加载数据,而loadData2同步使用JQuery $。ajax 并且正常工作很好。
所以问题是: $ http 只能异步工作,并且在异步加载操作完成之前处理内部指令。是否有一种有角度的方式来获得相同的结果?
我知道可以推迟使用then或$ q之类的用户定义函数的执行,但是我可以推迟处理指令吗?我该怎么办?
感谢您所能做的一切。
FV
答案 0 :(得分:2)
你还没有充分考虑'Angular方式'。 :)
时间问题
您在link
功能中创建指令内容,这意味着您当时必须拥有所有内容。正如您所注意到的,这是一个错误的假设。当新数据可用时(即异步操作完成时),必须允许内容更新。
操纵DOM的Angular方式是双向绑定。显示content
代替指令的惯用方法是为指令编写模板。
function myDirective() {
return {
...
template: '<div>{{someVar}}</div>',
...
};
}
使用这种技术,每次content
更新时DOM都会更新(这就是为什么我们使用Angular吧?)。在transformAndOutput
指令中添加模板,然后移除elm.append
函数中的link
行。现在,当异步回调更新content
时,DOM将更新以反映更改。
你会注意到在这个新的演示中,两行显示The value of content as called by loadData2 is: 2.0.171.17
,这不是你所期望的。这给我们带来了第二个问题。
<强>作用域强>
指令通常应该有自己独立的范围,这样它们就不会“弄脏”主机范围,或者导致与其他组件发生冲突。在您提供的代码中,您的两个指令都通过读写scope.data
和scope.callingFunction
来修改其主机范围,因此存在冲突。
要使指令具有自己的范围,请使用scope
选项。
function myDirective() {
return {
...
scope: true,
...
};
}
指令范围不继承主机范围。但是,您可以从主机范围导入一些数据。我不会在这里详述,因为不需要回答这个问题。请参阅Angular's Guide to Directives。
另一方面,嵌套指令的范围 继承父指令的范围。这意味着transformAndOutput
指令可以访问其父loadData
范围的属性。您应该通过向transformAndOutput
添加loadData
选项来对require: '^loadData'
要求父transformAndOutput
进行编码(在演示中,它是loadData1
或loadData2
所以我无法添加此选项。)
将scope: true
添加到您的loadData1
和loadData2
指令中,以便他们各自拥有自己的content
和callingFunction
。这些变量的前一个持有者 - 控制器 - 现在可以安全地移除。
最后一件小事:你的指令应该在JS中使用类似HTML的名称(小写+破折号)和类似JS的名字(camel case)。转换由Angular自动处理。
最终代码
app.directive('loadData1', function($http) {
return {
restrict: 'E',
replace: true,
scope: true,
link: function(scope, elm, attrs) {
scope.callingFunction = 'loadData1'
// the following to remove bad CORS warnings
delete $http.defaults.headers.common['X-Requested-With'];
$http.get(attrs.url).success(function(data) {
scope.content = data.ip;
})
},
};
})
app.directive('transformAndOutput', function() {
return {
restrict: 'E',
scope: true,
template: '<p>The value of content as called by {{callingFunction}} is: {{content}}</p>',
};
})