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
kyle.tkyle.t 

VF Mass Edit - Update only Changed Records

I am trying to create a Mass Edit page where our reps can see certain fields on all of the opportunities they are involved in.  I have the page rendered with all of the records and am attempting to implement a save button that will only update those records which have actually been changed.  Currently, using even the standard controller save functionality, ALL records are modified, but we don't want it to look like a rep changed ALL his records when, in fact, only a few records may have been updated. 

 

Here is what I have right now, but opportunityList is reflecting no changes, so nothing gets updated:

 

public PageReference save() {
	List<Opportunity> updateList = new List<Opportunity>(); //to capture the opportunities that need to be updated
	for (Integer i=0; i < opportunityList.size();i++){ //loop through the opportunities and if anything has been changed, we will update it.
		if(opportunityList.get(i).opp <> originalOpportunityList.get(i).opp){
			updateList.add(opportunityList.get(i).opp);
		}
	}
	update updateList;
	originalOpportunityList = opportunityList;
	return null;
}

 

I belive I need to access the current page values and do some sort of comparison, but I am unsure exactly how to do that.  Any help would be greatly appreciated.

 

Thank you!

 

Best Answer chosen by Admin (Salesforce Developers) 
kyle.tkyle.t

I was able to finally figure this out.  the problem appears to have been that when I created a list of "original opportunities" which was actually a list wrapper objects, the Ids of the opportunites was mantained, so if the opportunity changed on the VF page it also changed in the "Original Opportunities" list.  In order to remedy that I had to separate the two lists.  What I did was loop through my initial list and create clones (without preserving the IDs) and added them to a separate list or wrapper objects.  Once that was done, I had the ability to compare the original version of an opportunity to the new version of the opportunity to see if anything changed.  If somethinge changed then I added it to the "update list" and updated it.

 

so in case anybody needs to know how to do this, here is what I did.  (This code is still in dev and has plenty to be cleaned up, but take it for what it is worth. 

public with sharing class opportunityWrapper {

    //Our collection of the class/wrapper objects oOpportunity 
    public List<oOpportunity> opportunityList {get; set;}
    public List<oOpportunity> originalOpportunityList {get; set;}
    public Transient Date updateDate {get; set;}
        
    //This method uses a SOQL query to return a List of Opportunities
    public List<oOpportunity> getOpportunities(){
        if(opportunityList == null){            
            opportunityList = new List<oOpportunity>();
            String UserName = UserInfo.getName(); 
            String UserID = UserInfo.getUserId();                
            ID recTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('**OPEN - New Business').getRecordTypeId();
            
            for(Opportunity o : [select Account.Name, Name, Net_Gain__c, StageName, Probability, CloseDate from Opportunity where (SalesManager__c=:UserName OR AcctManager__c=:UserName OR OwnerId=:UserID ) AND RecordTypeId=:recTypeID ]){
                /* As each opportunity is processed we create a new oOpportunity object and add it to the opportunityList */
                opportunityList.add(new oOpportunity(o));
            }
            
            if(originalOpportunityList==null){
            	originalOpportunityList = new List<oOpportunity>();
            }
            
            for(oOpportunity oOpp : opportunityList){
            	oOpportunity o1 =new oOpportunity(oOpp.opp.clone(true));
            	system.debug('o1 is: ' + o1);
            	o1.selected = oOpp.selected;
            	originalOpportunityList.add(o1);
            }                    
            return opportunityList;
        }    
        return opportunityList;
    }
     
    public PageReference save() {
        List<Opportunity> updateList = new List<Opportunity>(); //to capture the opportunities that need to be updated
        List<oOpportunity> oOppList = getOpportunities(); //get all of the current opportunities
        for(Integer i=0;i<oOppList.size();i++){        	
        	if(oOppList[i].opp <> originalOpportunityList[i].opp){
        		updateList.add(oOppList[i].opp);
        	}
        }
        
        update updateList;
        PageReference pageRef = ApexPages.currentPage();
        pageRef.setRedirect(true);
        return pageRef;
    }
    
    /* This is our wrapper/container class. A container class is a class, a data 
    structure, or an abstract data type whose instances are collections of other 
    objects. In this example a wrapper class contains both the standard salesforce 
    object Opportunity and a Boolean value */
    public class oOpportunity{
        public Opportunity opp {get; set;}
        public Boolean selected {get; set;}
                
        /*This is the contructor method. When we create a new oOpportunity object we pass an 
        Opportunity that is set to the opp property. We also set the selected value to false*/
        public oOpportunity(Opportunity o){
            opp = o;
            selected = false;       
        }
    }
}

 

 

Also note that this code uses the setRedirect(true) to ensure that the page reloads after save so that the originalList gets re-written.  without it, you can only call the "Save" fuction once.

 

Hopefully this helps someone

 

 

 

 

All Answers

kyle.tkyle.t

Ok, Updating my own post because I think I have made progress.  I have a wrapper class implemented so I simply added a variable isChanged to the wrapper class, and I believe that I can then put a method in the wrapper class that will update the value to true as such:

 

 

public class oOpportunity{
public Opportunity opp {get; set;}
public Boolean selected {get; set;}
public Boolean isChanged {get; set;}

public PageReference setIsChanged(){
isChanged=true;
return null;
}
public oOpportunity(Opportunity o){
opp = o;
selected = false;
isChanged = false;
}
}

 

 

Assuming I can actually do that, I am thinking I can update this variable using an actionRegion and actionSupport and leveraging "onchage" to call the method setIsChanged.  I can't seem to get it working.  Here is what I have now... where am i going wrong?

 

 

<apex:column headerValue="Opportunity Name">
<apex:actionRegion >
<apex:inputText value="{!Opptys.opp.Name}" />
<apex:actionSupport event="onchange" action="{!Opptys.setIsChanged}" reRender="opp_table"/>
</apex:actionRegion>
</apex:column>

 Thank you.

 

kyle.tkyle.t

I was able to finally figure this out.  the problem appears to have been that when I created a list of "original opportunities" which was actually a list wrapper objects, the Ids of the opportunites was mantained, so if the opportunity changed on the VF page it also changed in the "Original Opportunities" list.  In order to remedy that I had to separate the two lists.  What I did was loop through my initial list and create clones (without preserving the IDs) and added them to a separate list or wrapper objects.  Once that was done, I had the ability to compare the original version of an opportunity to the new version of the opportunity to see if anything changed.  If somethinge changed then I added it to the "update list" and updated it.

 

so in case anybody needs to know how to do this, here is what I did.  (This code is still in dev and has plenty to be cleaned up, but take it for what it is worth. 

public with sharing class opportunityWrapper {

    //Our collection of the class/wrapper objects oOpportunity 
    public List<oOpportunity> opportunityList {get; set;}
    public List<oOpportunity> originalOpportunityList {get; set;}
    public Transient Date updateDate {get; set;}
        
    //This method uses a SOQL query to return a List of Opportunities
    public List<oOpportunity> getOpportunities(){
        if(opportunityList == null){            
            opportunityList = new List<oOpportunity>();
            String UserName = UserInfo.getName(); 
            String UserID = UserInfo.getUserId();                
            ID recTypeId = Schema.SObjectType.Opportunity.getRecordTypeInfosByName().get('**OPEN - New Business').getRecordTypeId();
            
            for(Opportunity o : [select Account.Name, Name, Net_Gain__c, StageName, Probability, CloseDate from Opportunity where (SalesManager__c=:UserName OR AcctManager__c=:UserName OR OwnerId=:UserID ) AND RecordTypeId=:recTypeID ]){
                /* As each opportunity is processed we create a new oOpportunity object and add it to the opportunityList */
                opportunityList.add(new oOpportunity(o));
            }
            
            if(originalOpportunityList==null){
            	originalOpportunityList = new List<oOpportunity>();
            }
            
            for(oOpportunity oOpp : opportunityList){
            	oOpportunity o1 =new oOpportunity(oOpp.opp.clone(true));
            	system.debug('o1 is: ' + o1);
            	o1.selected = oOpp.selected;
            	originalOpportunityList.add(o1);
            }                    
            return opportunityList;
        }    
        return opportunityList;
    }
     
    public PageReference save() {
        List<Opportunity> updateList = new List<Opportunity>(); //to capture the opportunities that need to be updated
        List<oOpportunity> oOppList = getOpportunities(); //get all of the current opportunities
        for(Integer i=0;i<oOppList.size();i++){        	
        	if(oOppList[i].opp <> originalOpportunityList[i].opp){
        		updateList.add(oOppList[i].opp);
        	}
        }
        
        update updateList;
        PageReference pageRef = ApexPages.currentPage();
        pageRef.setRedirect(true);
        return pageRef;
    }
    
    /* This is our wrapper/container class. A container class is a class, a data 
    structure, or an abstract data type whose instances are collections of other 
    objects. In this example a wrapper class contains both the standard salesforce 
    object Opportunity and a Boolean value */
    public class oOpportunity{
        public Opportunity opp {get; set;}
        public Boolean selected {get; set;}
                
        /*This is the contructor method. When we create a new oOpportunity object we pass an 
        Opportunity that is set to the opp property. We also set the selected value to false*/
        public oOpportunity(Opportunity o){
            opp = o;
            selected = false;       
        }
    }
}

 

 

Also note that this code uses the setRedirect(true) to ensure that the page reloads after save so that the originalList gets re-written.  without it, you can only call the "Save" fuction once.

 

Hopefully this helps someone

 

 

 

 

This was selected as the best answer
KVaishnaKVaishna

Kyle,

 

This is nice solution. Thanks for it. 

 

However I am facing one issue with Inline editing. 

 

If I inline edit any field on VF and directly click on save button without clicking anywhere on the page, I get same value in oOppList[i].opp and originalOpportunityList[i].opp. so my updatelist would not contain any record to be updated.

 

But if I inline edit any field then click anywhere on the page (which will show the value in orange color and give me option to revoke change), and then click on save, I am getting difference in oOppList[i].opp and originalOpportunityList[i].opp with changed records. so my updateList would have modified records.

 

Did you face this issue? Do you know the reason for this behavior?

 

Thanks again for nice solution..

-Kunjan

knthornt1knthornt1

Hi Kunjan,

  I actually don't even have this code working any more as the functionality it was driving was no longer needed. I am wondering if your problem may be browser based. I know that IE has some funkyness in it and making updates may act differently than Firefox. 

 

Unfortunately since I don't have the code in use, i can't test out the problem you are seeing.

 

Good luck and sorry for not being able to be overly helpful.

KVaishnaKVaishna

Hi Kyle,

 

Thanks for your response. Sorry to late response.

 

I could figure this out.

 

Thanks again for the nice solution..

 

-Kunjan