AngularJS - 如何在触发事件之前等待模板加载

时间:2015-09-22 14:47:45

标签: angularjs templates asynchronous

简单地说我的情况是我从运行阶段开始一个事件。在几个指令中,我听这个事件并执行代码。问题是在我的开发机器上,一些指令在编译指令之前通过templateUrl属性获取模板。因此,它将错过这一事件。可以使用$ locationChangeSuccess事件重现此行为。

var myApp = angular.module('myApp', []);

myApp.directive('directiveOne', function(){
    return {
        templateUrl: '/some/url.html',
        controller: function($rootScope){
            $rootScope.$on('$locationChangeSuccess', function(){
                console.log('Directive one callback');
            });
        }
    }
});

myApp.directive('directiveTwo', function(){
    return {
        template: '<div></div>',
        controller: function($rootScope){
            $rootScope.$on('$locationChangeSuccess', function(){
                console.log('Directive two callback');
            });
        }
    }
});

在此代码中,您将只看到记录的第二条日志消息,我希望这两条指令都能记录消息。

如何克服这个问题?我知道我可以创建一个将模板添加到$ templateCache的构建,但这是我的开发机器,我不想每次都进行构建。

2 个答案:

答案 0 :(得分:2)

要理解这个问题,您需要了解角度指令的生命周期 AND ui-router的架构。

该指令的捕捉是templatetemplateUrl。更有趣的是,你正在听指令的控制器函数中的$locationChangeSuccess

所以答案是因为指令加载templateUrl 异步。这意味着angular不会等待templateUrl完全加载(因为如果它,它将停止整个引导过程)。因此它继续遍历DOM节点,并继续在管道中应该做的任何事情。这当然包括加载控制器和火灾事件,进入特定状态等等。

现在如果$locationChangeSuccess的广播在之前触发指令完全加载,它将错过这个特定事件,因此,你将错过console.log

但是,如果新的$locationChangeSuccess再次发生 后加载指令(包括完成获取templateUrl,实例化自己的范围等),那么是的,您的控制台日志应该是再次抓住它。

我相信你的例子,$locationChangeSuccess只发生一次,这是在你的应用程序的初始加载期间,其中url被实例化。如果在加载DOM后实际强制另一个$locationChangeSuccess,则第一个指令将能够再次捕获该广播事件。

出于同样的原因,为什么template = "<div></div>"将起作用是因为该指令不需要异步获取它,因此在现场编译,并且DOM在$locationChangeSuccess事件之前呈现,并且能够控制台记录消息。

为了展示我的答案,我创建了一个plnkr。我在plnkr中使用$stateChangeSuccess,但你得到了要点。在这里,我通过单击按钮手动触发另一个stateChange,这在 指令加载后发生。瞧,它接收了广播!

TLDR:templateUrl是异步获取的,赶上locationChangeSuccess的火车已经很晚了。

希望这有帮助。

答案 1 :(得分:0)

指令被懒散地加载。我不相信angular会在运行阶段评估你的任何指令。你能详细说明你的要求吗?