Angular2 loading dynamic content/html in for loop
Asked Answered
C

2

10

I have a json array which can contain either the component or the html selector for the component i want to load. I am trying to load this data inside a for loop. When I try to interpolate the value {{d.html}} it appears as plan text. When I use the innerHTML approach below and inspect the dom I see the html there but it does not behave as a custom component (the dom will just contain instead of initializing it and replacing it with the components template.

I have look at the dynamic content loader but that does not see to fit. This is in a for loop and therefore can not use the template syntax so loadIntoLocation will not work for me. Also not sure how it would work if the component had any input.

<div *ngFor="#d of dtabs" class="tab-pane" id="tab-{{d.component}}">
  <div [innerHTML]="d.html"></div>
</div>
Calbert answered 17/2, 2016 at 13:5 Comment(0)
S
9

I also was looking for a way to do that. I saw the @guyoung answer and built something based on that. But then, I realised that DynamicComponentLoader.loadIntoLocation() doesn't exist anymore in the last version, and DynamicComponentLoader is already deprecated.

I read some docs and posts and created a new Directive that worked fine. Check out:

import {
  Component,
  ComponentResolver,
  Directive,
  ViewContainerRef,
  Input,
  Injector,
  ApplicationRef
} from "@angular/core";

/**

  This component render an HTML code with inner directives on it.
  The @Input innerContent receives an array argument, the first array element
  is the code to be parsed. The second index is an array of Components that
  contains the directives present in the code.

  Example:

  <div [innerContent]="[
    'Go to <a [routerLink]="[Home]">Home page</a>',
    [RouterLink]
  ]">

**/
@Directive({
  selector: '[innerContent]'
})
export class InnerContent {

  @Input()
  set innerContent(content){
    this.renderTemplate(
      content[0],
      content[1]
    )
  }

  constructor(
    private elementRef: ViewContainerRef,
    private injector: Injector,
    private app: ApplicationRef,
    private resolver:ComponentResolver){
  }

  public renderTemplate(template, directives) {
    let dynComponent = this.toComponent(template, directives)
    this.resolver.resolveComponent(
      dynComponent
    ).then(factory => {
      let component = factory.create(
        this.injector, null, this.elementRef._element.nativeElement
      );

      (<any>this.app)._loadComponent(component);
      component.onDestroy(() => {
        (<any>this.app)._unloadComponent(component);
      });
      return component;
    });
  }

private toComponent(template, directives = []) {
  @Component({
    selector: 'gen-node',
    template: template,
    directives: directives
  })
  class DynComponent {}
    return DynComponent;
  }
}
Swarth answered 22/5, 2016 at 22:9 Comment(3)
I think this snippet needs go into the angular docs. I used to render an embedded component in a template obtained form the server and it worked perfectly. Many thanks.Glyptics
This should be the official answerDuel
ComponentResolver has been depreciated. Could you please update? ThanksDomini
D
3

Angular2 Dynamically Render Template

import { Component, View, DynamicComponentLoader, ElementRef} from 'angular2/core';
import {bootstrap}    from 'angular2/platform/browser'
@Component({
    selector: 'some-component',
    properties: ['greeting'],
    template: `
    <b>{{ greeting }}</b>
  `
})
class SomeComponent { }
@Component({
    selector: 'app'
})
@View({
    template: `
    <h1>Before container</h1>
    <div #container></div>
    <h2>After container</h2>
  `
})
class App {
    loader: DynamicComponentLoader;
    elementRef: ElementRef;

    constructor(loader: DynamicComponentLoader, elementRef: ElementRef) {
        this.laoder = loader;
        this.elementRef = elementRef;

        // Some async action (maybe ajax response with html in it)
        setTimeout(() => this.renderTemplate(`
      <div>
    <h2>Hello</h2>
    <some-component greeting="Oh, hey"></some-component>
      </div>
    `, [SomeComponent]), 1000);
    }

    renderTemplate(template, directives) {
        this.laoder.loadIntoLocation(
            toComponent(template, directives),
            this.elementRef,
            'container'
        )
    }
}
function toComponent(template, directives = []) {
    @Component({ selector: 'fake-component' })
    @View({ template, directives })
    class FakeComponent { }

    return FakeComponent;
}


bootstrap(App);

full code : https://github.com/guyoung/GyPractice-Angular2Advanced/tree/master/apps/dynamically_render_template

Doncaster answered 19/2, 2016 at 1:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.