function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Patrick DixonPatrick Dixon 

How do I 'save' with a StandardSetController with extensions?

I can't figure out how to save updated records back with a StandardSetController and an extension to paginate the (filtered) set of data.  I'm obviously missing the mechanism to get the filtered data set back to the standard set controller 'save' function, but I can't figure out how to add it.

 

VF page is:

 

<apex:page standardController="Orphan__c" extensions="OrphanBulkReportsWithPagination" recordSetVar="orphans">
    <apex:form >
        <apex:sectionHeader title="Bulk {!ReportType} Reports"/>
        <apex:pageBlock mode="edit">
            <apex:pageMessages />

            <apex:pageBlockSection title="Print {!ReportType}" collapsible="false">
                <apex:inputField value="{!Orphan__c.Biodata_Report_Sent__c}"/>
            </apex:pageBlockSection>
            <apex:pageBlockSection title="Selected Orphans"  columns="1">
                <apex:pageblocktable value="{!PaginatedOrphans}" var="orphan" id="list">
                    <apex:column value="{!orphan.Name}"/>
                    <apex:column headerValue="Orphan Name">
                        <apex:outputText value="{!orphan.First_Name__c
                            & ' '
                            & orphan.Last_Name__c}"/>
                    </apex:column>
                    <apex:column value="{!orphan.Country__c}"/>
                    <apex:column value="{!orphan.IRP_Country__c}"/>
                    <apex:column headerValue="Biodata">
                        <apex:inputField value="{!orphan.Biodata_Report_Sent__c}"/>
                    </apex:column>
                </apex:pageblocktable>
            </apex:pageBlockSection>
            
            <apex:panelGrid columns="2">
                <apex:commandLink action="{!previous}">Previous</apex:commandlink>
                <apex:commandLink action="{!next}">Next</apex:commandlink>
            </apex:panelGrid>
            
            <apex:pageBlockButtons location="bottom">

                <apex:commandButton value="Save" action="{!saveOrphans}"/>
                <apex:commandButton value="Cancel" action="{!cancel}"/>
            </apex:pageBlockButtons>
        </apex:pageBlock>
    </apex:form>
</apex:page>

 

And controller extension is:-

 

public with sharing class OrphanBulkReportsWithPagination {

    Apexpages.StandardSetController controller;

    public OrphanBulkReportsWithPagination(ApexPages.StandardSetController c) {
        ReportType = ApexPages.currentPage().getParameters().get('rpt');
        Country = ApexPages.currentPage().getParameters().get('loc');
        controller = c;
    }    
    
    public ApexPages.StandardSetController orphanRecords {
        get {
            if(orphanRecords == null) {
                return new ApexPages.StandardSetController(
                         Database.getQueryLocator(
                [SELECT Id, name, First_Name__c, Last_Name__c, Country__c, IRP_Country__c, Biodata_Report_Sent__c FROM Orphan__c
                WHERE Biodata_Report_Sent__c = false
                And (Status__c = 'Available' OR Status__c = 'Sponsored')
                AND Id NOT IN (SELECT Orphan__c FROM Annual_Progress_Report__c where Sent_to_Donor__c = true)
                ]));
            }
            return orphanRecords;
        }
        private set;
    }

    public List<Orphan__c> getPaginatedOrphans() {
        return (List<Orphan__c>) orphanRecords.getRecords();
    }

}

 

Many thanks!

Best Answer chosen by Admin (Salesforce Developers) 
bob_buzzardbob_buzzard

This looks to be a cut down version of your extension controller - e.g. I can't see the code for the saveOrphans method in there.

 

That said, it looks to me that one issue you may be seeing is that you aren't saving the standard controller in the orphanRecords property, you are simply returning a new instance.  Assuming you are looking to execute the save against that controller, try the following:

 

 

 

        get {
            if(orphanRecords == null) {
                orphanRecords=new ApexPages.StandardSetController(
                         Database.getQueryLocator(
                [SELECT Id, name, First_Name__c, Last_Name__c, Country__c, IRP_Country__c, Biodata_Report_Sent__c FROM Orphan__c
                WHERE Biodata_Report_Sent__c = false
                And (Status__c = 'Available' OR Status__c = 'Sponsored')
                AND Id NOT IN (SELECT Orphan__c FROM Annual_Progress_Report__c where Sent_to_Donor__c = true)
                ]));
            }
            return orphanRecords;

 

 

All Answers

bob_buzzardbob_buzzard

This looks to be a cut down version of your extension controller - e.g. I can't see the code for the saveOrphans method in there.

 

That said, it looks to me that one issue you may be seeing is that you aren't saving the standard controller in the orphanRecords property, you are simply returning a new instance.  Assuming you are looking to execute the save against that controller, try the following:

 

 

 

        get {
            if(orphanRecords == null) {
                orphanRecords=new ApexPages.StandardSetController(
                         Database.getQueryLocator(
                [SELECT Id, name, First_Name__c, Last_Name__c, Country__c, IRP_Country__c, Biodata_Report_Sent__c FROM Orphan__c
                WHERE Biodata_Report_Sent__c = false
                And (Status__c = 'Available' OR Status__c = 'Sponsored')
                AND Id NOT IN (SELECT Orphan__c FROM Annual_Progress_Report__c where Sent_to_Donor__c = true)
                ]));
            }
            return orphanRecords;

 

 

This was selected as the best answer
Patrick DixonPatrick Dixon

Thanks once again!  That's what comes from copying other people's code ...

 

You got me on the cut-down too.  saveOrphans looks like this:-

 

    public PageReference SaveOrphans() {
        orphanRecords.save();
        PageReference pr = new PageReference('/apex//IRPBulkReports?rpt='
            + ReportType + '&loc=' + Country);
        pr.setRedirect(true);
        return pr;
   }

 

So that it returns to the page I want.

chris.wolfchris.wolf

Did you ever get this to work?  I found that if you use a StandardSetController with pagination where the page size is less then the total result size (i.e. there's more then one page), then upon calling "save", the modified values are not saved.  If the page size is less then or equal to the total result set size, then "save" works.  Just to clarify, the apex:dataTable columns are rendered with an apex:inputField, which allows in-place updating of field values to be saved.

 

I found that the following pieces are needed in the controller extension:

 

    // private member var
    transient List<sObject> pageRecords;
    transient List<sObject> origPageRecords;
public List<Opportunity> getPageRecords() { pageRecords = controller.getRecords();
origPageRecords = cloneList(pageRecords);
  return pageRecords; } public PageReference savePage() {
        List<sObject> recToSave = new List<sObject>();
        for (integer i=0; i<pageRecords.size(); i++) {
            if (pageRecords[i] != origPageRecords[i]) {
                recToSave.add(pageRecords[i]);
                system.debug('*** changed: ' + pageRecords[i] + '  orig: ' + origPageRecords[i]);
            }
        }

        system.debug('*** Num REC to SAVE: ' + recToSave.size());
        if (recToSave != null && recToSave.size() > 0)
// surround with try/catch in actual production
            update recTosave;
PageReference pr = ApexPages.currentPage(); pr.setRedirect(true); return pr; } static List<sObject> cloneList(List<sObject> orig) { List<sObject> copy = new List<sObject>(); for (sObject obj : orig) { // clone(true, false, true, true) // preserve id, not deep-copy, preserve timestamps, preserve auto-number copy.add(obj.clone(true, false, true, true)); } return copy; }

 

You call getPageRecords from your page (via the "value" attribute of dataTable or pageBlockTable, i.e. value="{pageRecords}".  ...and instead of calling "{!save}", call "{!savePage}".

 

The remaining problem is that once savePage is done, when the data table is re-rendered, you're back on page one of the results, but at least the data is being saved.    Interestingly, if you make the member vairable "pageRecords" non-transient, then it behaves just like the stock StandardSetController methods getRecords() / save() and won't save the updated values, which means, to me, that the page records buffer in the StandardSetController is being stored in the view state and perhaps masking the updated fields from the VF page.