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: