Jeto
Jeto

Reputation: 14927

Angular Material - Know exactly which tab was selected

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:

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.

Upvotes: 6

Views: 5164

Answers (3)

Vilmantas Baranauskas
Vilmantas Baranauskas

Reputation: 6726

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') { ... }
}

Upvotes: 5

Jeto
Jeto

Reputation: 14927

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!

Upvotes: 1

Jeto
Jeto

Reputation: 14927

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.

Upvotes: 4

Related Questions