6

So I might have missed something obvious in the docs, but I'm simply looking for an easy way to find which tab has been selected in the following scenario:

View

<mat-tab-group (selectedTabChange)="onTabChange($event)">
  <mat-tab *ngIf="true" label="Label1">Content 1</mat-tab>
  <mat-tab *ngIf="false" label="Label2">Content 2</mat-tab>
  <mat-tab *ngIf="true" label="Label3">Content 3</mat-tab>
</mat-tab-group>

Obviously, the conditions are dynamic in my actual code. This is just for the sample.

Script

onTabChange(event: MatTabChangeEvent) {
  // ?
}

Issue

In the above script, event.index will return 0 if I click the first tab, and 1 if I click the third tab, because the second one isn't displayed due to *ngIf.

This does make sense to me, however it's making it really hard to know which tab was actually clicked depending on which ones were displayed to begin with.

I could either:

  • test again for every tab condition within onTabChange to figure out which index corresponds to which tab,
  • (probably) bind a ViewChild(ren) reference to something and retrieve data (such as data- attributes) through their native DOM elements.

Both these options seem super overkill though.

Question

In the above code, what would be the appropriate way to know that, say, the tab labelled Label3 was clicked, without testing for the label itself (which would obviously be horrendous)?

Simple Stackblitz if that can help.

Jeto
  • 14,596
  • 2
  • 32
  • 46
  • try hiding your tab instead of removing it from DOM, i.e try using `[hidden] = "true"` instead of `*ngIf` – Sarthak Aggarwal Nov 01 '18 at 10:41
  • @SarthakAggarwal Nice suggestion and I actually tried that as well (on ``), but the tab still shows anyway as you can try on the StackBlitz. I'll try to find specific related issues. – Jeto Nov 01 '18 at 10:45
  • 1
    I ran into this as well a while back, it is unfortunate that you have to rely on the tab's index. I have (just now) created a [feature request on GitHub](https://github.com/angular/material2/issues/13921). The feature request is to allow the dev. to set a unique name per tab which can then be read back in the event on the `MatTab` instance. Please up-vote it (thumbs-up it) and let me know if I missed anything. Hopefully they will address it some point soon. – Igor Nov 01 '18 at 11:18
  • 1
    @Igor Thanks, awesome. I'll link this SO post to it in case it can provide some additional insight. I didn't read your entire post because I gotta run but I'll let you know if I find anything important missing. – Jeto Nov 01 '18 at 12:29

3 Answers3

4

Actually answering myself twice because I think this solution is interesting as well, and probably closest (yet) to what I'm looking for:

View

<mat-tab-group (selectedTabChange)="onTabChange($event)">
  <mat-tab *ngIf="true" label="tab1">
    <ng-template mat-tab-label>Label 1</ng-template>
    Content 1
  </mat-tab>
  <mat-tab *ngIf="false" label="tab2">
    <ng-template mat-tab-label>Label 2</ng-template>
    Content 2
  </mat-tab>
  <mat-tab *ngIf="true" label="tab3">
    <ng-template mat-tab-label>Label 3</ng-template>
    Content 3
  </mat-tab>
</mat-tab-group>

Script

onTabChange(event: MatTabChangeEvent) {
  const tabName = event.tab.textLabel;
  // ...
}

Basically, this uses the other way to add a (title) text label to the tab, using <ng-template>, which seems to take precedence over the label attribute.

This latter attribute can therefore be used to store the "programmatic" name of the tab (as opposed to its public text) and is easily retrieved on script side.

Jeto
  • 14,596
  • 2
  • 32
  • 46
4

Use aria-labelledby attribute to identify tab without resorting to human-readable text labels.

<mat-tab aria-labelledby="tab-x">
    <span *matTabLabel id="tab-x" i18n>Tab X</span>
</mat-tab>

In the code:

onTabChange(event: MatTabChangeEvent) {
    const tabId = event.tab.ariaLabelledby;
    if (tabId === 'tab-x') { ... }
}
Vilmantas Baranauskas
  • 6,596
  • 3
  • 38
  • 50
  • Thank you for your answer (it's an old question and I'm not doing much Angular right now so I'll need some time to get back to it, but when I do I'll make sure to mark your answer as accepted if it seems like the better solution). – Jeto Oct 28 '20 at 16:08
1

Not exactly what I was looking for, but here's the best solution I've found in the meantime:

View

<mat-tab-group (selectedTabChange)="onTabChange($event)">
  <mat-tab *ngIf="true" data-name="tab1" label="Label1">Content 1</mat-tab>
  <mat-tab *ngIf="false" data-name="tab2" label="Label2">Content 2</mat-tab>
  <mat-tab *ngIf="true" data-name="tab3" label="Label3">Content 3</mat-tab>
</mat-tab-group>

Script

onTabChange(event: MatTabChangeEvent) {
  const tabName = event.tab.content.viewContainerRef.element.nativeElement.dataset.name;
  // ...
}

Looks a bit hackish (and very verbose), but does the job.

PS: thanks to @GreenMonkeyBoy on Gitter for helping in finding this!

Jeto
  • 14,596
  • 2
  • 32
  • 46