javascript 仅在 AngularJS 中初始化完成后运行控制器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/27050496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Run controllers only after initialization is complete in AngularJS
提问by Slava Fomin II
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).
我有一些全局数据需要在我的 AngularJS 应用程序中执行任何控制器之前加载(即在 AngularJS 中全局解析依赖项)。
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).
例如,我有一个UserService
与getCurrentUser()
它不以获取有关当前验证的用户数据到后端服务器的请求方法。我有一个控制器需要这些数据才能启动另一个请求(例如加载用户的余额)。
How can I achieve that?
我怎样才能做到这一点?
回答by Slava Fomin II
Update
更新
Please consider using method specified in the ?Asynchronously Bootstrapping AngularJS Applications with Server-Side Data? article if possible.
请考虑使用 ? 使用服务器端数据异步引导 AngularJS 应用程序?如果可能的话。
You can use the angular-deferred-bootstrapmodule to achieve that now!
您现在可以使用angular-deferred-bootstrap模块来实现!
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.
我不再确定这个答案的有效性,您仍然可以使用这些想法,但一定要使用您的实际代码对其进行正确测试。我将尝试使用 never 技术使此答案保持最新。
Old answer
旧答案
There are several approaches to the problem of asynchronous application initialization.
有几种方法可以解决异步应用程序初始化问题。
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.
当涉及在调用单个控制器之前必须解析的数据时 - 您可以轻松使用'sresolve
选项。但是,当您需要在调用任何控制器之前加载一些全局数据时 - 您必须即兴发挥。ngRoute
$routeProvider
I've tried to collect all possible solutions in this answer. I'm providing them in the order of preference.
我试图在这个答案中收集所有可能的解决方案。我按优先顺序提供它们。
1. Using ui-router
1.使用ui-router
When using ui-routerinstead of native ngRoute
you can create an abstract root state and resolve all data in it, before sub-states are activated.
当使用ui-router而不是 native 时,ngRoute
您可以在激活子状态之前创建一个抽象的根状态并解析其中的所有数据。
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.
我建议使用这种方法。ui-router
提供了许多附加功能,包括分层解决依赖项的能力,并被开发人员社区广泛接受。
Example
例子
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);
}
}
}]
});
});
The stateHelper
will help greatly to reduce the code when using abstract root scope approach.
这stateHelper
将有助于在使用抽象根范围方法时大大减少代码。
Root scope is defined as abstract so can not be activated directly and it has no URL.
根范围被定义为抽象的,所以不能直接激活,它没有 URL。
template: '<ui-view/>'
is required for nested views to be properly rendered.
template: '<ui-view/>'
嵌套视图需要正确呈现。
2. Making promises in root controller
2. 在根控制器中做出承诺
You can make promises and add them to the $rootScope
inside of your root controller, i.e. run()
function.
您可以做出承诺并将它们添加到$rootScope
根控制器的内部,即run()
函数。
I've created a Plunk to demonstrate the idea: http://plnkr.co/edit/gpguG5Y2S4KOz1KOKzXe?p=preview
我创建了一个 Plunk 来演示这个想法: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.
这是一个完美的解决方案,但是,它会使代码膨胀,使其更难使用和理解(回调地狱)。仅当第一种方法不适合您时,我才会推荐它。
3. Passing data with the application page
3. 用应用页面传递数据
You can include all initialization data directly to the HTML page generated on the server and access it from your application.
您可以将所有初始化数据直接包含在服务器上生成的 HTML 页面中,并从您的应用程序访问它。
Consider this example:
考虑这个例子:
<html>
<body>
<script src="application.js"></script>
<script type="text/javascript">
application.init({
// Pass your data here.
userData: { ... }
});
</script>
</body>
</html>
And you can bootstrap AngularJS application manually in the init()
method of your custom application
object.
您可以在init()
自定义application
对象的方法中手动引导 AngularJS 应用程序。
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.
我不太喜欢这种方法,因为我认为 Web 应用程序的前端和后端应该高度分离。理想情况下,您的前端应该是一个静态网站(例如,可以通过 CDN 交付的一堆 HTML、CSS 和 JS),而您的后端应该是一个没有表示层的严格的 API 服务器(即它应该对 HTML、CSS 和这样的)。但是,如果您可以接受应用程序组件之间的紧密集成,那么它就是一个可行的解决方案。