[SalesForce] Save and close button not checking for required field

I want to achieve a functionality wherein i want the user to save and close and redirect to other page even if he has not entered values of required field on page.

I have used immediate property of button.

Following is the code

Apex Class:-

public class testaff 
{
    public String accId{get;set;}
    public Account account{get;set;}

    public testaff()
    {
       accId = ApexPages.currentPage().getParameters().get('Id'); 
       if(accId != null)        
        {
            this.account= [   SELECT  Name
                          FROM    Account
                          WHERE   Id = : accId ];  
        }
        else
        {
            this.account= new Account();

        }   
    }
    public pageReference save()
    {
        insert this.account;
        return null;    
    }
public pageReference saveandclose()
{
    insert this.account;

    PageReference pageRef = new PageReference('/apex/test');
    pageRef.setRedirect(true);
    return pageRef;   

}

}

Visualforce page code

<apex:page controller="testaff">
<apex:form >
<apex:actionRegion immediate="true">
<apex:pageBlock id="pbAccountDetails">
    <apex:pageBlockSection columns="1" collapsible="false">
    <apex:inputField value="{!account.Name}" required="true" />
    <apex:inputfield value="{!account.Email__c}" required="true"/>    
</apex:pageBlockSection>    
<apex:pageBlockButtons >
     <apex:commandButton action="{!save}" value="Save"/>
    <apex:commandButton action="{!saveandclose}" value="Save and Close" immediate="true"/>     
</apex:pageBlockButtons>


</apex:pageBlock>
</apex:actionRegion>
</apex:form>

</apex:page>

Error that i am facing is.. i am not able to skip validation and insert a record in database

Best Answer

In this instance you'll need to not save, but mock save as you redirect to the next page. I can think of a couple of ways you might do this. The question is, do you really need to save whilst going to the next page, or can you just make do with holding the data in memory.

Use the View State Two pages sharing the same controller will keep non-static variable state in between requests. A lot of people are annoyed by this as it adds to the page payload. Historically new VF developers have ignored the effects of putting too much stuff in the page view state causing VF page load times to be slow.

But in this instance, you can definitely take advantage of this. To show this, I'll use two pages, the first of which is yours and taken your exact controller and added two navigation methods to go back and forth between to pages. I've renamed them ViewStateStudy_page1, ViewStateStudy_page1, and ViewStateStudy_controller.

public with sharing class ViewStateStudy_controller {

...all of the rest of this is as your original controller class...
//these are two new methods
//also note the use of the static reference to the page 
//instead of relative URL

    public PageReference page2(){
    return Page.ViewStateStudy_page2;   
}
public PageReference page1(){
    return Page.ViewStateStudy_page1;   
}
}

So here, my method does absolutely nothing except tell the VF engine to go to a different page. If I go to the first page, ViewStateStudy_page1 and don't specify the id param, I get an empty Account instance (by extension) and Name field.

Initial nav to page is empty

This can be verified by a peek at the View State inspector.

View state shows an empty Account record

Now, I fill out the account name field and click Next. I've added a button that maps to the page2() method above.

<apex:commandButton action="{!page2}" value="Next"/>

As you see, it doesn't do anything except submit a post request which takes me to the next page.

Enter in my account name on page1

Once I arrive at the next page, I can still see the value typed into the first page.

enter image description here

Here the View State inspector let's you down a bit, but if I were to add a save button on page 2, I'd be in good shape.

There are a couple of things you must do and must not do to make this work.

  1. The controller must be the same for both pages.
  2. The second page must be arrived at using HTTP POST. You ensure this happens by not using PageReference.setRedirect(true). The minute you add that, you wipe the entire view state and start over.
  3. Ensure variables are not transient. Transient can be either explicitly declared in a class member, is implicit to some classes (like PageReference, for instance) and static members.
  4. Immediate=true on you button will not post data into the view state. It is usually reserved for cancel buttons and the like.

So what about option number 2 in my mock save scenario. If you had to actually stick something in the database temporarily, that wasn't validated, there are numerous options: serialize it into xml or json and stuff it into a long text field to retrieve later, create a dummy sobject (costly for object limits, but an option). These put the onus on you to manage your own state, but can be done.

To pursue some of these, take a look at the articles on developerforce on view state management that go into some more details. There was also a very well done video at Dreamforce this year on building efficient Visualforce pages that you should check out.

Finally, I've added the entire code from my example pages to a gist if you wish to take a look.

Related Topic