Tweet |
Unsaved Changes in Spring 19
Introduction
As I mentioned in my last post, it’s often the little things in a release that make all the difference. Another small change in the Spring 19 release is the lightning:unsavedChanges aura component (yes aura, remember that in Spring 19 Lightning Web Components are GA and Lightning Components are renamed Aura Components). The release notes are somewhat understated - "Notify the UI about unsaved changes in your component”, but what this means is that I can retire a bunch of code/components that I’ve written in the past to sop the user losing their hard earned changes to a record. Even better, I’m wiring in to the standard Lightning Experience behaviour so I don’t need to worry if Salesforce change this behaviour, I’ll just pick it up automatically.
Example
My example component is a simple form with a couple of inputs - first and last name:
<aura:component implements="flexipage:availableForAllPageTypes"> <aura:attribute name="firstname" type="String" /> <aura:attribute name="lastname" type="String" /> <aura:handler name="change" value="{!v.firstname}" action="{!c.valueChanged}"/> <aura:handler name="change" value="{!v.lastname}" action="{!c.valueChanged}"/> <lightning:card variant="narrow" title="Unsaved Example"> <div class="slds-p-around_medium"> <lightning:input type="text" label="First Name" value="{!v.firstname}" /> <lightning:input type="text" label="Last Name" value="{!v.lastname}" /> <lightning:button variant="brand" label="Save" title="Save" onclick="{! c.save }" /> </div> </lightning:card> <lightning:unsavedChanges aura:id="unsaved" onsave="{!c.save}" ondiscard="{!c.discard}" /> </aura:component>
I have change handlers on the first name and last name attributes, so that I can notify the container that there are unsaved changes. I achieve this via the embedded lightning:unsavedChanges component, which exposes a method named setUnsavedChanges. In my change handler I invoke this method:
valueChanged : function(component, event, helper) { var unsaved = component.find("unsaved"); unsaved.setUnsavedChanges(true, { label: 'Unsaved Example' }); }
So now if I add this component to a Lightning App page, enter some text and then try to click on another tab, I get a nice popup telling me that I may be making a big mistake. It also displays the label that I passed the setUnsavedChanges method, so that if there are multiple forms on the page then the user can easily identify which one I am referring to.
Of course, my Evil Co-Worker immediately spotted that they could pass the label of a different component and keep the user in a loop where they believe they have saved the changes but keep getting the popup. If I’m honest I expected something a bit more evil from them, like calling a method that clears the unsaved changes without saving the record when the user clicks the Save button, clearly getting lazy as well as Evil in their old age.
What’s even nicer is that if I click the Discard Changes or Save buttons, my controller methods to discard or save the record are invoked, because I specified these on the component:
<lightning:unsavedChanges ..." onsave="{!c.save}" ondiscard="{!c.discard}" />
so I have full control over what happens.
This kind of interaction with the user is possible when I click on a link that is managed by the Lightning Experience, but not so much if I reload the page or navigate to a bookmark. In this scenario I’m at the mercy of the beforeunload event, which is browser specific and much more limited.
This behaviour can’t be customised, the idea being that you can’t hold a user on your page against their will, regardless of whether you are doing it for their own good.
On another note, when I created the original lightning app page for this I used a single column, but the inputs then spanned the whole page. Thanks to the Spring 19 feature of changing lightning page templates, I was able to switch to header, body and right sidebar in a few seconds, rather than having to create a whole new page. I sense that feature is the gift that keeps giving.
It is not working in the community once the component in inside the community.
ReplyDeleteHi, How can we pass the body in <lightning:unsavedChanges tag. there is an attribute "Body" in this tag where we can pass component. can you please help me how can we pass.
ReplyDelete