Search code examples
angulartypescriptprimengtabpanel

Passing value from parent to child component, where child is nested within a tabpanel of a tabview


As stated in the question, the child component is nested in the tab panel defined in the parent component. Since it is a tabview, I can have multiple tab panels within that, which would mean multiple child component with the child nested in the tab panel. I would like to set a value in the child component based on the tab panel that is active. But regardless of the tab that I am in, the only value that gets set is that of tab 0. To explain better, here is a trimmed down prototype of the existing code. I have a working example set up here: https://stackblitz.com/edit/angular-fd7b3j

Click 'Create Tabs' to create a few tabs. Make Tab 3 the current tab. Click 'Add One'. Expected outcome is that element value would get updated to 4, but instead, the element value in Tab 0 gets updated to 1. How do I redirect the action to the correct tab? Is that even possible?

app.component.html

<p-button label="Create Tabs" (onClick)="handleClick()"></p-button>
<p-button label="AddOne" (onClick)="AddOne()"></p-button>
<p-tabView (onChange)=setIndex($event) [(activeIndex)]="index">
  <p-tabPanel #panel [header]="elememt" *ngFor="let elememt of counterList; let i = index" [selected]="i == currentIndex" >
    <app-main #main [element]="counterList[i]"></app-main>
  </p-tabPanel>
</p-tabView>

app.component.ts

import { Component, ViewChild } from '@angular/core';
import { MainComponent } from './main/main.component';
import { TabViewNav, TabView } from 'primeng/tabview';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'tabViews';
  currentIndex = 0;
  @ViewChild('main') main: MainComponent;

  @ViewChild ('panel') panel: TabView;
  counter = 0;
  counterList: number[] = [];

  index = 0;

  handleClick(event: Event) {
      this.counterList = [...this.counterList, this.counter];

      setTimeout(() => {
        this.index = this.counter;
        this.currentIndex = this.counter;
        this.counter = this.counter + 1;
    }, 100);
  }

  setIndex(event) {
    this.currentIndex = event.index;
  }

  AddOne() {
    console.log(this.index);
    this.main.element = this.main.element + 1;
  }
}

main.component.ts

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-main',
  templateUrl: './main.component.html',
  styleUrls: ['./main.component.css']
})
export class MainComponent implements OnInit {
  @Input() element: number;

  constructor() { }

  ngOnInit() {
  }
}

main.component.html

{{element}}

Solution

  • that happened, becouse you used ViewChild, which gaves you just 1 reference to firs component. Now just use ViewChildren for geting arrey of your child components and then you can call each of them by currentIndex. All you have to do that fix currentIndex, it mast change by onChage action of tab view. Enjoy it :))))

    import { Component, ViewChild, ViewChildren, QueryList  } from '@angular/core';
    import { MainComponent } from './main/main.component';
    import { TabViewNav, TabView } from 'primeng/tabview';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'tabViews';
      currentIndex = 0;
      @ViewChildren('main') main: QueryList<MainComponent>;
    
      @ViewChild ('panel') panel: TabView;
      counter = 0;
      counterList: number[] = [];
    
      tabIndex = 0;
    
      handleClick(event: Event) {
          this.counterList = [...this.counterList, this.counter];
          setTimeout(() => {
          this.currentIndex = this.counter;
          this.counter = this.counter + 1;     
         }, 100);
      }
    
      AddOne() {
        console.log(this.tabIndex);
       this.main.toArray()[this.currentIndex].element = this.main.toArray()[this.currentIndex].element  + 1;
      }  
    }