4

I have a component that makes a request to fetch an Angular template from the server and render it at runtime. Please keep in mind that the template is an Angular formatted template using Angular pipes and directives, so it's not something like using lodash templates. A very simple example of this template would be:

<ul>
  <li *ngFor="let item of items">
    {{ item.name | titlecase }}
  </li>
</ul>

In my component I've tried doing the following that excludes actually fetching the template from the server for my example for simplicity sake:

@Component({
  selector: 'app-landing-page',
  template: `<div [innerHtml]="template"></div>`,
})
export class LandingPageComponent {
  @ViewChild('dynamicComponentContainer', { read: ViewContainerRef, static: true })
  container: ViewContainerRef;

  ngAfterViewInit() {
    const componentRef = this.container.createComponent(DynamicTemplateComponent);
    componentRef.instance.items = [{ name: 'foo' }, { name: 'bar' }, { name: 'baz' }];
    componentRef.instance.template = `<ul>
      <li *ngFor="let item of items">
        {{ item.name | titlecase }}
      </li>
    </ul>`;
  }
}

And here is the DynamicTemplateComponent that is used to create the component to dynamically render the Angular template:

@Component({
  selector: 'app-dynamic-template',
  template: `<div [innerHtml]="template"></div>`,
})
export class DynamicTemplateComponent {
  @Input() template: string;
  @Input() items: any[];
}

Unfortunately this doesn't produce any results. Any help is much appreciated.

2 Answers 2

5

You can create dynamic components with a custom template and any other properties.

In this case if you want to dynamically change decorated properties on a component creation then it needs to be manually compiled async. Please check the example below:

  ngOnInit(): void {
    const template = `<div *ngFor="let item of items">{{ item }}</div>`;
    const component = getComponentFromTemplate(template);

    const componentRef = this.viewRef.createComponent(component);
    componentRef.setInput('items', ['value1', 'value2']);
  }
@Component({
    template: '',
  }) class MyCustomComponent {
    @Input() items: string[] = [];
}

function getComponentFromTemplate(template: string) {
  ɵcompileComponent(MyCustomComponent, {
    template,
    standalone: true,
    imports: [NgFor],
  });

  return MyCustomComponent;
}

And there is example on stackblitz: working example

Sign up to request clarification or add additional context in comments.

7 Comments

This is excellent, however, I'm using Angular 13.0.0 and it appears that "standalone" isn't recognized. Would I just need to register my component in the declarations within feature's module?
Someone have already tried using material components in the template? It seems it doesn't work at runtime. Any solutions? My test: stackblitz.com/edit/angular-xpmp2a
Don't you forget add all needed material modules to imports?
|
0

If you don't want to deal with including the JiT-compiler into your build like the other answer shows and all you need is to load components from strings, you could alternatively use the Angular Dynamic Hooks library.

Its designed to load components into dynamic "templates" like strings or even existing HTML structures without needing the JiT-compiler. It works with just about any version of Angular including the newest (v18+), supports AoT, Server-Side-Rendering and most other Angular configs. You could use it like this:

// The content to parse
content = 'Load a component here: <app-example></app-example>';

// A list of components to look for
parsers = [ExampleComponent];
<ngx-dynamic-hooks [content]="content" [parsers]="parsers"></ngx-dynamic-hooks>

Note that it can only load components into dynamic content, it doesn't parse Angular template syntax like ngFor, etc. itself. You'd have to wrap stuff like that in a component and load the component in your string instead to work. So I'm not sure it 100% fits your use case, but I though it might help others stumbling on this thread with similar problems.

I've been maintaining the library for some years now and initially wrote it to address those same limitations. It there are any questions, I'd be glad to help.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.