如何将从后端渲染的parameter passing给angular2引导方法

有没有办法将后端呈现的parameter passing给angular2引导方法? 我想为所有使用BaseRequestOptions和后端提供的值的请求设置http头。 我的main.ts文件如下所示:

 import { bootstrap } from '@angular/platform-browser-dynamic'; import { AppComponent } from "./app.component.ts"; bootstrap(AppComponent); 

我发现如何将这个parameter passing给根组件( https://stackoverflow.com/a/35553650/3455681 ),但我需要它时,我正在bootstrap方法…任何想法?

编辑:

webpack.config.js内容:

 module.exports = { entry: { app: "./Scripts/app/main.ts" }, output: { filename: "./Scripts/build/[name].js" }, resolve: { extensions: ["", ".ts", ".js"] }, module: { loaders: [ { test: /\.ts$/, loader: 'ts-loader' } ] } }; 

UPDATE2

Plunker例子

更新 AoT

为了与AoT合作,工厂closures需要被移出

 function loadContext(context: ContextService) { return () => context.load(); } @NgModule({ ... providers: [ ..., ContextService, { provide: APP_INITIALIZER, useFactory: loadContext, deps: [ContextService], multi: true } ], 

另见https://github.com/angular/angular/issues/11262

更新 RC.6和2.0.0最后一个例子

 function configServiceFactory (config: ConfigService) { return () => config.load(); } @NgModule({ declarations: [AppComponent], imports: [BrowserModule, routes, FormsModule, HttpModule], providers: [AuthService, Title, appRoutingProviders, ConfigService, { provide: APP_INITIALIZER, useFactory: configServiceFactory deps: [ConfigService], multi: true } ], bootstrap: [AppComponent] }) export class AppModule { } 

如果不需要等待初始化完成,也可以使用class AppModule {}的构造函数:

 class AppModule { constructor(/*inject required dependencies */) {...} } 

提示(循环依赖)

例如注入路由器可能会导致循环依赖。 为了解决这个问题,注入Injector并通过

 this.myDep = injector.get(MyDependency); 

而不是像直接注入MyDependency一样:

 @Injectable() export class ConfigService { private router:Router; constructor(/*private router:Router*/ injector:Injector) { setTimeout(() => this.router = injector.get(Router)); } } 

更新

这在RC.5中应该是一样的,但是将提供providers: [...]添加到提供providers: [...]根模块而不是bootstrap(...)

(还没有testing过)。

更新

一个有趣的方法完全在Angular内部完成,在这里解释https://github.com/angular/angular/issues/9047#issuecomment-224075188

你可以使用APP_INITIALIZER ,它会在应用程序初始化时执行一个函数,并在函数返回promise时延迟它提供的内容。 这意味着应用程序可以在没有太多延迟的情况下进行初始化,也可以使用现有的服务和框架function。

例如,假设您有一个多租户解决scheme,其中站点信息依赖于它所服务的域名。 这可以是[name] .letterpress.com或者一个自定义的域名,它与完整的主机名称相匹配。 我们可以通过使用APP_INITIALIZER来隐藏这个背后的承诺。

在bootstrap中:

 {provide: APP_INITIALIZER, useFactory: (sites:SitesService) => () => sites.load(), deps:[SitesService, HTTP_PROVIDERS], multi: true}), 

sites.service.ts:

 @Injectable() export class SitesService { public current:Site; constructor(private http:Http, private config:Config) { } load():Promise<Site> { var url:string; var pos = location.hostname.lastIndexOf(this.config.rootDomain); var url = (pos === -1) ? this.config.apiEndpoint + '/sites?host=' + location.hostname : this.config.apiEndpoint + '/sites/' + location.hostname.substr(0, pos); var promise = this.http.get(url).map(res => res.json()).toPromise(); promise.then(site => this.current = site); return promise; } 

注意: config只是一个自定义configuration类。 在这个例子中, rootDomain将是'.letterpress.com' ,并允许像aptaincodeman.letterpress.com这样的东西。

现在,任何组件和其他服务都可以将Site注入到它们中,并使用.current属性,这是一个具体的填充对象,无需在应用程序中等待任何承诺。

这种方法似乎削减了启动延迟,如果您等待大型Angular bundle加载,然后在引导启动之前再发出另一个http请求,则启动延迟会非常明显。

原版的

你可以使用Angularsdependency injection来传递它:

 var headers = ... // get the headers from the server bootstrap(AppComponent, [{provide: 'headers', useValue: headers})]); 
 class SomeComponentOrService { constructor(@Inject('headers') private headers) {} } 

或直接提供准备好的BaseRequestOptions

 class MyRequestOptions extends BaseRequestOptions { constructor (private headers) { super(); } } var values = ... // get the headers from the server var headers = new MyRequestOptions(values); bootstrap(AppComponent, [{provide: BaseRequestOptions, useValue: headers})]); 

在Angular2最终版本中,可以使用APP_INITIALIZER提供程序来实现你想要的。

我用一个完整的例子写了一个Gist: https : //gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9

要点是从JSON文件读取,但可以很容易地从REST端点读取。

你需要什么,基本上是:

a)在你现有的模块文件中设置APP_INITIALIZER:

 import { APP_INITIALIZER } from '@angular/core'; import { BackendRequestClass } from './backend.request'; import { HttpModule } from '@angular/http'; ... @NgModule({ imports: [ ... HttpModule ], ... providers: [ ... ... BackendRequestClass, { provide: APP_INITIALIZER, useFactory: (config: BackendRequestClass) => () => config.load(), deps: [BackendRequestClass], multi: true } ], ... }); 

这些行将在您的应用程序启动之前从BackendRequestClass类中调用load()方法。

确保你在“imports”部分设置了“HttpModule”,如果你想使用内置的angular2库对后端进行http调用的话。

b)创build一个类并命名文件“backend.request.ts”:

 import { Inject, Injectable } from '@angular/core'; import { Http } from '@angular/http'; import { Observable } from 'rxjs/Rx'; @Injectable() export class BackendRequestClass { private result: Object = null; constructor(private http: Http) { } public getResult() { return this.result; } public load() { return new Promise((resolve, reject) => { this.http.get('http://address/of/your/backend/endpoint').map( res => res.json() ).catch((error: any):any => { reject(false); return Observable.throw(error.json().error || 'Server error'); }).subscribe( (callResult) => { this.result = callResult; resolve(true); }); }); } } 

c)要读取后端调用的内容,只需将BackendRequestClass注入到您select的任何类中,然后调用getResult()。 例:

 import { BackendRequestClass } from './backend.request'; export class AnyClass { constructor(private backendRequest: BackendRequestClass) { // note that BackendRequestClass is injected into a private property of AnyClass } anyMethod() { this.backendRequest.getResult(); // This should return the data you want } } 

让我知道这是否解决了你的问题。

您可以创build并导出一个执行该工作的函数,而不是让自己的入口点调用引导程序:

 export function doBootstrap(data: any) { platformBrowserDynamic([{provide: Params, useValue: new Params(data)}]) .bootstrapModule(AppModule) .catch(err => console.error(err)); } 

你也可以把这个函数放在全局对象上,具体取决于你的设置(webpack / SystemJS)。 它也是AOT兼容的。

如果有意义的话,这样可以延长引导时间。 例如,在用户填写表单之后,当您将此用户数据作为AJAX调用检索时。 用这个数据调用导出的bootstrap函数。

唯一的方法是在定义提供者时提供这些值:

 bootstrap(AppComponent, [ provide(RequestOptions, { useFactory: () => { return new CustomRequestOptions(/* parameters here */); }); ]); 

那么你可以在你的CustomRequestOptions类中使用这些参数:

 export class AppRequestOptions extends BaseRequestOptions { constructor(parameters) { this.parameters = parameters; } } 

如果您从AJAX请求中获取这些参数,则需要以这种方式asynchronous引导:

 var appProviders = [ HTTP_PROVIDERS ] var app = platform(BROWSER_PROVIDERS) .application([BROWSER_APP_PROVIDERS, appProviders]); var http = app.injector.get(Http); http.get('http://.../some path').flatMap((parameters) => { return app.bootstrap(appComponentType, [ provide(RequestOptions, { useFactory: () => { return new CustomRequestOptions(/* parameters here */); }}) ]); }).toPromise(); 

看到这个问题:

  • angular2引导来自ajax调用的数据

编辑

既然你有你的数据在HTML中,你可以使用以下。

你可以导入一个函数并用参数调用它。

以下是引导您的应用程序的主要模块示例:

 import {bootstrap} from '...'; import {provide} from '...'; import {AppComponent} from '...'; export function main(params) { bootstrap(AppComponent, [ provide(RequestOptions, { useFactory: () => { return new CustomRequestOptions(params); }); ]); } 

然后你可以像这样从你的HTML主页面导入它:

 <script> var params = {"token": "@User.Token", "xxx": "@User.Yyy"}; System.import('app/main').then((module) => { module.main(params); }); </script> 

看到这个问题: 从_layout.cshtml传递常量值为Angular 。