只有在 AngularJS 中的初始化完成后才运行控制器 [英] Run controllers only after initialization is complete in AngularJS

查看:20
本文介绍了只有在 AngularJS 中的初始化完成后才运行控制器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些全局数据需要在我的 AngularJS 应用程序中执行任何控制器之前加载(即在 AngularJS 中全局解析依赖项).

I have some global data that needs to be loaded before any controller is executed in my AngularJS application (i.e. resolve dependencies globally in AngularJS).

例如,我有一个带有 getCurrentUser() 方法的 UserService 向后端服务器发出请求,以获取有关当前已验证用户的数据.我有一个控制器需要这些数据才能启动另一个请求(例如加载用户的余额).

For example, I have a UserService with the getCurrentUser() method which does a request to the backend server in order to get data about the currently authenticated user. And I have a controller that needs this data in order to launch yet another request (for example to load user's balance).

我怎样才能做到这一点?

How can I achieve that?

推荐答案

更新

请考虑使用«如果可能,使用服务器端数据异步引导 AngularJS 应用程序» 文章.

您现在可以使用 angular-deferred-bootstrap 模块来实现这一目标!

You can use the angular-deferred-bootstrap module to achieve that now!

我不再确定这个答案的有效性,您仍然可以使用这些想法,但一定要使用您的实际代码对其进行正确测试.我会尽量保持这个答案是最新的,从来没有技术.

I'm not sure about validity of this answer anymore, you can still use the ideas, but be sure to properly test it with your actual code. I will try to keep this answer up to date with never technologies.

有几种方法可以解决异步应用程序初始化的问题.

There are several approaches to the problem of asynchronous application initialization.

当涉及到在调用单个控制器之前必须解析的数据时 - 您可以轻松使用 ngRoute$routeProviderresolve 选项代码>.但是,当您需要在调用任何控制器之前加载一些全局数据时,您必须即兴发挥.

When it comes to data that must be resolved before a single controller is called - you can easily use resolve option of ngRoute's $routeProvider. However, when you need some global data to be loaded before ANY controller is called - you have to improvise.

我已尝试在此答案中收集所有可能的解决方案.我是按优先顺序提供的.

I've tried to collect all possible solutions in this answer. I'm providing them in the order of preference.

当使用 ui-router 而不是原生的 ngRoute 时在激活子状态之前,您可以创建一个抽象的根状态并解析其中的所有数据.

When using ui-router instead of native ngRoute you can create an abstract root state and resolve all data in it, before sub-states are activated.

我建议使用这种方法.ui-router 提供了许多附加功能,包括分层解析依赖项的能力,并被开发者社区广泛接受.

I would recommend to use this approach. ui-router provides a lot of additional features including ability to resolve dependencies hierarchically and is well accepted by the developer community.

module.config(function($urlRouterProvider, stateHelperProvider) {
    $urlRouterProvider.otherwise('/404');
    stateHelperProvider.setNestedState({
        name: 'root',
        template: '<ui-view/>',
        abstract: true,
        resolve: {
            user: function(UserService) {
                // getCurrentUser() returns promise that will be resolved
                // by ui-router before nested states are activated.
                return UserService.getCurrentUser();
            }
        },
        children: [{
            name: 'index',
            url: '/',
            templateUrl: '/partials/index'
        }, {
            name: 'not-found',
            url: '/404',
            templateUrl: '/partials/404'
        }, {
            name: 'balance',
            url: '/balance',
            templateUrl: '/partials/balance',
            resolve: {
                balance: function(UserService, user) {
                    // Using data resolved in parent state.
                    return UserService.getBalanceByAccountId(user.accountId);
                }
            }
        }]
    });
});

stateHelper 将有助于在使用抽象根范围方法时大大减少代码.

The stateHelper will help greatly to reduce the code when using abstract root scope approach.

Root 作用域被定义为抽象的,所以不能直接激活,也没有 URL.

Root scope is defined as abstract so can not be activated directly and it has no URL.

template: '<ui-view/>' 是正确呈现嵌套视图所必需的.

template: '<ui-view/>' is required for nested views to be properly rendered.

您可以做出承诺并将它们添加到根控制器内的 $rootScope 中,即 run() 函数.

You can make promises and add them to the $rootScope inside of your root controller, i.e. run() function.

我创建了一个 Plunk 来演示这个想法:http://plnkr.co/edit/gpguG5Y2S4KOz1KOKzXe?p=preview

I've created a Plunk to demonstrate the idea: http://plnkr.co/edit/gpguG5Y2S4KOz1KOKzXe?p=preview

这是一个完美的解决方案,但是,它使代码膨胀,使其更难使用和理解(回调地狱).仅当第一种方法不适合您时,我才会推荐它.

This is a perfectly working solution, however, it bloats the code and makes it harder to use and understand (callback hell). I would recommend it only if the first approach is not working for you.

您可以将所有初始化数据直接包含在服务器上生成的 HTML 页面中,并从您的应用程序访问它.

You can include all initialization data directly to the HTML page generated on the server and access it from your application.

考虑这个例子:

<html>

<body>

    <script src="application.js"></script>
    <script type="text/javascript">
        application.init({
            // Pass your data here.
            userData: { ... }
        });
    </script>

</body>

</html>

并且您可以在自定义 application 对象的 init() 方法中手动引导 AngularJS 应用程序.

And you can bootstrap AngularJS application manually in the init() method of your custom application object.

我不太喜欢这种方法,因为我认为 Web 应用程序的前端和后端应该高度分离.理想情况下,您的前端应该是一个静态网站(例如,可以通过 CDN 交付的一堆 HTML、CSS 和 JS),而您的后端应该是一个严格的 API 服务器,没有表示层(即它应该对 HTML、CSS 和这样的).但是,如果您可以接受应用程序组件之间的紧密集成,那么这是一个可行的解决方案.

I don't really like this approach, as I do believe that frontend and backend of Web application should be highly separated. Ideally, your frontend should be a static website (e.g. bunch of HTML, CSS and JS that can be delivered via CDN) and your backend should be a strictly an API server without a presentation layer (i.e. it should know nothing about HTML, CSS and such). However, it's a working solution if you can live with tight integration between application components.

这篇关于只有在 AngularJS 中的初始化完成后才运行控制器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆