Angular Material Tab : Prevent tab change of mat-t

2020-02-15 08:52发布

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.

1条回答
甜甜的少女心
2楼-- · 2020-02-15 09:14

This solution is just a hack and has its flaws. It is mentioned below.

Steps :

In the template :

  1. Disable all tabs of the mat-tab-group <mat-tab label="Tab 0" disabled>
  2. 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 :

  1. Declare the variable selectedTabIndex
    selectedTabIndex = 0;

  2. 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

  3. 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 :

  1. 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;
     }
    
  2. 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>
查看更多
登录 后发表回答