bootstrap angular2 con dati da una o più chiamate ajax

Voglio riavviare la mia applicazione con i dati che sto recuperando da un servizio. Sto facendo qualcosa sulla falsariga di

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

Funziona bene, ma non mi piace usare due volte l’array di dipendenze, c’è un modo più pulito per farlo? Posso aggiungere cose all’iniettore dell’applicazione dopo il bootstrap? Inoltre, noto che la funzione bootstrap restituisce una promise, posso usare questa promise per impedire il bootstrap dell’applicazione fino a quando non termina la richiesta di ajax?

Ovviamente per l’ Injector potrei usare solo le dipendenze richieste da MyService ma questo lo rende molto fragile come potete immaginare.

Il problema qui è che Angular2 non ti dà accesso al riferimento dell’applicazione e al suo iniettore prima di avviare il componente principale su di esso. Vedi questa riga nel codice sorgente: https://github.com/angular/angular/blob/master/modules/angular2/platform/browser.ts#L110 .

Un approccio potrebbe essere quello di implementare un bootstrap personalizzato invece di utilizzare quello predefinito. Qualcosa del genere che divide la creazione dell’applicazione e il booster sul componente dell’applicazione su di esso. In questo modo sarai in grado di caricare qualcosa tra le due attività.

Ecco un’implementazione di esempio:

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

e usalo in questo modo:

 customBoostrap(AppComponent, [ HTTP_PROVIDERS, CompaniesService ]); 

Le aziende saranno automaticamente disponibili per l’iniezione all’interno del componente, ad esempio:

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

Vedi questo plunkr corrispondente: https://plnkr.co/edit/RbBrQ7KOMoFVNU2ZG5jM?p=preview .

In questo momento, è un po ‘hacky ma un simile approccio potrebbe essere proposto come una richiesta di funzionalità …

modificare

Dopo aver dato un’occhiata al doc per la class ApplicationRef , ho visto che c’è una soluzione più semplice 😉

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

Ecco il plunkr corrispondente: https://plnkr.co/edit/ooMNzEw2ptWrumwAX5zP?p=preview .

@Thierry (come al solito) ha risposto bene al cuore della tua domanda, ma penso che valga la pena di notare separatamente:

Posso aggiungere cose all’iniettore dell’applicazione dopo il bootstrap?

Sì, dichiarandoli in providers o viewProviders sui decoratori dei componenti che li richiedono. per esempio:

 //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: `
{{mySvc.getMessage()}}
` //displays foobar }) class MyComponent { constructor(private mySvc: MyService){ } }

Si noti che i providers possono essere utilizzati sia per le direttive che per i componenti (è un’opzione su DirectiveMetadata , da cui ComponentMetadata estende), mentre viewProviders è disponibile solo sui componenti per ragioni chiare, data la differenza tra loro .

IMHO, è una buona pratica iniettare le dipendenze in questo modo, laddove ansible, invece di farlo bootstrap , in quanto consente di limitare l’ambito di disponibilità di una determinata dipendenza alla parte dell’applicazione (ad esempio il sottostruttura del componente) dove si desidera sarà disponibile. È anche favorevole al caricamento progressivo ed evita l’odore di SoC di configurare una miriade di iniettabili non correlati in un singolo file di bootstrap.