Saturday 19 March 2011

Persisting List Edits in Visualforce

A topic that appears semi-regularly on the Visualforce discussion boards is editing the contents of a list of sobjects and how to persist that information into the Salesforce database.  There's often confusion around how to submit the changes back to the Visualforce controller.

This is a good example of how easy it is to capture complex form data from a Visualforce page into the controller.  Essentially as long as the list is a controller property that is part of the viewstate, there's nothing that has to be done to submit the changes back to the page and very little to save the changes back to the database.

Here's the output of a small Visualforce page that allows basic information for an account and up to 5 associated contacts to be edited in one go.


The contacts information is stored in a list property from the controller, and output via an apex:repeat tag:

<apex:repeat value="{!contacts}" var="Contact">
   <apex:inputField value="{!Contact.FirstName}"/>
   <apex:inputField value="{!Contact.LastName}"/>
</apex:repeat>

As you can see, there's very little to this - simply iterate the list of contacts and for each element, render inputs for the first and last name.  From the controller perspective, there's also even less - the list of contacts is a property that is initialised when the controller is constructed:

// the associated contacts
   public List<Contact> contacts {get; set;}
   
   public AccountContactsListExample(ApexPages.StandardController stdCtrl)
   {
     std=stdCtrl;
     contacts=[select id, FirstName, LastName, Email from Contact where accountid=:std.getId() order by firstname asc limit 5];
    }

In terms of hooking up the page and controller, that's all there is to it.  Each input field on the page is bound to a field from a Contact sobject in the list.  Changes that are made on the page will be reflected in the cached contacts list and are then available to be processed server side.

Here's the full page, with the button to allow saving of the changes:

<apex:page standardController="Account" extensions="AccountContactsListExample">
  <apex:form >
  <apex:outputText value="{!message}" rendered="{!LEN(message)>0}"/>
   <apex:pageBlock title="Account Detail">
      <apex:pageBlockSection title="Account">
            <apex:inputField value="{!Account.Name}"/>
            <apex:inputField value="{!Account.Description}"/>
      </apex:pageBlockSection>
      <apex:pageBlockSection title="Contacts">
         <apex:repeat value="{!contacts}" var="Contact">
            <apex:inputField value="{!Contact.FirstName}"/>
            <apex:inputField value="{!Contact.LastName}"/>
         </apex:repeat>
      </apex:pageBlockSection>
  </apex:pageBlock>
   <apex:commandButton value="Save" action="{!save}"/>
  </apex:form>
</apex:page>

and here's the full controller. The save method persists the changes to the database, simply by executing an update on the list of contacts.

public class AccountContactsListExample 
{
    private ApexPages.StandardController std;
    
    public String message{get;set;}
    
    // the associated contacts
   public List<Contact> contacts {get; set;}
   
    public AccountContactsListExample(ApexPages.StandardController stdCtrl)
    {
     std=stdCtrl;
     contacts=[select id, FirstName, LastName, Email from Contact where accountid=:std.getId() order by firstname asc limit 5];
    }

    public PageReference save()
    {
     // first save the account
     std.save();
     
     // then save the contacts
     update contacts;
     
     PageReference result=ApexPages.currentPage();
     result.setRedirect(true);
     
     return result;
    }
    
}

This also demonstrates one way to allow editing of a parent (account) record and its children (contacts).

1 comment:

  1. how i can building a visualforce page to edit or update my custom object such that (student__c),
    when i put primary field value then update object that depend on this field

    ReplyDelete