[英]How to pass parameters rendered from backend to angular2 bootstrap method
有沒有辦法將后端呈現的參數傳遞給 angular2 bootstrap 方法? 我想使用BaseRequestOptions和后端提供的值為所有請求設置 http 標頭。 我的main.ts
文件如下所示:
import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from "./app.component.ts";
bootstrap(AppComponent);
我找到了如何將此參數傳遞給根組件( 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'
}
]
}
};
更新2
更新AoT
為了與 AoT 合作,工廠關閉需要移出
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: [...]
of the root module 而不是bootstrap(...)
(尚未測試自己)。
更新
這里解釋了一種完全在 Angular 內部完成的有趣方法https://github.com/angular/angular/issues/9047#issuecomment-224075188
您可以使用
APP_INITIALIZER
它將在應用程序初始化時執行一個函數,並在該函數返回承諾時延遲它提供的內容。 這意味着應用程序可以在沒有太多延遲的情況下進行初始化,您還可以使用現有的服務和框架功能。例如,假設您有一個多租戶解決方案,其中站點信息依賴於為其提供服務的域名。 這可以是 [name].letterpress.com 或與完整主機名匹配的自定義域。 我們可以通過使用
APP_INITIALIZER
來隱藏這是在 promise 背后的APP_INITIALIZER
。在引導程序中:
{provide: APP_INITIALIZER, useFactory: (sites:SitesService) => () => sites.load(), deps:[SitesService, HTTP_PROVIDERS], multi: true}),
站點.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
只是一個自定義配置類。 在這個例子中rootDomain
將是'.letterpress.com'
並且允許像aptaincodeman.letterpress.com
這樣的東西。任何組件和其他服務現在都可以將
Site
注入其中並使用.current
屬性,該屬性將是一個具體的填充對象,無需等待應用程序中的任何承諾。這種方法似乎減少了啟動延遲,如果您在等待大型 Angular 包加載,然后在引導程序開始之前等待另一個 http 請求,則啟動延遲非常明顯。
原來的
您可以使用 Angulars 依賴注入來傳遞它:
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 提供程序來實現您想要的。
我寫了一個完整的例子: 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() 方法。
如果要使用 angular2 內置庫對后端進行 http 調用,請確保在“導入”部分設置“HttpModule”。
b) 創建一個類並將文件命名為“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 注入您選擇的任何類並調用 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
}
}
如果這能解決您的問題,請告訴我。
您可以創建並導出一個完成工作的函數,而不是讓您的入口點調用 bootstrap 本身:
export function doBootstrap(data: any) {
platformBrowserDynamic([{provide: Params, useValue: new Params(data)}])
.bootstrapModule(AppModule)
.catch(err => console.error(err));
}
你也可以把這個函數放在全局對象上,這取決於你的設置(webpack/SystemJS)。 它也與 AOT 兼容。
這有一個額外的好處,可以延遲引導,當它有意義時。 例如,當您在用戶填寫表單后通過 AJAX 調用檢索此用戶數據時。 只需使用此數據調用導出的引導程序函數即可。
唯一的方法是在定義提供者時提供這些值:
bootstrap(AppComponent, [
provide(RequestOptions, { useFactory: () => {
return new CustomRequestOptions(/* parameters here */);
});
]);
然后您可以在CustomRequestOptions
類中使用這些參數:
export class AppRequestOptions extends BaseRequestOptions {
constructor(parameters) {
this.parameters = parameters;
}
}
如果您從 AJAX 請求中獲取這些參數,則需要以這種方式異步引導:
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();
看到這個問題:
編輯
由於您的數據在 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>
看到這個問題: Pass Constant Values to Angular from _layout.cshtml 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.