I updated the question due to the issue being specifically for a dynamic component
Currently, I have a custom VisualForce page used to fill out a new Opportunity. Everything works as intended except for a certain scenario.
The issue is when you select save when all the required fields aren't populated. When you choose to save and not all of the fields are populated, some of the fields are retained (specifically lookup fields) and others (date/time picklists and text boxes) are not retained after the page is refreshed due to a page error. Please note: the values are being put out by a dynamic component.
I understand partially why this happens (some values are not stored in the server and certain ones are not) but, I do not know exactly how to work-around the issue. I have come up with a few decent attempts but I haven't had any success.
Has anyone found a way to work-around this issue?
Here is some code to better understand and I figure I will get asked to share the code anyway.
Controller Code
public with sharing class ExampleController
{
private ApexPages.StandardController InheritedStandardController { get; set; }
public Component.Apex.PageBlockSection DynamicSection { get { return this.CreateDynamicSection(); } }
public Opportunity CurrentOpportunity { get; set; }
public ExampleController(ApexPages.StandardController InheritedStandardController)
{
this.InheritedStandardController = InheritedStandardController;
this.CurrentOpportunity = (Opportunity)InheritedStandardController.getRecord();
}
private Component.Apex.PageBlockSection CreateDynamicSection()
{
Component.Apex.PageBlockSection InternalDynamicSection = new Component.Apex.PageBlockSection();
InternalDynamicSection.expressions.value= '{!Opportunity}';
for(Schema.FieldSetMember Field : Schema.SObjectType.Contact.fieldSets.getMap().get('OpportunityFields').getFields())
{
Component.Apex.Column OpportunityColumn = new Component.Apex.Column();
OpportunityColumn.Facets.Header = new Component.Apex.OutputText(value = this.FieldLabelCorrection(Field.getLabel()));
OpportunityColumn.expressions.value = '{!Opportunity.' + Field.getFieldPath() + '}';
InternalDynamicSection.childComponents.add(OpportunityColumn);
}
return InternalDynamicSection;
}
public PageReference save()
{
this.OpportunityName = this.CurrentOpportunity.Name;
if(this.OpportunitySavedProperly() == false)
return new PageReference( '/apex/EditNewPage');
PageReference CorrectRedirectionPage = new PageReference( '/' + this.CurrentOpportunity.Id);
CorrectRedirectionPage.setRedirect(true);
return CorrectRedirectionPage;
}
private Boolean OpportunitySavedProperly()
{
try
{
Utility.UpsertWithoutSahring(this.CurrentOpportunity);
return true;
}
catch(Exception ExceptionWasThrown)
{
ApexPages.Message FailureMessage = new ApexPages.Message(ApexPages.Severity.FATAL, ExceptionWasThrown.getDmlMessage(0)) ;
ApexPages.addMessage(FailureMessage);
return false;
}
}
}
public without sharing class Utility
{
public static void UpsertWithoutSahring(Opportunity SomeOpportunity)
{
try
{
UPSERT SomeOpportunity;
}
cacth(Exception DMLFailure){ throw DMLFailure; }
}
}
VisualForce Page
<apex:page tabStyle="Opportunity" standardController="Opportunity" extensions="ExampleController">
<apex:pageBlock title="Opportunity Edit" tabStyle="Opportunity" id="OpportunityInfo">
<apex:pageBlockButtons>
<apex:commandButton action="{save}" value="Save"/>
</apex:pageBlockButtons>
<apex:pagemessages />
<apex:dynamicComponent componentValue="{!DynamicSection}"/>
</apex:pageBlock>
</apex:page>
Solutions I Have Tried
The first thing I tried was changing the PageReference return null like so:
public PageReference save()
{
if(this.OpportunitySaved() == false)
return null;
PageReference CorrectRedirectionPage = new PageReference( '/' + this.CurrentOpportunity.Id);
CorrectRedirectionPage.setRedirect(true);
return CorrectRedirectionPage;
}
But it did not work that way.
I tried using methods with apex:params
but was unsuccessful and from the input that Matt Lacey gave, that would not bear the fruit I was looking for.
I also tried to see if I could save the information somewhere prior to a save. So I had to alter my code like the following:
Apex Code
public Opportunity CloningOpportunity { get; set; }
public PageReference RestoreFromClone()
{
if(this.CloningOpportunity != null)
{
this.CurrentOpportunity.Name = this.CloningOpportunity.Name;
this.CloningOpportunity = null;
}
return null;
}
public PageReference CloneCurrentOpportunity()
{
this.CloningOpportunity = this.CurrentOpportunity.clone(false, true, false, false);
return null;
}
Added in VisualForce
<apex:page tabStyle="Opportunity" standardController="Opportunity" extensions="ExampleController" action="{!RestoreFromClone}">
<apex:actionFunction name="SpecialtySave" action="{!save}"/>
<apex:actionFunction name="CloneInCaseOfCancel" action="{!CloneCurrentOpportunity}" immediate="true"/>
....
<apex:commandButton action="{CloneAndSave}" value="Save"/>
<script>
function CloneAndSave()
{
CloneInCaseOfCancel();
SpecialtySave();
}
</script>
....
What I was expecting is, the CloneInCaseOfFailure
method to clone the Opportunity and stick it to the view state (hence why I chose that function to be immediate), the if there was a failure on save, it would hit the RestoreFromClone
method and restore the current opportunity with the clone.
Problem is, despite everything, the clone still remains null. I've tried making it static and it still doesn't stick to the view state.
Hopefully, this will help find a solution, since the only other way to resolve this is by moving out of the dynamic component entirely (which I do not want to do).
Apologies for not posting that this was in a dynamic component sooner. This may have clarified a few things.