0

I'm working on a component using a lightning:tabset component to organize my data. However, when a user clicks on another tab to switch, I want to add behavior to determine if the user has work they haven't saved, and confirm that they want to switch tabs if there is unsaved work. I'm using a confirm() call to determine if they want to continue. If that call returns false, I want to block the switch from happening and stay on the current tab so the user can save. What would be the best way to handle stop the switch from taking place?

Component Code:

<aura:component implements="force:hasRecordId,flexipage:availableForRecordHome">
    <aura:attribute name="day" type="String" default="Mon" />
    <aura:attribute name="acceptedDay" type="String" default="Mon" />


    <aura:attribute name="ignoreDayChangeHandler" type="Boolean" default="false"/>
    <aura:handler name="change" value="{!v.day}" action="{!c.confirmTabSwitch}"/>

    <lightning:tabset selectedTabId="{!v.day}" class="tab-label" aura:id="tabs">
        <lightning:tab aura:id="tab" label="Mon" id="Mon">

        </lightning:tab>

        <lightning:tab aura:id="tab" label="Tue" id="Tue">

        </lightning:tab>
    </lightning:tabset>
</aura:component>

Controller code:

confirmTabSwitch : function (component, event, helper) {
    if (component.get("v.ignoreDayChangeHandler")) {
        return;
    }

    var selected;

    //there is code here to confirm if there is any need to block. If there is no such need, it returns.

    var confirmChange = confirm("You have unsaved changes. Click \"OK\" to continue without saving.");


    if (confirmChange === true) {
        component.set("v.acceptedDay", component.get("v.day"));
        selected = component.get("v.day");
    } else {
        component.set("v.ignoreDayChangeHandler", true); //Being we're about to change v.day, ignore the change handler.
        selected = component.get("v.acceptedDay"); //Re-set v.day to v.acceptedDay.
        component.set("v.ignoreDayChangeHandler", false);
    }

    component.set("v.ignoreDayChangeHandler", true);
    component.set("v.day", selected);
    component.find("tabs").set("v.selectedTabId",selected);
    component.set("v.ignoreDayChangeHandler", false);
}
  • 1
    Can you share a little bit of code so we can help better? – Sebastian Kessel Jul 9 '19 at 23:01
  • @SebastianKessel added! – Dylan Bowman Jul 9 '19 at 23:09
2

I am not aware of a mechanism that you'll be able to use to accomplish this with lightning:tabset because there does not appear to be any sort of hook like onBeforeChange() that you'd need to prevent something from happening.

Your best bet might be custom code the tab components yourself, which may sound like a daunting task, except for the fact that lightning design system has an excellent blueprint that shows you how to do plenty of the heavy lifting.

For very detailed information, see the following link: https://lightningdesignsystem.com/components/tabs/

Sample markup from that link:

<div class="slds-tabs_default">
  <ul class="slds-tabs_default__nav" role="tablist">
    <li class="slds-tabs_default__item slds-is-active" title="Item One" role="presentation">
      <a class="slds-tabs_default__link" href="javascript:void(0);" role="tab" tabindex="0" aria-selected="true" aria-controls="tab-default-1" id="tab-default-1__item">Item One</a>
    </li>
    <li class="slds-tabs_default__item" title="Item Two" role="presentation">
      <a class="slds-tabs_default__link" href="javascript:void(0);" role="tab" tabindex="-1" aria-selected="false" aria-controls="tab-default-2" id="tab-default-2__item">Item Two</a>
    </li>
    <li class="slds-tabs_default__item" title="Item Three" role="presentation">
      <a class="slds-tabs_default__link" href="javascript:void(0);" role="tab" tabindex="-1" aria-selected="false" aria-controls="tab-default-3" id="tab-default-3__item">Item Three</a>
    </li>
  </ul>
  <div id="tab-default-1" class="slds-tabs_default__content slds-show" role="tabpanel" aria-labelledby="tab-default-1__item">Item One Content</div>
  <div id="tab-default-2" class="slds-tabs_default__content slds-hide" role="tabpanel" aria-labelledby="tab-default-2__item">Item Two Content</div>
  <div id="tab-default-3" class="slds-tabs_default__content slds-hide" role="tabpanel" aria-labelledby="tab-default-3__item">Item Three Content</div>
</div>

Once you've got the markup, you'll need to follow their instructions for manipulating CSS from your JS controller

When the user clicks a different tab, move the .slds-active class and toggle the .slds-hide/.slds-show classes.

It would be far preferable to do this using the native lightning:tab and lightning:tabset components, but if nobody can clue you into an approach that will do that for you, you've now got an option to consider.

The only other idea I've got (not tested) would be to tie into the fact that lightning:tabset has an 'onselect' controller action as well as a 'selectedTabId' property. Maybe in the 'onselect' you could force them back to your original tab if your condition fails. If you want to try it you may need to check out the following thread for more info about programatically setting the tab id. It's from 2017 so you should test any assumptions.

How do I use the lightning:tabset selectedTabId to change the current tab?

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.