2

Is it possible to manually resolve a component by only knowing it's name?

I have a string variable which will contain the name of a component, lets say "UserService"

I need to be able to resolve this type, I've looked at Injctor, I can see from the documenation there is a resolve() and resolveAndCreate() (https://angular.io/docs/ts/latest/api/core/Injector-class.html)

but I don't have the Type.

Thanks

Steve

EDIT: tried the following:

System.import("path/to/service").then(p=>{

     var injector = Injector.resolveAndCreate([p[this.serviceName]]);//works

     var serviceInstance = injector.get(p[this.serviceName]); //Fails with "No provider for Http! (UserService -> Http)".


});

I have Http available, it's been provided during bootstrap and this works fine for other parts of the application.

bootstrap(AppComponent, [
    ROUTER_PROVIDERS, Http, HTTP_PROVIDERS, UrlBuilderService,
    provide(LocationStrategy, { useClass: HashLocationStrategy }),
    provide('notification', { useClass: NotificationService })
]);

Any idea's?

Further Edit:

I now call the resolveAndCreate like this:

var injector = Injector.resolveAndCreate([p[this.serviceName], Http]);

which failed with

No provider for ConnectionBackend! (UserService -> Http -> ConnectionBackend)

So i called it like this:

var injector = Injector.resolveAndCreate([p[this.serviceName], Http, ConnectionBackend]);

which failed with some other missing stuff.

Changed to this

var injector = Injector.resolveAndCreate([p[this.serviceName], HTTP_PROVIDERS]);

and now all is working.

What I do not understand is why it's not automatically resolving these components because i have them provided during bootstrap.

Steven Yates
  • 2,400
  • 3
  • 30
  • 58

2 Answers2

5

new

To get components by name import the components like

import * as components from './components'

and access them with

var componentName = 'SomeComponent';
components[componentName]

See also this Plunker from Rob Wormald from https://github.com/angular/angular/issues/7596#issuecomment-198199074

old

With

Injector.resolveAndCreate(

you create a new injector that is entirely disconnected from the connector created from Angular using the providers passed to bootstrap(..., [Providers]).
An injector created this way can only resolve providers passed to resolveAndCreate().

If you want to use the same injector as your Angular application, then you need to inject the injector

constructor(private injector:Injector) {
  injector.get(...);
}

You can create a child injector from the passed injector and override bindings if you want. The child injector either resolves to the overridden bindings or walks up the parent injectors until root while trying to resolve requested dependencies.

Mathew Thompson
  • 55,877
  • 15
  • 127
  • 148
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • how do I make `components[componentName]` into a component? – Phil Aug 05 '17 at 19:25
  • You need to add it to `entryComponents: [...]`, then you should be able to create a comonent like shown in https://stackoverflow.com/questions/36325212/angular-2-dynamic-tabs-with-user-click-chosen-components/36325468#36325468 – Günter Zöchbauer Aug 05 '17 at 21:01
4

You can achieve this by using system.js (that is loader used by angular2) by doing so:

System.import('path/to/UserService').then(m => 
{
    //Here you can access user service and use it in injector etc.
    Injector.resolveAndCreate([m.UserService]);
});

This technique is well illustrated in this article: Lazy Loading of Route Components in Angular 2

Matt
  • 74,352
  • 26
  • 153
  • 180
Amid
  • 21,508
  • 5
  • 57
  • 54