+ Start a Discussion
michaelforcemichaelforce 

Dynamic Visualforce: form being cleared out on failed save attempt

Hey folks, I'm in a new role now, so I will be coding a lot more.  Looking forward to hanging out in here more often!

 

I'm working with Dynamic Visualforce at the moment (apex:dynamicComponent) to build a simple Lead form.  It's a long story why it has to be built dyamically.  I'm extending the standard Lead controller, and leveraging the standard {!save} method.  It works great when the record saves... they are brought to the new record and all the info they entered is there... woohoo!

 

The problem is when they click save but haven't filled in one or more required fields.  The form refreshes and correctly identifies the fields they forgot to populate and notifies them as is appropriate.  BUT, all the info they had entered is cleared out!

 

Here is a small example that shows what I mean:

 

Visualforce Page:

<apex:page extensions="dynamicTestController" standardController="Lead">

    <apex:messages />

    <apex:form >
        <apex:pageBlock mode="edit">

            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!save}"/>
            </apex:pageBlockButtons>
            
            <apex:dynamicComponent componentValue="{!mySection}"/>
            
        </apex:pageBlock>
    </apex:form>
</apex:page>

 

 

Apex Controller:

public with sharing class dynamicTestController {

    public Lead theLead {get;set;}

    public dynamicTestController(ApexPages.StandardController controller) {
        theLead = (lead)controller.getRecord();
    }

    public Component.Apex.PageBlockSection getMySection() {
        
        Component.Apex.PageBlockSection section = new Component.Apex.PageBlockSection(columns=1);
        
        Component.Apex.InputField field1 = new Component.Apex.InputField();
        field1.expressions.value = '{!theLead.LastName}';
        
        Component.Apex.InputField field2 = new Component.Apex.InputField();
        field2.expressions.value = '{!theLead.Company}';
        
        Component.Apex.InputField field3 = new Component.Apex.InputField();
        field3.expressions.value = '{!theLead.Phone}';
        
        section.childComponents.add(field1);
        section.childComponents.add(field2);
        section.childComponents.add(field3);
        
        return section;
    }
}

 

 

 

You can see that when you populate LastName and Phone, but NOT Company and click save the form is cleared out... not cool!

 

I've concocted a workaround, which is to use a custom save method that returns nothing so I can avoid refreshing of the form.  I then use the apex:messages component to display any errors at the top of the page and redirect with JavaScript if there are no errors.  It works, but then errors that should be on a specific field are at the top instead and I would rather not have to rely on JS for navigation like that.

 

Any thoughts?

 

Cheers,

michaelforce

Big VBig V

The form gets cleared out because each time the <apex:dynamicComponent> is loaded it calls the function getMySection() where you are reinitializing  the contents. try this out in the controller:

 

public with sharing class dynamicTestController {

    public Lead theLead {get;set;}

 Component.Apex.InputField field1 = new Component.Apex.InputField();
 Component.Apex.InputField field2 = new Component.Apex.InputField();
Component.Apex.InputField field3 = new Component.Apex.InputField();

    public dynamicTestController(ApexPages.StandardController controller) {
        theLead = (lead)controller.getRecord();
    }

    public Component.Apex.PageBlockSection getMySection() {
        
        Component.Apex.PageBlockSection section = new Component.Apex.PageBlockSection(columns=1);
        
       
        field1.expressions.value = '{!theLead.LastName}';
        
       
        field2.expressions.value = '{!theLead.Company}';
        
        
        field3.expressions.value = '{!theLead.Phone}';
        
        section.childComponents.add(field1);
        section.childComponents.add(field2);
        section.childComponents.add(field3);
        
        return section;
    }
}

 

michaelforcemichaelforce

Hey Big V,

 

That was a good thought, it turns out though that all the Component.Apex._____ entities are "non-serializable" so they can't be made part of the view state... so can't be a class property as you have suggested (unless they have the transient keyword... but that isn't feasible in my use case).

 

So it's back to the drawing board....

 

 

sdbsdb

Hi Michael, I was wondering if you ever found a resolution to this issue? I am having a similar problem -- see my post here:

http://boards.developerforce.com/t5/Visualforce-Development/Page-View-State-not-maintained-for-dynamically-added-components/td-p/467313

 

Thanks,

sdb

michaelforcemichaelforce

sdb,

 

No, I never got an official fix for this.  My workaround is that I simply don't ever have my controller send a null PageReference to the page.  In otherwords, I wrote my own save function that returns void, and then I have my page rerender a section with my apex:messages component in it after the function runs.  If there are no messages, it will redirect to the newly created record.

 

It's not ideal... but it got the job done, because as you said, if the page refreshes fully then the values are gone... so don't let it!

 

I have subscribed to your post too, hopefully we get an answer.

TylerM.ax1133TylerM.ax1133

Hi Michael,

 

I am hoping that you can share the workaround that you are speaking of. I am working on something very simlar to your issue and I am hoping to understand how you are showing the message and then redirect if there is none.

sdbsdb

I got official verification back from Salesforce that this is working 'as designed'. However the lack of view state support for dynamic components really reduces the usefulness of a very powerful feature. Therefore I have created an enhancement request here:

 

https://success.salesforce.com/ideaView?id=08730000000kx6sAAA

 

Please vote for this idea if you are using or would like to use dynamic components!