2016-04-01 2 views
5

Ich möchte meine Anwendung mit Daten, die ich von einem Dienst abzurufen, Bootstrap. Ich tue etwas entlang der Linien vonangular2 bootstrap mit Daten von AJAX-Aufruf (en)

let dependencies = [ 
    //... a load of dependencies 
    MyService 
]; 

let injector = Injector.resolveAndCreate(dependencies); 
let service: MyService = injector.get(MyService); 

service.getData() // returns observable 
    .toPromise() 
    .then((d) => { 
     // use data to append to dependencies 

     bootstrap(App, dependencies) 
    }); 

Dies funktioniert gut, aber ich weiß nicht, wie die Abhängigkeit Array zweimal, gibt es eine sauberere Möglichkeit, dies zu tun? Kann ich dem Anwendungsinjektor nach dem Bootstrap Dinge hinzufügen? Außerdem stelle ich fest, dass die Bootstrap-Funktion ein Versprechen zurückgibt. Kann ich dieses Versprechen verwenden, um den Bootstrap der Anwendung zu verhindern, bis meine Ajax-Anfrage beendet ist?

Natürlich könnte ich für die Injector nur die Abhängigkeiten von MyService benötigt verwenden, aber das macht es sehr brüchig, wie Sie sich vorstellen können.

Antwort

5

Das Problem hier ist, dass Angular2 Ihnen keinen Zugriff auf die Anwendungsreferenz und den Injektor gibt, bevor Sie die Hauptkomponente darauf starten. Siehe diese Zeile im Quellcode: https://github.com/angular/angular/blob/master/modules/angular2/platform/browser.ts#L110.

Ein Ansatz könnte darin bestehen, ein benutzerdefiniertes Bootstrap zu implementieren, anstatt das Standard-Bootstrap zu verwenden. So etwas teilt die Anwendungserstellung und das Boosten auf der Anwendungskomponente auf. Auf diese Weise können Sie etwas zwischen den beiden Aufgaben laden.

Hier ist eine Beispielimplementierung:

function customBoostrap(appComponentType, customProviders) { 
    reflector.reflectionCapabilities = new ReflectionCapabilities(); 
    let appProviders = 
    isPresent(customProviders) ? [BROWSER_APP_PROVIDERS, customProviders] : BROWSER_APP_PROVIDERS; 
    var app = platform(BROWSER_PROVIDERS).application(appProviders); 

    var service = app.injector.get(CompaniesService); 

    return service.getCompanies().flatMap((companies) => { 
    var companiesProvider = new Provider('companies', { useValue: data }); 
    return app.bootstrap(appComponentType, [ companiesProvider ]); 
    }).toPromise(); 
} 

und es auf diese Weise verwenden:

customBoostrap(AppComponent, [ 
    HTTP_PROVIDERS, 
    CompaniesService 
]); 

Unternehmen werden beispielsweise in der Komponente für die Injektion automatisch zur Verfügung:

@Component({ 
    (...) 
}) 
export class AppComponent { 
    constructor(@Inject('companies') companies) { 
    console.log(companies); 
    } 
} 

Siehe entsprechende Plunkr: https://plnkr.co/edit/RbBrQ7KOMoFVNU2ZG5jM?p=preview.

Zu dieser Zeit ist es ein bisschen hacky, aber solche Ansatz könnte als Feature-Anfrage vorgeschlagen werden ...

bearbeiten

einen Blick auf die doc für die ApplicationRef Klasse Nachdem, sah ich, dass es eine einfachere Lösung ;-) ist,

var app = platform(BROWSER_PROVIDERS) 
    .application([BROWSER_APP_PROVIDERS, appProviders]); 

service.getCompanies().flatMap((companies) => { 
    var companiesProvider = new Provider('companies', { useValue: data }); 
    return app.bootstrap(appComponentType, [ companiesProvider ]); 
}).toPromise(); 

Hier die entsprechende plunkr: https://plnkr.co/edit/ooMNzEw2ptWrumwAX5zP?p=preview.

1

@Thierry (wie üblich) hat das Herz Ihrer Frage auch beantwortet, aber ich denke, das ist erwähnenswert, getrennt:

Kann ich die Dinge auf die Anwendung Injektor nach Bootstrap hinzufügen?

Ja, indem man sie in providers oder viewProviders auf die Dekorateure der Komponenten zu erklären, die sie benötigen. z:

//main.ts 
bootstrap(MyComponent) //no dependencies declared 


//my.service.ts 
@Injectable class MyService { public getMessage =() => "foobar" } 


//my.component.ts 
@Component({ 
    selector: 'foo', 
    providers: [MyService] 
    template: `<div>{{mySvc.getMessage()}}</div>` //displays foobar 
}) 
class MyComponent { 
    constructor(private mySvc: MyService){ } 
} 

Beachten Sie, dass providers können sowie Komponenten auf Richtlinien verwendet werden (es ist eine Option auf DirectiveMetadata, von dem ComponentMetadata erstreckt), während viewProviders auf Komponenten aus Gründen nur zur Verfügung, die klar the difference between them gegeben.

IMHO, ist es eine Best Practice, um Abhängigkeiten auf diese Weise wann immer möglich zu injizieren, anstatt es zu tun bootstrap, wie Sie den Umfang der Verfügbarkeit einer bestimmten Abhängigkeit auf den Teil der Anwendung (dh Komponente Unterstruktur) zu begrenzen) wo Sie möchten, dass es verfügbar ist. Es ist auch förderlich für das progressive Laden und vermeidet den SoC-Geruch der Konfiguration unzähliger nicht verwandter Injektionen in einer einzigen Bootstrap-Datei.

Verwandte Themen