0

I have a few Inputfields, that are populated dynamically. The number of Inputfields changes based on the "Product Family" Picklist field the user selects. I have buttons that enable Pagination. The problem is, I want the inputfields to save the user inputs, even on Pagination, but when I paginate, the values revert back to the values when the page loaded initially. How should I make the inputfields save the user values? I'm not sure how should I approach this problem.

VF Page

<apex:form>
        <apex:actionFunction name="familyChangedJS" action="{!familyChanged}" reRender="fam1"/>
        <apex:inputField label="Product Family" value="{!prod.Product_Family__c}" onchange="familyChangedJS()"/>
    </apex:form>


<apex:form>
<apex:dataTable value="{!packageItems}" var="pkg1" id="fam">
            <apex:column>
                <apex:inputField value="{!pkg1.Quantity__c}"/>
            </apex:column>

            <apex:column>
                    <apex:outputText value="{!pkg1.Product__r.Name}"/>
            </apex:column>

            <apex:column>
                <apex:outputText value="{!pkg1.Product__r.Cost__c}"/>
            </apex:column>
        </apex:dataTable>

        <apex:inputHidden value="{!startingFrom}"/>

        <apex:panelGrid columns="4" cellpadding="2px" id="btns">

            <apex:commandButton action="{!first}" value="First" disabled="{!isFirstDisabled}"/>
            <apex:commandButton action="{!previous}" value="Previous" disabled="{!isPreviousDisabled}"/>
            <apex:commandButton action="{!next}" value="Next" disabled="{!isNextDisabled}"/>
            <apex:commandButton action="{!last}" value="Last" disabled="{!isLastDisabled}"/>
            <apex:outputText value="Page {!presentPage} of {!totalPages}"></apex:outputText>
       
 </apex:panelGrid>

</apex:form>

Apex -

public Package_Item__c[] packageItems {
        get {
            if((prod.Product_Family__c == 'Any Type') || (prod.Product_Family__c == NULL)){  
             packageItems = [SELECT Name, Product__c, Quantity__c, Cost_Per_Item__c, Product__r.Cost__c, Product__r.Name,Package__r.id  
             FROM Package_Item__c
             ORDER BY Cost_Per_Item__c ASC
             LIMIT : MAX_RECORDS_PER_PAGE
             OFFSET : startingFrom];
                
            }
            else {
                packageItems = [SELECT Name, Product__c, Quantity__c, Cost_Per_Item__c, Product__r.Cost__c, Product__r.Name,Package__r.id,Product__r.Active__c,Product__r.Product_Family__c   
                        FROM Package_Item__c
                        WHERE Product__r.Active__c = FALSE AND Product__r.Product_Family__c = :prod.Product_Family__c
                        ORDER BY Cost_Per_Item__c ASC
                        LIMIT : MAX_RECORDS_PER_PAGE
                        OFFSET : startingFrom];
                
                
            }
             for (Package_Item__c pi : packageItems) {
              if (recid != pi.Package__r.id) {pi.Quantity__c = 0;}
             }
             return packageItems;
        } set;
      }

The action methods for the buttons just have logic for evaluation the startingFrom and the isDisabled variables.

So, How should I make the inputfields save the user values?

1 Answer 1

1

This is going to sound obvious, but if you want your paginated form to remember inputs from a given page of results, you need to keep that information somewhere. In the case of Visualforce, that would be in the viewstate (i.e. in instance variables in your controller or extension).

The viewstate is limited to 15k, so if you have too many records and/or too many fields, the approach I'll be going over won't work. I can imagine using something like an SObject to store temporary record input, but using the viewstate is most natural way to do this.

The naive/simple approach to pagination is what you currently have, using LIMIT and OFFSET in an SOQL query, and provide next/previous actions. The issue is that once you go to a new "page" of records, the current records (and their input) are discarded.

There are a few ways to work around that. Probably the most natural progression for you would be to remove OFFSET and LIMIT from your SOQL. You'd execute the query once, get all of the records you could possibly work on, and then use apex to return slices of the overall results.

Example application (untested):

public Package_Item__c[] packageItems {
    get {
        // query once (when we don't have any records yet)
        if(packageItems == null || packageItems.isEmpty()){
            packageItems = <your query here>;
        }

        // slice the overall record set to get an individual "page"
        List<Package_Item__c> page = new List<Package_Item__c>();
        for(Integer i = 0; i < MAX_RECORDS_PER_PAGE && packageItems.size() < (startingFrom + i); i++){
            page.add(packageItems[startingFrom + i]);
        }

        return page;
    } set;
}

Instead of doing that manually though, you should consider using ApexPages.StandardSetController. It's typically used when you want to make a list button(done by including the recordsetvar attribute in your <apex:page> tag), but you can create an instance of that class yourself. The benefit here is that StandardSetController provides helpful things like actions for first, last, next, and previous (less work for you to implement, test, and maintain).

The idea is the similar to the previous approach.

  • Query all records once
  • Pass the list to the standardSetController
  • Set the page size
  • Use the provided action methods to show different slices of the overall record set

Example (also untested)

public ApexPages.StandardSetController paginator;
public Package_Item__c[] packageItems {
    get { return paginator.getRecords(); }
}

public MyControllerExtension(ApexPages.StandardController std){
    paginator = new ApexPages.StandardSetController(<your query for Package_Item__c here>);
    paginator.setPageSize(MAX_RECORDS_PER_PAGE);
}

// Eventually, perhaps in a save() method you define, you'll want to retrieve all records. // You can do that using the getSelected() method of StandardSetController

StandardSetController does provide a save() method of its own, however the behavior of that method has had some quirks in the past. Perhaps that was only with the "prototype object" functionality (to roll your own mass-update). It's been too long, and I've forgotten.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .