bootstrap angular2 con datos de llamada (s) ajax

Quiero iniciar mi aplicación con datos que estoy recuperando de un servicio. Estoy haciendo algo en la línea de

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

Esto funciona bien, pero no me gusta usar la matriz de dependencias dos veces, ¿hay alguna manera más clara de hacerlo? ¿Puedo agregar cosas al inyector de la aplicación después del arranque? También noté que la función bootstrap devuelve una promesa, ¿puedo usar esta promesa para evitar el arranque de la aplicación hasta después de que termine mi solicitud de ajax?

Por supuesto, para el Injector podría usar solo las dependencias requeridas por MyService pero esto lo hace muy frágil como se puede imaginar.

El problema aquí es que Angular2 no le da acceso a la referencia de la aplicación y su inyector antes de iniciar el componente principal en él. Vea esta línea en el código fuente: https://github.com/angular/angular/blob/master/modules/angular2/platform/browser.ts#L110 .

Un enfoque podría ser implementar un bootstrap personalizado en lugar de usar el predeterminado. Algo así que divide la creación de aplicaciones y el boostrapping en el componente de la aplicación. De esta forma, podrás cargar algo entre las dos tareas.

Aquí hay una implementación de ejemplo:

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

y úsalo de esta manera:

 customBoostrap(AppComponent, [ HTTP_PROVIDERS, CompaniesService ]); 

Las empresas estarán automáticamente disponibles para inyección dentro del componente, por ejemplo:

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

Vea este plunkr correspondiente: https://plnkr.co/edit/RbBrQ7KOMoFVNU2ZG5jM?p=preview .

En este momento, es un poco raro, pero ese enfoque podría proponerse como una solicitud de función …

Editar

Después de echar un vistazo al documento para la clase ApplicationRef , vi que hay una solución más simple 😉

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

Aquí está el plunkr correspondiente: https://plnkr.co/edit/ooMNzEw2ptWrumwAX5zP?p=preview .

@Thierry (como de costumbre) ha respondido bien al núcleo de su pregunta, pero creo que vale la pena señalarlo por separado:

¿Puedo agregar cosas al inyector de la aplicación después del arranque?

Sí, al declararlos en providers o viewProviders en los decoradores de los componentes que los requieren. p.ej:

 //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){ } }

Tenga en cuenta que los providers se pueden usar tanto en directivas como en componentes (es una opción en viewProviders , desde donde se extiende ComponentMetadata ), mientras que viewProviders solo está disponible en componentes por razones que son claras dada la diferencia entre ellos .

En mi humilde opinión, es una buena práctica inyectar dependencias de esta manera siempre que sea posible en lugar de hacerlo en el bootstrap , ya que le permite limitar el scope de la disponibilidad de una dependencia dada a la parte de la aplicación (es decir, el subárbol de componentes) donde desea estar disponible También es propicio para la carga progresiva y evita el olor SoC de configurar innumerables inyectables no relacionados en un solo archivo de arranque.