9

Here is my sample code

Main Controller

<mat-tab-group id="report">
<mat-tab label="Poll">
<div class="demo-tab-content">
  <app-poll></app-poll>
</div>

</mat-tab>
<mat-tab label="Survey">
<div class="demo-tab-content">
  <app-survey></app-survey>
</div>
</mat-tab>

In each tab, there is different controller named - Poll and Survey. Here I want to refresh\reset one tab data if the user moves from one to another.

Any simple way to achieve that?

Prashant Pimpale
  • 10,349
  • 9
  • 44
  • 84
  • 1
    Possible duplicate of [Angular 2 How to "watch" for tab changes](https://stackoverflow.com/questions/42059151/angular-2-how-to-watch-for-tab-changes) – David Apr 03 '18 at 12:10
  • @David I tried above code but it is not working for me. It directly navigating to brand new route which I don't want. Need to stay on the current tab but data should be refreshed after the tab change – Prashant Pimpale Apr 03 '18 at 12:29
  • See my answer if it helps – David Apr 03 '18 at 13:05

3 Answers3

12

If you don't want to use @Input parameters, you can also use @ViewChild to get a reference to your child components and then call a method on these components to refresh the data

component.ts

  import {ViewChild} from '@angular/core';
  import { MatTabChangeEvent } from '@angular/material';
  //...
  @ViewChild(PollComponent) private pollComponent: PollComponent;
  @ViewChild(SurveyComponent) private surveyComponent: SurveyComponent;


  //...
  onTabChanged(event: MatTabChangeEvent) 
  {
    if(event.index == 0)
    {
        this.pollComponent.refresh();//Or whatever name the method is called
    }
    else
    {
        this.surveyComponent.refresh(); //Or whatever name the method is called
    }
  }

component.html

<mat-tab-group id="report" (selectedTabChange)="onTabChanged($event)">

</mat-tab>
David
  • 33,444
  • 11
  • 80
  • 118
  • I've tried setting it up like this but this.surveyComponent is not defined, so the refresh doens't get triggered... any idea why? Looks good on paper to me though – BHANG Nov 03 '20 at 15:48
  • @BHANG Maybe post a new question with a stackblitz exemple – David Nov 06 '20 at 16:02
  • my bad, my components weren't parent-child ;-) thanks for replying though – BHANG Nov 07 '20 at 14:53
4

In angular material 8, there is an option for lazy loading the component in tabs when user selects it.

you can simply wrap your component to be lazy loaded in ng-template as shown in link below

https://material.angular.io/components/tabs/overview#lazy-loading

1

You can read about component interaction types here.

You need something like this:

1. Children -> parent

In both of the components, have an need an emitter.

MainController:

  <app-poll (changed)=this.update($event)></app-poll>

  <app-survey (changed)=this.update($event)></app-survey>

In the components, have an event emitter defined:

@Output() changeEmitter = new EventEmitter<any>();

when you want to trigger the reset, write something like this:

changedEmitter.emit(<<you can insert objects here>>);

This will trigger the call in their parent's this.update().

in that method, you can define other logic to trigger a reset, but from parent-child, the easiest way is to bind a data object, which you can change:

2. Parent-> children

  <app-survey (changed)=this.update(newValue) [data]="surveyData"></app-survey>

in the main comp ts:

private surveyData: any;

update(newValue: any){
  surveyData =  <<something>>
}

in the survey comp:

@Input() private data: any;
ForestG
  • 17,538
  • 14
  • 52
  • 86
  • Is there any other way than above one? – Prashant Pimpale Apr 03 '18 at 12:32
  • the comment below reflects to that, although I do not think that that solution is clean-code. It feels wrong to call a different components functions directly, as it is supposed to be encapsulated iside the component and accessed via it's interface in my opinion. – ForestG Apr 03 '18 at 13:46
  • Yes exactly. But I am new to angular hence I am not able to decide which one is better. Can you explain or any reference code for about comment? It would be grateful..! – Prashant Pimpale Apr 04 '18 at 06:55
  • 1
    Angular uses an automatic change detection in the DOM. If somhing triggers it, it re-renders only part of the document - only the ones, Angular think it needs to update as it is a resource-heavy and costly operation. To narrow down the required re-rendering parts, you should stick to the official recommendations: from parent to child use direct binding, and from children to parent use event emitters. As the DOM is a tree representation, following the flow of that tree, you can achive quite fast updates. [Source](https://angular.io/guide/component-interaction) – ForestG Apr 04 '18 at 07:12
  • did this answer help you? – ForestG Apr 05 '18 at 06:43
  • Nope. Still not able to achieve that. I have tried what suggested by @David approach for the temporary purpose. – Prashant Pimpale Apr 05 '18 at 12:16
  • @David as per documentation of an Angular Material I have used Tabs and navigation [https://material.angular.io/components/tabs/overview#tabs-and-navigation] which exactly do the same thing what Tab does with the router link parameter. I have to post an answer to my own question but due to less reputation not able to do that how do i submit that? – Prashant Pimpale Apr 09 '18 at 10:17