update2
Plunker Beispiel
AoT aktualisieren
Um mit AoT arbeiten zu können, muss die Werksschließung ausgezogen werden
function loadContext(context: ContextService) {
return () => context.load();
}
@NgModule({
...
providers: [ ..., ContextService, { provide: APP_INITIALIZER, useFactory: loadContext, deps: [ContextService], multi: true } ],
Siehe auch https://github.com/angular/angular/issues/11262
Aktualisieren Sie ein letztes Beispiel für RC.6 und 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 { }
Wenn Sie nicht warten müssen, bis die Initialisierung abgeschlossen ist, kann auch der Konstruktor der Klasse AppModule {} verwendet werden:
class AppModule {
constructor() {...}
}
Hinweis (zyklische Abhängigkeit)
Beispielsweise kann das Injizieren des Routers zyklische Abhängigkeiten verursachen. Um dies zu umgehen, injizieren Sie die Injector
und erhalten Sie die Abhängigkeit von
this.myDep = injector.get(MyDependency);
anstatt MyDependency
direkt zu injizieren wie:
@Injectable()
export class ConfigService {
private router:Router;
constructor( injector:Injector) {
setTimeout(() => this.router = injector.get(Router));
}
}
aktualisieren
Dies sollte in RC.5 genauso funktionieren, aber stattdessen den Provider providers: [...]
des Root-Moduls hinzufügenbootstrap(...)
(habe mich noch nicht getestet).
aktualisieren
Ein interessanter Ansatz, um dies vollständig in Angular zu tun, wird hier erklärt: https://github.com/angular/angular/issues/9047#issuecomment-224075188
Sie können verwenden, APP_INITIALIZER
welche Funktion ausgeführt wird, wenn die App initialisiert wird, und die Bereitstellung verzögern, wenn die Funktion ein Versprechen zurückgibt. Dies bedeutet, dass die App ohne große Latenz initialisiert werden kann und Sie auch die vorhandenen Dienste und Framework-Funktionen verwenden können.
Angenommen, Sie haben eine Lösung mit mehreren Mandanten, bei der die Site-Informationen vom Domain-Namen abhängen, von dem aus sie bereitgestellt werden. Dies kann [Name] .letterpress.com oder eine benutzerdefinierte Domain sein, die mit dem vollständigen Hostnamen übereinstimmt. Wir können die Tatsache verbergen, dass dies hinter einem Versprechen steht, indem wir verwenden APP_INITIALIZER
.
Im 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;
}
HINWEIS: config
ist nur eine benutzerdefinierte Konfigurationsklasse. rootDomain
wäre
'.letterpress.com'
für dieses Beispiel und würde Dinge wie erlauben
aptaincodeman.letterpress.com
.
Alle Komponenten und anderen Dienste können jetzt Site
in sie eingefügt werden und die .current
Eigenschaft verwenden, bei der es sich um ein konkretes Objekt handelt, ohne dass auf ein Versprechen in der App gewartet werden muss.
Dieser Ansatz schien die Startlatenz zu verringern, was ansonsten ziemlich auffiel, wenn Sie darauf warteten, dass das große Angular-Bundle geladen wurde, und dann eine weitere http-Anforderung, bevor der Bootstrap überhaupt begann.
Original
Sie können es mit Angulars-Abhängigkeitsinjektion übergeben:
var headers = ...
bootstrap(AppComponent, [{provide: 'headers', useValue: headers})]);
class SomeComponentOrService {
constructor(@Inject('headers') private headers) {}
}
oder BaseRequestOptions
direkt wie vorbereitet bereitstellen
class MyRequestOptions extends BaseRequestOptions {
constructor (private headers) {
super();
}
}
var values = ...
var headers = new MyRequestOptions(values);
bootstrap(AppComponent, [{provide: BaseRequestOptions, useValue: headers})]);
<script> function() { window.headers = someJson; }()</script>
. Ich bin mir nicht sicher über die Syntax, ich benutze JS selbst nicht viel. Auf diese Weise müssten Sie überhaupt nicht analysieren.load()
mussPromise
, nicht anObservable
. Verwenden Sie die.toPromise()
Funktion hier, wenn Sie Observables wie ich in Ihrem Dienst verwenden. 2) Sie fragen sich möglicherweise, wie Sie den Wertsites.load()
in Ihre Dienste, Komponenten usw. abrufen können. Beachten Sie, dass erSitesService
zugewiesen wirdthis.current
. Sie müssen also nurSitesService
in Ihre Komponente injizieren und ihrecurrent
Eigenschaft abrufen() => sites.load()
zu einer Funktion (außerhalb der Klasse und des Dekorateurs) wechseln und diese dann im Anbieter durch diesen Funktionsnamen ersetzenIn der endgültigen Version von Angular2 kann der APP_INITIALIZER-Anbieter verwendet werden, um das zu erreichen, was Sie möchten.
Ich habe eine Übersicht mit einem vollständigen Beispiel geschrieben: https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9
Das Hauptbeispiel ist das Lesen aus JSON-Dateien, kann jedoch leicht geändert werden, um von einem REST-Endpunkt zu lesen.
Was Sie brauchen, ist im Grunde:
a) Richten Sie APP_INITIALIZER in Ihrer vorhandenen Moduldatei ein:
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 } ], ... });
Diese Zeilen rufen die load () -Methode aus der BackendRequestClass-Klasse auf, bevor Ihre Anwendung gestartet wird.
Stellen Sie sicher, dass Sie "HttpModule" im Abschnitt "Importe" festlegen, wenn Sie mithilfe der integrierten Angular2-Bibliothek http-Aufrufe an das Backend senden möchten.
b) Erstellen Sie eine Klasse und nennen Sie die Datei "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) Um den Inhalt des Backend-Aufrufs zu lesen, müssen Sie nur die BackendRequestClass in eine Klasse Ihrer Wahl einfügen und getResult () aufrufen. Beispiel:
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 } }
Lassen Sie mich wissen, ob dies Ihr Problem löst.
quelle
() =>
für useFactoryAnstatt dass Ihr Einstiegspunkt Bootstrap selbst aufruft, können Sie eine Funktion erstellen und exportieren, die die Arbeit erledigt:
export function doBootstrap(data: any) { platformBrowserDynamic([{provide: Params, useValue: new Params(data)}]) .bootstrapModule(AppModule) .catch(err => console.error(err)); }
Sie können diese Funktion abhängig von Ihrem Setup (Webpack / SystemJS) auch auf dem globalen Objekt platzieren. Es ist auch AOT-kompatibel.
Dies hat den zusätzlichen Vorteil, dass der Bootstrap verzögert wird, wenn dies sinnvoll ist. Wenn Sie diese Benutzerdaten beispielsweise als AJAX-Aufruf abrufen, nachdem der Benutzer ein Formular ausgefüllt hat. Rufen Sie einfach die exportierte Bootstrap-Funktion mit diesen Daten auf.
quelle
Die einzige Möglichkeit, dies zu tun, besteht darin, diese Werte bei der Definition Ihrer Anbieter anzugeben:
bootstrap(AppComponent, [ provide(RequestOptions, { useFactory: () => { return new CustomRequestOptions(/* parameters here */); }); ]);
Dann können Sie diese Parameter in Ihrer
CustomRequestOptions
Klasse verwenden:export class AppRequestOptions extends BaseRequestOptions { constructor(parameters) { this.parameters = parameters; } }
Wenn Sie diese Parameter aus einer AJAX-Anforderung erhalten, müssen Sie asynchron wie folgt booten:
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();
Siehe diese Frage:
Bearbeiten
Da Sie Ihre Daten im HTML haben, können Sie Folgendes verwenden.
Sie können eine Funktion importieren und mit Parametern aufrufen.
Hier ist ein Beispiel des Hauptmoduls, mit dem Ihre Anwendung gebootet wird:
import {bootstrap} from '...'; import {provide} from '...'; import {AppComponent} from '...'; export function main(params) { bootstrap(AppComponent, [ provide(RequestOptions, { useFactory: () => { return new CustomRequestOptions(params); }); ]); }
Dann können Sie es wie folgt von Ihrer HTML-Hauptseite importieren:
<script> var params = {"token": "@User.Token", "xxx": "@User.Yyy"}; System.import('app/main').then((module) => { module.main(params); }); </script>
Siehe diese Frage: Übergeben Sie konstante Werte von _layout.cshtml an Angular .
quelle
{"token": "@User.Token", "xxx": "@User.Yyy"}
so rendern: also in gerendertem HTML werde ich haben{"token": "123abc456def", "xxx": "yyy"}
. Und ich möchte diesen gerenderten JSON irgendwie an die Bootstrap-Methode übergeben, die ich in der .js-Datei habe.