Monday, March 19, 2012

Salesforce "Save and New" method for Controller Extension with custom sObject

A client recently wanted to add a "Save and New" command button to a Visualforce page that was using a controller extension overriding the new button. The users should be able to save the current sObject that was being created and then transition straight to adding another instance.

Creating a custom save method in Apex wasn't difficult as I could just keep a reference to the StandardController and then call save on that. However, creating a PageReference that would create the required StandardController was a bit more difficult.

My first attempt was more or less as follows. Note that this doesn't work in practice.

public with sharing class CustomExtensionController {
    
    Foo__c foo;
    ApexPages.StandardController sController;
    
    public CustomExtensionController (ApexPages.StandardController controller) {
        sController = controller;
        foo = (Opportunity)controller.getRecord();
    }
    
    public PageReference saveAndNew() {
        
        // Custom Save code here...
        
        PageReference pr = sController.save();

        return (new ApexPages.StandardController(new Foo__c())).edit();
    }
}

The results in the Exception:

Visualforce Error java.lang.UnsupportedOperationException: You cannot call edit() on a null object

It seems odd that there isn't a new() method on StandardController for such a scenario. Instead the PageReference can be built up manually using the schema.

public with sharing class CustomExtensionController {
    
    private Foo__c foo;
    private ApexPages.StandardController sController;
    private String queryString;
    
    public CustomExtensionController (ApexPages.StandardController controller) {
        sController = controller;
        foo = (Opportunity)controller.getRecord();

        // Keep track of any inbound query string parameters so they can be passed along when creating a new record
        List pageUrl = ApexPages.currentPage().getUrl().split('\\?');
        queryString = pageUrl[1];
    }
    
    public PageReference saveAndNew() {
        
        
        try {
            // Save the current sObject
            sController.save();

            // Get the Meta Data for Foo__c
            Schema.DescribeSObjectResult describeResult = sController.getRecord().getSObjectType().getDescribe();
            // Create PageReference for creating a new sObject and add any inbound query string parameters.
            PageReference pr = new PageReference('/' + describeResult.getKeyPrefix() + '/e?' + queryString);
            // Don't redirect with the viewstate of the current record.
            pr.setRedirect(true);
            return pr;
        } catch(Exception e) {
            // Don't redirect if something goes wrong. May be a validation or trigger issue on save.
            ApexPages.addMessages(e);
            return null;
        }
    }
}

See also:

3 comments:

  1. Hi!....Thanks for this!....I was trying to find a way to retain the save functionally in the controller :)....Thanks to your blog...I did it :)

    ReplyDelete
  2. Hi
    I have one requirement,
    Actually using below code i save object record in database dynamically.
    Schema.SObjectType targetType = Schema.getGlobalDescribe().get(strFieldName);
    SObject myObj = targetType.newSObject();
    insert myObj;

    Note:using above code related object record only created.ButFields information is not saved.Here Fields add visualforce page Dynamically

    but I gave some fields information here but those fields information is not saved in this record
    How to save fields information also related object record Dynamically?

    help me...............

    ReplyDelete
    Replies
    1. Try using the put method on the sObjects to set the field values. See http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_sobject.htm#apex_System_SObject_put

      Delete