Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
554 views
in Technique[技术] by (71.8m points)

typescript - angular2 bootstrap with data from ajax call(s)

I want to bootstrap my application with data I am retrieving from a service. I am doing something along the lines of

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

This works fine, but I do not like using the dependency array twice, is there a cleaner way of doing this? Can I add things to the application injector after bootstrap? Also I notice that the bootstrap function returns a promise, can I use this promise to prevent bootstrap of the application until after my ajax request finishes?

Of course for the Injector I could use only those dependencies required by MyService but this makes it very brittle as you can imagine.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The problem here is that Angular2 doesn't give you access to the application reference and its injector before bootstrapping the main component on it. See this line in the source code: https://github.com/angular/angular/blob/master/modules/angular2/platform/browser.ts#L110.

An approach could be to implement a custom bootstrap instead of using the default one. Something like that that splits the application creation and the boostrapping on the application component on it. This way you will be able to load something between the two tasks.

Here is a sample implementation:

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

and use it this way:

customBoostrap(AppComponent, [
  HTTP_PROVIDERS,
  CompaniesService
]);

Companies will be automatically available for injection within the component for example:

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

See this corresponding plunkr: https://plnkr.co/edit/RbBrQ7KOMoFVNU2ZG5jM?p=preview.

At this time, it's a bit hacky but such approach could proposed as a feature request...

Edit

After having a look at the doc for the ApplicationRef class, I saw that there is a simpler solution ;-)

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

Here is the corresponding plunkr: https://plnkr.co/edit/ooMNzEw2ptWrumwAX5zP?p=preview.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...