4

I wanted to load component templateUrl based on value passed from parent component. I know tt can be pass through property binding to component by have @Input, I gave example below in which myHtml will be passed as templateName.

.But there is no ability to access @Input value inside templateUrl function. I think templateUrl is the first thing going to evaluate by asking for HTML, after that all other component code gets executed.

Like in angular 1 has ability to pass some value from attribute, & then I can use that value inside templateUrl function as a parameter like below.

templateUrl: function(element, attrs){
    //was getting value
    return '/app/templates/'+ attrs.myTemplateName + '.html'
}

But same thing I can't do in Angular2, as templateUrl is strongly typed as string so it doesn't take function as an attribute.

Is there a way to achieve this OR I missed something simple?

Edit

I've already looked at this answer which isn't what I want. In referred answer, it render DOM using DynamicComponentLoader which loads another component.

This is not what I wanted, because creating new separate component for having different templateUrl doesn't make sense in mine case.

Any idea how do I implement this?

Community
  • 1
  • 1
Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
  • @MarkRajcok The way I has been done in marked as duplicate answer, created template manually/`assign independant component`. And don't wanted to create a new `component` having different `templateUrl`, it sounds repeatative to me.. please guide me If I still missed something.. – Pankaj Parkar Mar 17 '16 at 21:08
  • 1
    Dynamic templateUrls are not supported, according to the answers to the other question (that's why I originally closed this one). If you want a dynamic template, I believe you have to use DynamicComponentLoader. It seems like you're trying to create a generic component of sorts, which can have many different possible templates. That sounds like a job for a DynamicComponent loader, doesn't it? – Mark Rajcok Mar 17 '16 at 22:01
  • See http://stackoverflow.com/questions/36008476/how-to-realize-website-with-hundreds-of-pages-in-angular2 – Günter Zöchbauer Mar 18 '16 at 05:41
  • @MarkRajcok correct, this seems kind of workaround, but that need to have boilerplate code, though thanks for explanation. But in linked answer I saw that for each `templateUrl` I need to create a separate `FakeComponent` for having different templateUrl, so for 3 templateUrl's, I need to create three `FakeComponent`, which isn't sounds good for me(unwanted boilerplate code). I think should be a better way than this. am I thinking in wrong direction? – Pankaj Parkar Mar 18 '16 at 05:41
  • 1
    @AngelAngel thanks..the suggested answer over the referred link, I already tried that thing before adding question.. Angular2 doesn't have such option to have `function` for `templateUrl`, because `@Component` metadata `templateUrl` property is strongly typed as `string`, I already mentioned the thing in my question. Thanks :-) – Pankaj Parkar Mar 18 '16 at 07:57

1 Answers1

3

Been struggling with something similar, but unfortunately you can't do this. Component templates are compiled at runtime. So, basically, I would make a component that compiles other child components (which I actually did)

DynamicComponentLoader is beign deprecated. You need to use the ComponentResolver class to load other components inside the main one, like so:

function makeComponent( selector, template, ...more )
{
  @Component({ selector: selector, template: template })
  class FakeComponent {}
  return FakeComponent;
}

@Component({ ... })
export class MainCmp implements OnInit
{
  // place to insert
  @ViewChild('viewChild', {read: ViewContainerRef}) viewChild: ViewContainerRef;

  constructor(private compiler: ComponentResolver){}
  // or OnChanges, or event binding.. should work

  ngOnInit()
  {
    // decide on your custom logic here, get you @Input, whatever...

    // and you can actually make some custom dynamic component...
    let childCmp = makeComponent( custom, stuff, here );

    // compile then insert in your location, defined by viewChild
    this.compiler.resolveComponent( childCmp )
      .then( (compFactory:ComponentFactory) => this.viewChild.createComponent(compFactory) )
  }
}
Billy
  • 341
  • 3
  • 11
  • Looks like angular 2 does not support anymore this option?? – guyaloni Mar 09 '17 at 09:02
  • keeping up to date with new changes in angular2, maybe this link can help: https://angular.io/docs/ts/latest/cookbook/dynamic-component-loader.html – Billy Mar 09 '17 at 13:45