+ Start a Discussion
Bob DeRosierBob DeRosier 

Display and ViewState disagree

I have VF page in which some of the records as displayed on my VF page and the View State disagree.  Not all, just some and only for a couple fields.  Is that normal or expected ? 

If not expected behavior, how do I report it or resolve it ?  I only have standard support, so I got referred back here in my attempts to report it.
 
Ashish_Sharma_DEVSFDCAshish_Sharma_DEVSFDC
Hi Bob DeRosier,

What means you are using to display records on vf page .

1. Is it through normal apex mothods.
2. Are you using javascript remoting.

Please paste your code here .

 
Bob DeRosierBob DeRosier
normal apex the problem becomes apparent on some records after hitting the "Save Only" button two or more time. VF page:
Ashish_Sharma_DEVSFDCAshish_Sharma_DEVSFDC
Hi Bob,

Please paste your vf page and apex class code.

Ashish
ashish.sharma.devsfdc@gmail.com
Bob DeRosierBob DeRosier
it was in the email I sent - it must have been stripped out by something along the way.  Here it is

VF page
<apex:page standardController="Event__c" tabStyle="Event__c" extensions="EventActivities_Controller" sidebar="false" title="Event Fundraising"> <apex:sectionHeader title="Event Activities" subtitle="{!event.Name}"/> <apex:form > <apex:pageBlock > <apex:pageBlockButtons > <apex:actionStatus id="statusSave"> <apex:facet name="stop"> <apex:commandButton value="Save Only" action="{!justsave}" rerender="dummy" status="statusSave"/> </apex:facet> <apex:facet name="start"> <apex:outputPanel > <c:SpinningWheel top="200" text="Saving..."/> <apex:commandButton value="Saving..." status="statusSave" disabled="true"/> </apex:outputPanel> </apex:facet> </apex:actionStatus> <apex:actionStatus id="statusSaveProcess"> <apex:facet name="stop"> <apex:commandButton value="Save & Process" action="{!processandsave}" rerender="dummy,acts" status="statusSaveProcess" rendered="{!ISPICKVAL($User.UserType, 'Standard')}"/> </apex:facet> <apex:facet name="start"> <apex:outputPanel > <c:SpinningWheel top="200" text="Saving & Processing..."/> <apex:commandButton value="Saving & Processing..." status="statusSaveProcess" disabled="true"/> </apex:outputPanel> </apex:facet> </apex:actionStatus> <apex:actionStatus id="statusSaveClose"> <apex:facet name="stop"> <apex:commandButton value="Save & Close" action="{!saveandclose}" rerender="dummy" status="statusSaveClose" /> </apex:facet> <apex:facet name="start"> <apex:outputPanel > <c:SpinningWheel top="200" text="Saving & Closing..."/> <apex:commandButton value="Saving & Closing..." status="statusSaveClose" disabled="true"/> </apex:outputPanel> </apex:facet> </apex:actionStatus> <apex:commandButton value="Cancel" action="{!cancelonly}" immediate="true"/> </apex:pageBlockButtons> <apex:pageBlockSection title="Defaults Values" columns="1"> <apex:selectRadio label="Type" value="{!defaultType}" layout="lineDirection" required="true"> <apex:selectOptions value="{!items}"/> </apex:selectRadio> <apex:inputField label="Fund" value="{!defaultActivity.Fund__c}" required="true"> <apex:actionSupport event="onchange" status="status" action="{!changeDefaultFunds}" reRender="acts,stats" /> </apex:inputField> <apex:inputField label="Register For" value="{!defaultActivity.Register_for_Event__c}"> <apex:actionSupport event="onchange" status="status" action="{!changeDefaultEvents}" reRender="acts" /> </apex:inputField> </apex:pageBlockSection> <apex:outputPanel id="stats"> <apex:pageMessages /> <apex:pageBlockSection title="Enter asks (distributions) & donations (contributions)" columns="2"> <apex:outputText label="Total Distributions" value="{!sumDistribution}" /> <apex:outputText label="Total Contributions" value="{!sumContribution}" /> </apex:pageBlockSection> </apex:outputPanel> <apex:pageBlockSection id="acts" columns="1"> <pbe:PageBlockTableEnhancerADV targetPbTableIds="activityList" paginate="true" defaultPageSize="100" pageSizeOptions="200,500"/> <apex:pageBlockTable id="activityList" value="{!eventActivities}" var="a"> <apex:column headerValue="Contact" value="{!a.Contact__c}" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"/> <apex:column headerValue="Fund" value="{!a.Fund__c}" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"/> <apex:column headerValue="Distribution/Ask (NEGATIVE Amount)" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:inputField value="{!a.Distribution__c}" style="width: 50px" rendered="{!(a.Status__c == 'Created')}"> <apex:actionSupport event="onchange" status="status" action="{!recalc}" reRender="stats" /> </apex:inputField> <apex:outputField value="{!a.Payment__c}" rendered="{!(a.Status__c != 'Created')}"/> </apex:column> <apex:column headerValue="Contribution/Donation" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:inputField value="{!a.Contribution__c}" style="width: 50px" rendered="{!(a.Status__c == 'Created')}"> <apex:actionSupport event="onchange" status="status" action="{!recalc}" reRender="stats" /> </apex:inputField> <apex:outputField value="{!a.Opportunity__c}" rendered="{!(a.Status__c != 'Created')}"/> </apex:column> <apex:column headerValue="Status" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:inputField value="{!a.Status__c}" rendered="{!(a.Status__c == 'Created')}"/> <apex:outputField value="{!a.Status__c}" rendered="{!(a.Status__c != 'Created')}"/> </apex:column> <apex:column headerValue="Register?" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:inputField value="{!a.Register__c}" style="width: 30px" rendered="{!(a.Status__c == 'Created')}"/> <apex:outputField value="{!a.Register__c}" style="width: 30px" rendered="{!(a.Status__c != 'Created')}"/> </apex:column> <apex:column headerValue="Register for" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:inputField value="{!a.Register_for_Event__c}" rendered="{!(a.Status__c == 'Created')}" required="{!OR(AND((a.Distribution__c != null),(a.Distribution__c < 0)),a.Register__c)}"/> <apex:outputField value="{!a.Register_for_Event__c}" rendered="{!(a.Status__c != 'Created')}"/> </apex:column> <apex:column style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:outputLink value="/apex/register?eventId={!a.Register_for_Event__c}&contactId={!a.Contact__c}" target="_blank" rendered="{!AND(ISPICKVAL($User.UserType, 'Standard'),(a.Register_for_Event__c != null))}">Create New Registration</apex:outputLink> </apex:column> <apex:column headerValue="Deposit Amount and other Notes" style="{!IF(a.Status__c != 'Created', 'background-color:whitesmoke', '')}"> <apex:inputField value="{!a.Notes__c}" style="width: 200px" rendered="{!(a.Status__c == 'Created')}"/> <apex:outputField value="{!a.Notes__c}" rendered="{!(a.Status__c != 'Created')}"/> </apex:column> </apex:pageBlockTable> <div style="position: relative;"> <apex:outputpanel > <apex:actionstatus id="status"> <apex:facet name="start"> <c:SpinningWheel top="200" text="Loading..."/> </apex:facet> </apex:actionstatus> </apex:outputpanel> </div> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>


Controller:
public class EventActivities_Controller {
    
    private Id eventId;
    public Double sumDistribution {get;set;}
    public Double sumContribution {get;set;}
    public String defaultType {get;set;}
    public List<SelectOption> getItems() {
        List<SelectOption> items = new List<SelectOption>();
        items.add(new SelectOption('Angel Fund','Angel Fund')); 
        items.add(new SelectOption('Scholarship Fund','Scholarship Fund')); 
        items.add(new SelectOption('Team Fund','Team Fund'));
        items.add(new SelectOption('Other','Other'));
        return items; 
    }

    public Event_Activity__c defaultActivity {get;set;}
    public List<Event_Activity__c> eventActivities {get;set;}
    public List<Event_Activity__c> getEventActivities () {
        List<Event_Activity__c> results = new List<Event_Activity__c>(); 
        Map<Id, Event_Activity__c> act = new Map<Id, Event_Activity__c>();
        if(eventId != null && defaultActivity.Fund__c != null) {
            // get event registrations
            List<Registration__c> regs = [SELECT Id, Contact__c, Contact__r.Name, Contact__r.AccountId, Status__c FROM Registration__c WHERE
                                                Event__c = :eventId AND
                                                (Status__c = 'Registered' OR Status__c = 'Checked In') ORDER BY Contact__r.Name];
            // get existing activities
            List<Event_Activity__c> currAct = [SELECT Name, Contact__c, Contact__r.Name, Contact__r.AccountId, Status__c, Register_for_Event__c, Register__c, Id, Fund__c, Event__c, Distribution__c, Contribution__c, Payment__c, Opportunity__c, Notes__c FROM Event_Activity__c WHERE Event__c = :eventId AND Fund__c = :defaultActivity.Fund__c];
            for(Event_Activity__c a : currAct)
                    act.put(a.Contact__c, a);
            //results.addAll(currAct);
        
                // add missing regs to activities
            for (Registration__c r : regs) {
                if(!act.containsKey(r.Contact__c))
                    act.put(r.Contact__c, new Event_Activity__c(
                                    Contact__c = r.Contact__c,
                                    Event__c = eventId,
                                    Fund__c = defaultActivity.Fund__c,
                                    Status__c = 'Created',
                                    Register_for_Event__c = defaultActivity.Register_for_Event__c));
            }
            //results.addAll(act);
            // add map values to resuts
            for(Event_Activity__c a : act.values())
                    results.add(a);
        }

        eventActivities = results;
        return results;         
    }

    public Event__c event {get;set;}
        
    public EventActivities_Controller(ApexPages.StandardController controller) {
        eventId = System.currentPageReference().getParameters().get('Id');

        if(eventId != null)
            event = [SELECT Id, Name, Region__c, Region__r.Event_Opportunity__c, PO_Number__c, CurrencyIsoCode, Region__r.CurrencyIsoCode FROM Event__c WHERE Id = :eventId];
        else
            event = null;
        
        defaultActivity = new Event_Activity__c();
        defaultType = 'Angel Fund';
                //ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Info, 'eventActivities.size()=' + eventActivities.size())); 
    }

    public PageReference changeDefaultEvents() {
        // set defaults
        for(Event_Activity__c a : eventActivities) {
                if(a.Status__c == 'Created')
                        a.Register_for_Event__c = (a.Register_for_Event__c == null ? defaultActivity.Register_for_Event__c : a.Register_for_Event__c);                          
        }
        return null;
    }

    public PageReference changeDefaultFunds() {
        // get data
        eventActivities = getEventActivities();
        recalc();       
        return null;
    }

    public PageReference recalc() {
        sumDistribution = 0.0;
        sumContribution = 0.0;
        for(Event_Activity__c a : eventActivities) {
                //ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Info, 'a.Distribution__c=' + a.Distribution__c + ', a.Contribution__c=' + a.Contribution__c));              
                sumDistribution += (a.Distribution__c != null ? a.Distribution__c : 0.0);
                sumContribution += (a.Contribution__c != null ? a.Contribution__c : 0.0);
        }
        return null;
    }

    private void deleteEmptyRecords() {
        Integer counter = 0;
        Integer[] deletes = new Integer[]{};
        // check for empty records
        for(Event_Activity__c a : eventActivities) {
            if(a.Contribution__c == null && a.Distribution__c == null && a.Register__c == false && a.Notes__c == null)
                    deletes.add(counter);
            counter += 1;
        }
        // delete empty records
        counter = 0;
        for(Integer i : deletes) {
            eventActivities.remove(i-counter);
            counter += 1;
        }
    }
        
    private void upsertEventActivities() {
        // clean up activities
        for(Event_Activity__c a : eventActivities) {
        if(a.Contribution__c != null && a.Distribution__c == null && a.Register__c == false)
                a.Register_for_Event__c = null;
        }
                            
        // update Activities
        try {
            upsert eventActivities;
        } catch(Exception ex) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Error, 'ACTIVITY ERROR: ' + ex.getMessage())); 
        }                  
    }
        
    private void processData() {
        // create empty lists for donations and transfers
        List<Opportunity> myDonations = new List<Opportunity>();
        List<npe01__OppPayment__c> myTransfers = new List<npe01__OppPayment__c>();
        
        // get recordTypeIds
        Id transferId = [Select Id, Name FROM RecordType WHERE Name = 'Transfer'].Id;
        Id donationId = [Select Id, Name FROM RecordType WHERE Name = 'Donation'].Id;
        
        // loop thru activities
        for(Event_Activity__c a : eventActivities) {
            if(a.Status__c == 'Created'){
                Boolean isProcessed = false;
                // add transfer if exists
                if(a.Distribution__c < 0 && a.Payment__c == null) {
                    myTransfers.add(new npe01__OppPayment__c(
                        RecordTypeId = transferId,
                        npe01__Payment_Amount__c = a.Distribution__c,
                        CurrencyIsoCode = event.CurrencyIsoCode,
                        npe01__Payment_Method__c = 'Transfer',
                        Payment_Status__c = 'Application Submitted',
                        Description__c = a.Name,
                        // npe01__Payment_Date__c = Date.today(),
                        npe01__Opportunity__c = event.Region__r.Event_Opportunity__c,
                        Region__c = event.Region__c,
                        Contact__c = a.Contact__c,
                        Fund__c = a.Fund__c,
                        Event__c = a.Event__c));
                    isProcessed = true;
                }
                    
                // add donation if exists
                if(a.Contribution__c > 0 && a.Opportunity__c == null) {
                    myDonations.add(new Opportunity(
                        RecordTypeId = donationId,
                        Type = defaultType,
                        Fund__c = a.Fund__c,
                        Region__c = event.Region__c,
                        StageName = 'Pledged',
                        CloseDate = Date.today(),
                        Amount = a.Contribution__c,
                        CurrencyIsoCode = event.CurrencyIsoCode,
                        Name = a.Contact__r.Name + ' - Donation ' + Date.today().format(),
                        AccountId = a.Contact__r.AccountId,
                        Description = a.Name,
                        Event__c = a.Event__c,
                        PO_Number__c = defaultType + ' ' + event.PO_Number__c));
                    isProcessed = true;
                }                    
                // mark record processed
                if(isProcessed)
                    a.Status__c = 'Processed';
            }
        }
    
        // upsert donations and transfers
        try {
            if(myDonations.size() > 0)
                upsert myDonations;
        } catch(Exception ex) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Error, 'DONATION ERROR: ' + ex.getMessage())); 
        }
                        
        // upsert donations and transfers
        try {
            if(myTransfers.size() > 0)
                upsert myTransfers;
        } catch(Exception ex) {
            ApexPages.addmessage(new ApexPages.message(ApexPages.severity.Error, 'TRANSFER ERROR: ' + ex.getMessage())); 
        }
        
        // update activities with Ids
        for(npe01__OppPayment__c t : myTransfers) {
            if(t.Id != null) {
                for(Event_Activity__c a : eventActivities) {
                    if(t.Description__c == a.Name)
                        a.Payment__c = t.Id;
                }
            }
        }
        for(Opportunity o : myDonations) {
            if(o.Id != null) {
                for(Event_Activity__c a : eventActivities) {
                    if(o.Description == a.Name)
                        a.Opportunity__c = o.Id;
                    }
            }
        }
        // upsertEventActivities();          
    }
        
    public PageReference justsave() {
                    
        saveandrefresh();
        return null;
    }
    
    private void saveandrefresh() {
        
        // delete empty records
        deleteEmptyRecords();
        
        // save records
        upsertEventActivities();

        // refresh data
        eventActivities = getEventActivities();
        recalc();               
    }

    public PageReference saveandclose() {
        
        PageReference nextPage = null;
        if(event != null)
            nextPage = (new ApexPages.StandardController(event)).view();
            
        // delete empty records
        deleteEmptyRecords();
        
        // save records
        upsertEventActivities();

        return nextPage;
    }

    public PageReference cancelonly() {
        
        PageReference nextPage = null;
        if(event != null)
            nextPage = (new ApexPages.StandardController(event)).view();
            
        return nextPage;
    }

    public PageReference processandsave() {
        
        // save existing records
        saveandrefresh();
                
        // process records
        processData();
        
        // save updated records 
        saveandrefresh();

        return null;
    }

    public String dummyFunction(){
        // Dummy statements to pass testing ... workaround for now for testing class
        String dummy = 'temp';
        dummy = 'temp';
        dummy = 'temp';      
        return dummy;
    }   
}

 
Ravi NarayananRavi Narayanan
If its just a ready only page, you can use transient keyword. if not u can use js remoting + angualrJS for displaying records . this will solve ur pbm
Ashish_Sharma_DEVSFDCAshish_Sharma_DEVSFDC
Hi ,
Agree with ravi, and you can make your properties transient which are read only on page.
such as
public transient Event__c event {get;set;}

Let us know if it helps you.
 
Bob DeRosierBob DeRosier
It is an interactive page.
Ashish_Sharma_DEVSFDCAshish_Sharma_DEVSFDC
Hi Bob,
Then use Javascript remoting.
Please go through below link.
https://developer.salesforce.com/page/An_Introduction_to_Visualforce_View_State

Let us know if it helps you.
Bob DeRosierBob DeRosier
The problem is that only part of the data is out of synch.  Imagine a sorted list of text values from 1-30 and items 4 and 21 were switched in ViewState, but displayed correctly on the screen (ie my code didn't switch them). Hitting the Save button again will cause the view state and display to agree- but with the incorrect values.Since the form is for data input, I don't think it makes sense to use 'public transient".