延迟处理AngularJs中的指令

时间:2014-08-22 13:43:23

标签: javascript angularjs angularjs-directive

我需要推迟嵌套在另一个指令中的指令的处理,直到嵌套指令执行异步操作。这很容易用两行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

1 个答案:

答案 0 :(得分:2)

你还没有充分考虑'Angular方式'。 :)

时间问题

您在link功能中创建指令内容,这意味着您当时必须拥有所有内容。正如您所注意到的,这是一个错误的假设。当新数据可用时(即异步操作完成时),必须允许内容更新。

操纵DOM的Angular方式是双向绑定。显示content代替指令的惯用方法是为指令编写模板。

function myDirective() {
    return {
        ...
        template: '<div>{{someVar}}</div>',
        ...
    };
}

使用这种技术,每次content更新时DOM都会更新(这就是为什么我们使用Angular吧?)。在transformAndOutput指令中添加模板,然后移除elm.append函数中的link行。现在,当异步回调更新content时,DOM将更新以反映更改。

DEMO

你会注意到在这个新的演示中,两行显示The value of content as called by loadData2 is: 2.0.171.17,这不是你所期望的。这给我们带来了第二个问题。

<强>作用域

指令通常应该有自己独立的范围,这样它们就不会“弄脏”主机范围,或者导致与其他组件发生冲突。在您提供的代码中,您的两个指令都通过读写scope.datascope.callingFunction来修改其主机范围,因此存在冲突。

要使指令具有自己的范围,请使用scope选项。

function myDirective() {
    return {
        ...
        scope: true,
        ...
    };
}

指令范围不继承主机范围。但是,您可以从主机范围导入一些数据。我不会在这里详述,因为不需要回答这个问题。请参阅Angular's Guide to Directives

另一方面,嵌套指令的范围 继承父指令的范围。这意味着transformAndOutput指令可以访问其父loadData范围的属性。您应该通过向transformAndOutput添加loadData选项来对require: '^loadData'要求父transformAndOutput进行编码(在演示中,它是loadData1loadData2所以我无法添加此选项。)

scope: true添加到您的loadData1loadData2指令中,以便他们各自拥有自己的contentcallingFunction。这些变量的前一个持有者 - 控制器 - 现在可以安全地移除。

DEMO

最后一件小事:你的指令应该在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>',
    };
})