Issue in loading dynamic components in individual angular tabs

1,833 views
Skip to first unread message

Navaneetha Krishnan S

unread,
Dec 19, 2017, 8:33:23 PM12/19/17
to Angular and AngularJS discussion

I have a requirement where I need to load the angular components dynamically inside a (/) tabs. By default when the page loads I wanted to load a component and on some user interaction the other components to be loaded by bubbling the already loaded components event trigger.

The tabs can grow dynamically based on user interaction and each tab would be loaded with a dynamic component in it. It might happen that the same component can be loaded in multiple tabs with different contents being populated based on the @Input parameter being passed into it.

Note:

  1. I need to pass both @input and @Output parameters i.e. the events can be bubbled out to the parent to do some functionalities etc.

  2. When the user switch across the tabs, the components should not reload every time

The problem that I am facing is when I am trying to load components dynamically, its getting loaded in the first tab itself and not in thier respective tabs. Instead the expectation is the second component should be loaded on the second tab and not on the first tab. instead currently all the components are getting loaded in the first tab itself.

I have created a working POC on stackblitz where the same issue can be reproduced

The parent component which hosts the angular tab

@Component({
  selector: 'home',
  template: `<mat-tab-group class="demo-tab-group">
  <mat-tab *ngFor="let tab of homepageTabs; let i = index" label="{{tab.label}}">
    <div class="demo-tab-content">
      <!--dynamic components i.e. Component1 and Component2 to be loaded here...-->
      <ng-container #placeholder>{{tab.templateRef}}</ng-container>
   </div>
  </mat-tab>
  </mat-tab-group>
  `
})
export class HomeComponent implements AfterViewInit {
    activeTabIndex: any;
    cmpRef: ComponentRef<any>;
    @ViewChild('placeholder', { read: ViewContainerRef }) target: ViewContainerRef;

    homepageTabs = [
      {
        label: 'HomeLabel',
        templateRef: null,
        tabTitle: 'HomeTitle'
      }
    ];

    constructor(private cfr: ComponentFactoryResolver)
    {
      this.activeTabIndex = 0;
    }

    ngAfterViewInit() {
      let factory = this.cfr.resolveComponentFactory(Component1);
      this.cmpRef = this.target.createComponent(factory);
      this.cmpRef.instance.CompclickEvent.subscribe((v) => { this.Compclick(v) });
      //this.homepageTabs.replace()
      //this.homepageTabs[0].templateRef = this.cmpRef;
    }

    Compclick(value: any) {
      this.activeTabIndex = this.activeTabIndex + 1;
      console.log("Event bubbled from the child component.");
      this.addTab("Child " + this.activeTabIndex, this.activeTabIndex);
    }

    addTab(tabTitle: any, tabPosition: any): void {
      let factory = this.cfr.resolveComponentFactory(Component2);
      this.cmpRef = this.target.createComponent(factory)
      this.activeTabIndex = tabPosition;
      this.homepageTabs.splice(tabPosition, 0, {
        label: tabTitle,
        templateRef: this.cmpRef,
        tabTitle: tabTitle
      });
    }
}

the First child component is as below

@Component({
  selector: 'Component1',
  template: `<div >Component1 Loaded, click on the button to load child component</div><button type="button" class="action-btn action-btn-default" style="float:left" (click)="compclicked()">Click</button><br/> `
})
export class Component1 {
  @Output() CompclickEvent = new EventEmitter();
  constructor(){
  }

  compclicked()
  {
    console.log("Clicked on child component, bubbling the event to the parent");
    this.CompclickEvent.emit();
  }
}

What is the mistake I am doing here? why all the components are getting loaded in the first tab itself?

Sander Elias

unread,
Dec 20, 2017, 12:01:30 AM12/20/17
to Angular and AngularJS discussion
Hi Navaneetha,

You use a viewChild #placeholder in your code. Both of those are resulting in a single point where you insert your dynamic component.
Use viewChildren, and something else to get hold of the place where you want to insert.

Regards
Sander

Sander Elias

unread,
Dec 20, 2017, 12:03:44 AM12/20/17
to Angular and AngularJS discussion
I forgot to mention, use a setTimeout to split out the actual creation of the tab itself, and it's content. You cannot add stuff to a view that hasn't be created yet.

murali krish

unread,
Nov 12, 2018, 11:27:17 PM11/12/18
to Angular and AngularJS discussion
Hi Navaneeth, Am also having same issue. Were you able to fix this out?

NavaneethaKrishnan S

unread,
Nov 13, 2018, 3:16:42 PM11/13/18
to ang...@googlegroups.com
Hi,
you can find the working sample here https://stackblitz.com/edit/angular-e7fnhd-ihumnz
let me know if you need more details

Regards,
Krishnan

--
You received this message because you are subscribed to a topic in the Google Groups "Angular and AngularJS discussion" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/Vd7ZCcKUqaM/unsubscribe.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at https://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages