89

How can I select a specific tab when an event occurs?

I tried with [selectedIndex]="selectedTab" changing the selectedTab to the tab index needed but it doesn't seems to work after the tabs are loaded.

slaesh
  • 16,659
  • 6
  • 50
  • 52
Filipe Amaral
  • 1,683
  • 1
  • 14
  • 15

7 Answers7

170

UPDATE (using newest angular+material)

there are multiple ways..

  1. possible solution, using two-way databinding
<button mat-raised-button (click)="demo1BtnClick()">Tab Demo 1!</button>
<mat-tab-group [(selectedIndex)]="demo1TabIndex">
    <mat-tab label="Tab 1">Content 1</mat-tab>
    <mat-tab label="Tab 2">Content 2</mat-tab>
    <mat-tab label="Tab 3">Content 3</mat-tab>
</mat-tab-group>
public demo1TabIndex = 1;
public demo1BtnClick() {
  const tabCount = 3;
  this.demo1TabIndex = (this.demo1TabIndex + 1) % tabCount;
}
  1. possible solution, using template-variable and pass through our click-function
<button mat-raised-button (click)="demo2BtnClick(demo2tab)">Tab Demo 2!</button>
<mat-tab-group #demo2tab>
    <mat-tab label="Tab 1">Content 1</mat-tab>
    <mat-tab label="Tab 2">Content 2</mat-tab>
</mat-tab-group>
public demo2BtnClick(tabGroup: MatTabGroup) {
  if (!tabGroup || !(tabGroup instanceof MatTabGroup)) return;

  const tabCount = tabGroup._tabs.length;
  tabGroup.selectedIndex = (tabGroup.selectedIndex + 1) % tabCount;
}
  1. possible solution, using @ViewChild
<button mat-raised-button (click)="demo3BtnClick()">Tab Demo 3!</button>
<mat-tab-group #demo3Tab>
    <mat-tab label="Tab 1">Content 1</mat-tab>
    <mat-tab label="Tab 2">Content 2</mat-tab>
</mat-tab-group>
@ViewChild("demo3Tab", { static: false }) demo3Tab: MatTabGroup;

public demo3BtnClick() {
  const tabGroup = this.demo3Tab;
  if (!tabGroup || !(tabGroup instanceof MatTabGroup)) return;

  const tabCount = tabGroup._tabs.length;
  tabGroup.selectedIndex = (tabGroup.selectedIndex + 1) % tabCount;
}

live-demo: https://stackblitz.com/edit/angular-selecting-mattab?file=src%2Fapp%2Fapp.component.ts

slaesh
  • 16,659
  • 6
  • 50
  • 52
  • 10
    This worked for me only once. Use `[(selectedIndex)]` for two way binding. – Mathias Mar 07 '18 at 07:57
  • I had to mix solution 1 and 3 to have a good behaviour. Thanks. – Dams Jan 27 '20 at 10:32
  • 1
    I implemented #1 to trigger two tabs, one tab for login and one tab for register. To programmatically trigger the register tab, from a link that says, "no account? create account" - it works. Thanks! Although I had my link as a child component and had to trigger via eventEmitter. Works like charm still. – Gel May 04 '20 at 21:26
  • @Mathias Thank you for the idea of using `[(selectedIndex)] ` for two way binding. It helped me greatly. – David Votrubec Mar 09 '21 at 10:53
36

In case it helps anyone, it is also possible to set selectedIndex on the MatTabGroup in your component.

If your HTML has: <mat-tab-group #tabs>, you can get a reference to it in the component using @ViewChild('tabs') tabGroup: MatTabGroup;.

Then you can do this.tabGroup.selectedIndex = newIndex; in the OnInit function, or elsewhere.

Jon Onstott
  • 13,499
  • 16
  • 80
  • 133
  • 4
    Just to add to this answer: Angular 8 now requires an object with 'static' for ViewChild: `@ViewChild('tabs', {static: false}) tabGroup: MatTabGroup;` and one needs to import the following: `import { MatTabGroup } from '@angular/material';` – BoDeX Sep 04 '19 at 09:34
  • 1
    Had to use `ngAfterContentInit(`) instead of `OnInit()` for lazy loaded content. Angular first needs to "projects external content into the component's view.." and ngAfterContentInit() makes sure it is. See [Angular life cycle hooks](https://angular.io/guide/lifecycle-hooks). – Bernhard Fürst Jul 20 '20 at 14:39
10

I also had similar issue. In my case I needed to show the tab the user was there before he left the component. I solved this by stuffing the current selected tab index in a service.

On HTML template I have this:

<mat-tab-group [selectedIndex]="getSelectedIndex()" (selectedTabChange)="onTabChange($event)">

Implementation of onTabChange and getSelectedIndex are as follows:

    getSelectedIndex(): number {
        return this.appService.currentTabIndex
    }

    onTabChange(event: MatTabChangeEvent) {
        this.appService.currentTabIndex = event.index
    }

My service code looks like this:

export class AppService {
    public currentTabIndex = 1  //default tab index is 1
}
Ivan
  • 1,487
  • 1
  • 16
  • 27
user2995358
  • 977
  • 11
  • 27
6

I had the same issue and I tried the above answers but they are not helping. Here is my solution:

In my typescript code, first, declare a variable:

selected = new FormControl(0); // define a FormControl with value 0. Value means index.

then, in the function:

changeTab() {
    this.selected.setValue(this.selected.value+1);
 } //

in the html,

 <mat-tab-group [selectedIndex]="selected.value" (selectedIndexChange)="selected.setValue($event)">
            <mat-tab label="label0">0</mat-tab>
            <mat-tab label="label1">1</mat-tab>
            <mat-tab label="label2">2</mat-tab>
            <mat-tab label="label3">3</mat-tab>
            <mat-tab label="label4">4</mat-tab>
            <mat-tab label="label5">5</mat-tab>
</mat-tab-group>

<button (click)="changeTab()">ChangeTab</button>
Alex
  • 601
  • 8
  • 22
  • 2
    There is an example for this in the Angular Material docs called "Tab group with dynamically changing tabs": https://material.angular.io/components/tabs/examples – waternova May 28 '20 at 19:37
  • This is the best option and it's in the official docs above. – Meqwz Jun 21 '20 at 20:51
  • Not sure why but I had to specify index property for $event having: `(selectedTabChange)="selected.setValue($event.index)"` – Jordi Aug 16 '21 at 12:25
  • 1
    @Jordi one year late, but this is because you're using `selectedTabChange` and not `selectedIndexChange` – Rafalon Aug 02 '22 at 09:06
2

@Input()selectedIndex: number | null: The index of the active tab.  

SelectedIndex expects a number binding as property, so you can select any tab starting from 0 to (workflow_list.length - 1)

<mat-tab-group class="m-t-30" [selectedIndex]="2">
    <mat-tab label="{{wf.ApproverName}}" *ngFor="let wf of workflow_list">
    </mat-tab>
</mat-tab-group>
Toqeer Yousaf
  • 382
  • 4
  • 9
1

it's worked for me

    isActiveTab = 0 // First tab
    isActiveTab = 1 // Second Tab
        
       <mat-tab-group mat-align-tabs="start" 
         (selectedTabChange)="onTabChanged($event.index)"
          [selectedIndex]="isActiveTab" >
        
         <mat-tab label="One"> </mat-tab>
         <mat-tab label="Two"> </mat-tab>
            
       </mat-tab-group>
Siddhartha Mukherjee
  • 2,703
  • 2
  • 24
  • 29
0

I'm using angular 10 and make my mat-options with ngFor; in my case no one of the solutions didn't work and finally i found the tabIndex is the index of object in list that we have ngFor on it;

<mat-tab-group mat-align-tabs="start" style="width: 100%;text-align: start;overflow: hidden"
                     (selectedTabChange)="setNodeInfo($event)" [(selectedIndex)]="selectedIpIndex">
        <mat-tab *ngFor="let nodeTab of nodeList" [tabIndex]="nodeTab.id">
          <ng-template mat-tab-label>
            <label>{{nodeTab.ip}}</label>
            <mat-icon class="close-btn" style="font-size: medium;z-index: 100" (click)="tabClose(nodeTab)">close
            </mat-icon>
          </ng-template>
        </mat-tab>
      </mat-tab-group>

as you see i get the each tabIndex value in html like this:

[tabIndex]="nodeTab.id"

but it doesn't work and get index of position in list by its own choice.

and in my ts file i fill selectedIpIndex like this :

this.selectedIpIndex = this.nodeList.indexOf(node);
DaniyalVaghar
  • 138
  • 1
  • 2
  • 9