3

I would like to know what is the best way (performance) to create dynamic component. I tried both but I'm not able to determine which one I should use.

With an ng-switch in my component.html container

@Component({
  selector: 'app-component-container',
  template: `<div [ngSwitch]="typeComponent">
              <app-component-one *ngSwitchCase="1" [value]="someValue"></app-component-one>
              <app-component-two *ngSwitchCase="2" [value]="someValue"></app-component-two>
              <app-component-three *ngSwitchCase="3" [value]="someValue"></app-component-three>
              </div>`
})
export class ContainerComponent implements OnInit {
  private typeComponent: number;
  private someValue: string;

  constructor() {
    this.typeComponent = 2;
    this.someValue = "Hello";

  }

  ngOnInit() {

  }
}

or with a component builder in my component.ts container

@Component({
  selector: 'app-component-container',
  template: '<div #container></div>'
})
export class ContainerComponent implements OnInit {
  @ViewChild('container', {read: ViewContainerRef}) container: ViewContainerRef;

  private typeComponent: number;

  private someValue: string;

  constructor(private _resolver: ComponentFactoryResolver) {
    this.typeComponent = 2;
    this.someValue = "Hello";
  }

  ngOnInit() {
    let childComponent: ComponentRef<any> = null;
    switch (this.typeComponent) {
      case 1:
        childComponent = this.container.createComponent<ChildComponentOne>(this._resolver.resolveComponentFactory(ChildComponentOne));
        break;
      case 2:
        childComponent = this.container.createComponent<ChildComponentTwo>(this._resolver.resolveComponentFactory(ChildComponentTwo));
        break;
      case 3:
        childComponent = this.container.createComponent<ChildComponentThree>(this._resolver.resolveComponentFactory(ChildComponentThree));
        break;
    }

    if (childComponent != null) {
      childComponent.instance.value = this.someValue;
    }
  }
}

This are simple exemple, in my application I have huge imbrication of dynamic component.

Thank you in advance for your answer guys.

1
  • In my second exemple, the cool thing is I can have an instance on my childComponent, I can easily manipulate the instance and call methods. In my opinion this is more OO way. Commented Dec 14, 2016 at 16:37

1 Answer 1

3

Although both ways are viable, for the sake of DRYness, readability and future maintenance I would probably go the second way - that is, creating a dynamic component via the API and inserting it as a child of the container...

You can further decrease duplication in your code this way:

ngOnInit() {
  let childComponentType: Type = null;
  switch (this.typeComponent) {
    case 1:
      childComponentType = ChildComponentOne;
      break;
    case 2:
      childComponentType = ChildComponentTwo;
      break;
    case 3:
      childComponentType = ChildComponentThree;
      break;
  }

  if (childComponentType != null) {
    let factory = this._resolver.resolveComponentFactory(childComponentType);
    let instance: ComponentRef<any> = this.container.createComponent(factory);

    childComponent.instance.value = this.someValue;
  }
}

You could also have all of your 3 example components inherit a common base class and have your common attributes, methods and @Outputs in the base class. This way you could read values and subscribe to EventEmitters when each component share a common behaviour.

Something along these lines:

export class ChildComponentBaseClass {
  @Input() value;
}

@Component({...})
export class ChildComponentOne<ChildComponentBaseClass> {
  ...
}
@Component({...})
export class ChildComponentTwo<ChildComponentBaseClass> {
  ...
}

ngOnInit() {
  let childComponentType: Type = null;
  switch (this.typeComponent) {
    case 1:
      childComponentType = ChildComponentOne;
      break;
    case 2:
      childComponentType = ChildComponentTwo;
      break;
    case 3:
      childComponentType = ChildComponentThree;
      break;
  }

  if (childComponentType != null) {
    let factory = this._resolver.resolveComponentFactory(childComponentType);
    let instance: ComponentRef<ChildComponentBaseClass> = this.container.createComponent<ChildComponentBaseClass>(factory);

    // instance.value is now properly typed!
    childComponent.instance.value = this.someValue;
  }
}
Sign up to request clarification or add additional context in comments.

1 Comment

A sight improvement to get rid of the verbose switch would be to use a dictionary. const typeToComponentMap = { 1: ChildComponentTwo, 2: ChildComponentTwo, 3: ChildComponentThree }; then use: let factory = this._resolver.resolveComponentFactory(typeToComponentMap[this.typeComponent]);

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.