Come passare parametri resi dal backend al metodo bootstrap angular2

C’è un modo per passare gli argomenti resi sul backend al metodo bootstrap angular2? Voglio impostare l’intestazione http per tutte le richieste usando BaseRequestOptions con valore fornito dal back-end. Il mio file main.ts il seguente aspetto:

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

Ho trovato come passare questo argomento al componente root ( https://stackoverflow.com/a/35553650/3455681 ), ma ne ho bisogno quando lancio il metodo bootstrap … Qualche idea?

modificare:

contenuto 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

Esempio di Plunker

aggiorna AoT

Per lavorare con AoT è necessario rimuovere la chiusura di fabbrica

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

Vedi anche https://github.com/angular/angular/issues/11262

aggiornare un esempio finale RC.6 e 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 { } 

Se non è necessario attendere il completamento dell’inizializzazione, è ansible utilizzare anche il costruttore di `AppModule {}:

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

suggerimento (dipendenza ciclica)

Ad esempio, l’iniezione del router può causare dipendenze cicliche. Per risolvere il Injector , iniettare l’ Injector e ottenere la dipendenza da

 this.myDep = injector.get(MyDependency); 

invece di iniettare MyDependency direttamente come:

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

aggiornare

Questo dovrebbe funzionare allo stesso modo in RC.5, ma aggiungere il provider ai providers: [...] del modulo root invece del bootstrap(...)

(non ancora testato).

aggiornare

Un approccio interessante per farlo interamente all’interno di Angular è spiegato qui https://github.com/angular/angular/issues/9047#issuecomment-224075188

Puoi utilizzare APP_INITIALIZER che eseguirà una funzione quando l’app viene inizializzata e ritarda ciò che fornisce se la funzione restituisce una promise. Ciò significa che l’app può essere inizializzata senza abbastanza latenza e puoi anche utilizzare i servizi e le funzionalità di framework esistenti.

Ad esempio, supponiamo di avere una soluzione multi-tenant in cui le informazioni del sito si basano sul nome del dominio da cui viene servito. Può essere [nome] .letterpress.com o un dominio personalizzato che corrisponde al nome host completo. Possiamo hide il fatto che questo è dietro una promise usando APP_INITIALIZER .

Nel 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 { 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; } 

NOTA: config è solo una class di configurazione personalizzata. rootDomain sarebbe '.letterpress.com' per questo esempio e consentirebbe cose come aptaincodeman.letterpress.com .

Qualsiasi componente e altri servizi possono ora avere il Site iniettato in essi e utilizzare la proprietà .current che sarà un object popolato concreto senza la necessità di attendere alcuna promise all’interno dell’app.

Questo approccio sembrava ridurre la latenza di avvio che altrimenti sarebbe stata notevole se si stesse aspettando il caricamento del grande pacchetto Angular e poi un’altra richiesta HTTP prima ancora dell’avvio del bootstrap.

originale

Puoi passarlo usando l’iniezione di dipendenza di Angulars:

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

o fornire direttamente BaseRequestOptions come

 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})]); 

Nella versione finale di Angular2, il fornitore APP_INITIALIZER può essere utilizzato per ottenere ciò che desideri.

Ho scritto un Gist con un esempio completo: https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9

L’esempio di esempio è la lettura da file JSON, ma può essere facilmente modificato per leggere da un endpoint REST.

Quello di cui hai bisogno, è fondamentalmente:

a) Configura APP_INITIALIZER nel tuo file modulo esistente:

 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 } ], ... }); 

Queste linee chiamano il metodo load () dalla class BackendRequestClass prima dell’avvio dell’applicazione.

Assicurati di aver impostato “HttpModule” nella sezione “importazioni” se vuoi effettuare chiamate http al backend usando la libreria integrata angular2.

b) Creare una class e denominare il file “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) Per leggere il contenuto della chiamata di back-end, è sufficiente inserire la BackendRequestClass in qualsiasi class di tua scelta e chiamare getResult (). Esempio:

 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 } } 

Fammi sapere se questo risolve il tuo problema.

Invece di avere il punto di ingresso che chiama lo stesso bootstrap, puoi creare ed esportare una funzione che fa il lavoro:

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

È inoltre ansible posizionare questa funzione sull’object globale, a seconda della configurazione (webpack / SystemJS). È anche compatibile con AOT.

Questo ha l’ulteriore vantaggio di ritardare il bootstrap, quando ha senso. Ad esempio, quando recuperi questi dati utente come una chiamata AJAX dopo che l’utente compila un modulo. Basta chiamare la funzione di bootstrap esportata con questi dati.

L’unico modo per farlo è fornire questi valori quando si definiscono i provider:

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

Quindi puoi utilizzare questi parametri nella tua class CustomRequestOptions :

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

Se ottieni questi parametri da una richiesta AJAX, devi eseguire il bootstrap in modo asincrono in questo modo:

 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(); 

Vedi questa domanda:

  • bootstrap angular2 con dati da una o più chiamate ajax

modificare

Poiché hai i tuoi dati nell’HTML, potresti usare quanto segue.

Puoi importare una funzione e chiamarla con i parametri.

Ecco un esempio del modulo principale che avvia la tua applicazione:

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

Quindi puoi importarlo dalla tua pagina principale HTML in questo modo:

  

Vedi questa domanda: Passa valori costanti a Angular da _layout.cshtml .