-1

I have some components that I'd like to add to my page dynamically.

I have their name in a config file config.json, currently the typescript classname MySuperComponent. I can put anything I want in my config file is the class name is not suited.

I've tried some code with component resolver, but I can't pass a string to it.

This works:

this.resolver.resolveComponent(MySuperComponent)

This doesn't:

this.resolver.resolveComponent("MySuperComponent")

How can I instanciate (and inject) a component from a String ?

blue112
  • 52,634
  • 3
  • 45
  • 54
  • I guess this [github issue](https://github.com/systemjs/systemjs/issues/1295) link should help you. Thanks :) – Pankaj Parkar Jul 28 '16 at 12:38
  • @PankajParkar The `DynamicComponentLoader` is deprecated, I'd like not to use it. – blue112 Jul 28 '16 at 12:40
  • 1
    I think that Pankaj wanted to show you the use of `System.import` ;-) This applies in your case... – Thierry Templier Jul 28 '16 at 12:45
  • @ThierryTemplier I'm not using systemjs. – blue112 Jul 28 '16 at 12:47
  • 1
    @blue112 you could something similar with `require` ;-) – Thierry Templier Jul 28 '16 at 12:48
  • @blue112 what do you use as module manager? – Thierry Templier Jul 28 '16 at 12:51
  • @ThierryTemplier What if I don't? – blue112 Jul 28 '16 at 12:52
  • 1
    @blue112 what do you exactly mean? you use es5 without modules? – Thierry Templier Jul 28 '16 at 12:54
  • I may be loading every single file I need into the browser using `script` tags. Don't over assume. This question is about typescript and angular, not about using another tool to "automagically" solve my problem. – blue112 Jul 28 '16 at 12:57
  • 1
    How can it determine which class belongs to "MySuperComponent" name without determined modular system? (By the way, the answer is "it can't"). – Estus Flask Jul 28 '16 at 13:21
  • @estus MySuperComponent is a class name. – blue112 Jul 28 '16 at 13:22
  • 1
    @blue112 could you please update you question with which module loader loader you are using to transpile your files, otherwise you are not going to get answer.. – Pankaj Parkar Jul 28 '16 at 13:26
  • 1
    Classes aren't defined as globals. And even if they are (but they aren't!), there's no guarantee that they will save their names after minification (there is a guarantee that they won't). The question cannot get an answer that will satisfy you because your assumptions on language capabilities are wrong. – Estus Flask Jul 28 '16 at 13:28
  • 1
    There's no way how "MySuperComponent" can be resolved to certain class by means of TS. And the only way "MySuperComponent" can be resolved to certain class by means of A2 is when the provider is defined as a string: `{ provide: "MySuperComponent", useClass: MySuperComponent }`. – Estus Flask Jul 28 '16 at 13:29

2 Answers2

1

You can set up a map and provide it by a service that translates from string to type

import {MySuperComponent} from './MySuperComponent';

@Injectable() 
class ComponentTypes {
  types = {
    MySuperComponent: MySuperComponent
  };
  toType(name:string) {
    return types[name];
  }
}

where you use it

@Component({
  ...
  providers: [ComponentTypes],
})
class SomeComponent {
  constructor(private componentTypes:ComponentTypes) {}

  addDynamicComponent() {
    ...
    this.resolver.resolveComponent(this.componentTypes.toType("MySuperComponent"))

  }
}

See also Angular2, manually resolve a type by string/name

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    Enumerating every single component that I could instanciate seems completely underproductive. – blue112 Jul 28 '16 at 12:42
  • 1
    This is how strong types work. See the linked question for other answers. – Günter Zöchbauer Jul 28 '16 at 12:43
  • I am (and should be) a lazy programmer. When I implement a new component, I do not expect to updated a "component bank" file just to resolve them. – blue112 Jul 28 '16 at 12:45
  • 1
    I understand that you don't like that, that doesn't automatically invent better solutions. Angular uses types. Types can only uniquely identified with an import or a full path. There are other options (again see the linked question) but they also have their drawbacks. – Günter Zöchbauer Jul 28 '16 at 12:47
  • I know this is an old post. But recently I ran into the same problem. If you have found a better solution, please share. The best I found so far is this http://stackoverflow.com/questions/42949647/resolve-type-of-component-from-string-in-angular2?answertab=votes#tab-top. – nmy May 22 '17 at 10:33
1

Following the Pankaj's comment, you could use System.import:

let componentPath = (...)
let componentName = 'MySuperComponent';
System.import(componentPath)
        .then(fileContents => {
            return fileContents[componentName]
        })
        .then(component => {
            this.resolver.resolveComponent(component);
        });
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Don't assume I'm using systemjs. I'm not particulary using any framework or loading library. Currently I'm using webpack, but I don't want to be tied to a loading library. – blue112 Jul 28 '16 at 12:50