8

I'm aware this is not the best solution but I would like to be able to load components dynamically from a JSON response, something along these lines:

app.component

@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1> {{component.title}} {{component.selector}}',
    providers: [AppService],
    directives: [ExampleComponent]
})
export class AppComponent implements OnInit {

    component:{};

    constructor(
        private _appService: AppService) {
    }

    ngOnInit() {
        this.component = this._appService.getComponent();
    }
}

app.service

@Injectable()
export class AppService {

    component = {
        title: 'Example component',
        selector: '<example></example>'
    }

    getComponent() {
        return this.component;
    }
}

example.component

@Component({
    selector: 'example',
    template: 'This a example component'
})
export class ExampleComponent  {
}

If I run this example, my output is <example></example> but it doesn't actually render the component. Also I've tried to use [innerHtml]="component.selector", but that also didn't work. Does anyone have an idea or suggestion?

1 Answer 1

6

update

The code to create components has changed a bit. A working example can be found in Angular 2 dynamic tabs with user-click chosen components


To insert a component dynamically you can use ViewContainerRef.createComponent()

For a declarative approach you can use a helper component like

@Component({
  selector: 'dcl-wrapper',
  template: `<div #target></div>`
})
export class DclWrapper {
  @ViewChild('target', {read: ViewContainerRef}) target;
  @Input() type;
  cmpRef:ComponentRef;
  private isViewInitialized:boolean = false;

  constructor(private resolver: ComponentResolver) {}

  updateComponent() {
    if(!this.isViewInitialized) {
      return;
    }
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }
   this.resolver.resolveComponent(this.type).then((factory:ComponentFactory<any>) => {
      this.cmpRef = this.target.createComponent(factory)
    });
  }

  ngOnChanges() {
    this.updateComponent();
  }

  ngAfterViewInit() {
    this.isViewInitialized = true;
    this.updateComponent();  
  }

  ngOnDestroy() {
    if(this.cmpRef) {
      this.cmpRef.destroy();
    }    
  }
}

See also Angular 2 dynamic tabs with user-click chosen components

In you example you can use it like

@Component({
    selector: 'my-app',
    template: '<h1>My First Angular 2 App</h1> {{component.title}} <dcl-wrapper [type]="component.type"></dcl-wrapper>',
    providers: [AppService],
    directives: [ExampleComponent]
})
export class AppComponent implements OnInit {

    component:{};

    constructor(
        private _appService: AppService) {
    }

    ngOnInit() {
        this.component = this._appService.getComponent();
    }
}
import {ExampleComponent} from './example.component.ts';

@Injectable()
export class AppService {

    component = {
        title: 'Example component',
        type: ExampleComponent
    }

    getComponent() {
        return this.component;
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

@GünterZöchbauer Is there a way to replace the target with the component?
I don't think so.
@Geo is this working, does it mean you can load a component from a remote call returning component as json or is there something I didn't get ?
@GünterZöchbauer not sure I get your answer

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.