Requirement: When an opportunity's stage is one of several values, allow Opportunity Products to be edited as normal. Otherwise, disallow the edit and display a message with some key fields from the OppProduct record. The primary use case is the Edit action from the Related List on the Opportunity, as we have removed the Edit button from the Opportunity Product page layout.
In classic, we can do the following:
- Create a VF Page with the OpportunityProduct standard controller, which displays the message and key fields.
- Add an
action
param to theapex:page
tag to check the criteria and redirect if an edit is allowed.
Here's my first attempt. Note that in my case, I need to allow edits only if the Opportunity Stage Name starts with "11%", "21%", "31%", or "41%", so I'm using a simple string check.
<apex:page standardController="OpportunityLineItem"
action="{!IF(CONTAINS('11%21%31%41%',LEFT(OpportunityLineItem.Opportunity.StageName,3)),
URLFOR($Action.OpportunityLineItem.Edit, OpportunityLineItem.Id, null, true),
null)}">
<div style="display:none">{!OpportunityLineItem.Opportunity.StageName}</div>
<div>No edits are allowed on the Opportunity Product. Any changes must be made through the related Primary Quote.</div
<apex:pageBlock>
<apex:pageBlockSection title="Opportunity Product Information">
<apex:outputField value="{!OpportunityLineItem.Name}"/>
<!-- etc. -->
</apex:pageBlockSection>
</apex:pageBlock
</apex:page>
Note that I had to output {!OpportunityLineItem.Opportunity.StageName} in the page body in order to use it in the action
formula.
When used in Classic, this page correctly redirects to the standard edit page when the Stage matches the correct pattern, or remains and shows the outputFields if not.
When used in LEX, this page also correctly redirects the VF page and chooses the right behavior, however, when an edit is allowed, the redirect to the Edit view appears as the standard "Edit" popover window with a blank LEX tab behind it, instead of the prior page behind it as you would see without an action override.
In both Classic and LEX, however, if you end up in the Edit view, there is an issue - both Save and Cancel buttons redirect you back to the same Edit view. After some research and testing, I found the workaround is to pass saveURL
and retURL
params to URLFOR
, so that the action
property of the VF page becomes:
action="{!IF(CONTAINS('11%21%31%41%',LEFT(OpportunityLineItem.Opportunity.StageName,3)),
URLFOR($Action.OpportunityLineItem.Edit,
OpportunityLineItem.Id,
[saveURL=URLFOR($Action.OpportunityLineItem.View, OpportunityLineItem.Id),
retURL=URLFOR($Action.OpportunityLineItem.View, OpportunityLineItem.Id)],
true),
null)}"
Note here that I'm redirecting to the OpportunityProduct View and not the Opportunity View in order to simplify things; if I can get everything working correctly I may switch these back to the Opportunity View.
With this change, when viewing in Classic, the redirect works as before, and clicking either Save or Cancel works correctly.
However, when viewing in LEX, the addition of retURL
and saveURL
causes the Classic Edit view to be presented in a LEX tab instead of the LEX popup edit view, AND Cancel and Save remains broken; you are left on a blank LEX tab with the URL lightning/r/OpportunityLineItem/00k4u000010ryoNAAQ/edit?navigationLocation=RELATED_LIST_ROW&inContextOfRef=(a long string of charaters)
with nothing displayed.
Since I cannot get the VF page to work correctly in LEX, I decided to try a Lightning Component override. As of this writing, that means using Aura.
<aura:component implements="lightning:actionOverride,force:hasRecordId">
<aura:attribute name="oppProduct" type="Object"/>
<aura:attribute name="cannotEdit" type="Boolean" default="false"/>
<lightning:navigation aura:id="navService"/>
<force:recordData fields="Name,OpportunityId,Opportunity.StageName"
recordId="{!v.recordId}"
targetFields="{!v.oppProduct}"
recordUpdated="{!c.handleRecordData}">
</force:recordData>
<!-- omitted non-edit view -->
</aura:component>
controller:
({
handleRecordData: function(cmp, event, helper) {
var stage = cmp.get("v.oppProduct.Opportunity.StageName");
console.log("stage: ", stage);
if ( /^[1234]1%/.test(stage) ) {
var navService = cmp.find("navService");
var pageRef = {
type: "standard__recordPage",
attributes: {
objectApiName: "OpportunityLineItem",
recordId: cmp.get("v.recordId"),
actionName: "edit"
},
state: {
nooverride: 1
}
}
navService.navigate(pageRef);
}
else {
cmp.set("v.cannotEdit", true);
}
}
});
Again, the basic logic to redirect or not works fine, but when the Edit view is displayed, it's like the original VF version - the Edit Popup View occurs against a blank LEX page. Clicking Cancel leaves you on the same blank page, and clicking Save shows a success toast, and then re-displays the popup Edit view.
What is the correct way to implement a conditional Action override in LEX?