I was trying to prevent tab change of mat-tab
, if the form in currently active tab is dirty.
But I couldn't find a way to intercept the tab change event.
<mat-tab-group>
<mat-tab label="Tab 0" >
// Tab 0 Content
</mat-tab>
<mat-tab label="Tab 1" >
// Tab 1 Content
</mat-tab>
<mat-tab label="Tab 2" >
// Tab 2 Content
</mat-tab>
</mat-tab-group>
Even though there is a selectedTabChange
event, we can't prevent tab change. we can only switch tab programatically after tab change.
I have got a hack to make it possible. Just posting here to help if someone encounters the same.
This solution is just a work around and has its flaws. It is mentioned below.
Steps :
In the template :
Disable all tabs of the mat-tab-group
<mat-tab label="Tab 0" disabled>
Provide a click event handler on mat-tab-group.
Also set the selectedIndex
property using a variable from the component class.
<mat-tab-group (click)="tabClick($event)" [selectedIndex]="selectedTabIndex">
In the Component class :
Declare the variable selectedTabIndex
selectedTabIndex = 0;
Create a method to get the tab Index , provided the tab label.
getTabIndex(tabName: string): number {
switch (tabName) {
case 'Tab 0': return 0;
case 'Tab 1': return 1;
case 'Tab 2': return 2;
default: return -1; // return -1 if clicked text is not a tab label text
}
}
We can get the tab-label text from a property of the click event
`clickEventName.toElement.innerText`
Create the method for handling the click event on mat-tab-group.
tabClick(clickEvent: any) {
// Get the index of clicked tab using the above function
const clickedTabIndex = this.getTabIndex(clickEvent.toElement.innerText);
// if click was not on a tab label, do nothing
if (clickedTabIndex === -1) {
return;
}
// if current tab is same as clicked tab, no need to change.
//Otherwise check whether editing is going on and decide
if (!(this.selectedTabIndex === clickedTabIndex)) {
if ( /*logic for form dirty check*/ ) {
// if form is dirty, show a warning modal and don't change tab.
}
else {
// if form is not dirty, change the tab
this.selectedTabIndex = clickedTabIndex;
}
}
}
In my case each tab content was in separate components. So I used @ViewChild
to access them and check whether any of the form is dirty or not.
Flaws :
Since this method uses the text of clicked element for switching tabs, there is a chance that one of your tab may contain some element with text content same as the heading of other tabs.
So it may trigger a tab change. You can look for other properties in click event to prevent this scenario if possible.
I used following code in tabClick()
method's beginning
if (!((clickEvent.toElement.className).toString().includes('mat-tab-label'))) {
return;
}
You may need to override the css
of disabled
state of mat-tab
to make it look natural
Template :
<mat-tab-group (click)="tabClick($event)" [selectedIndex]="selectedTabIndex">
<mat-tab label="Tab 0" disabled>
// Tab 0 Content
</mat-tab>
<mat-tab label="Tab 1" disabled>
// Tab 1 Content
</mat-tab>
<mat-tab label="Tab 2" disabled>
// Tab 2 Content
</mat-tab>
</mat-tab-group>