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
aapt.devaapt.dev 

Help needed understanding controller extensions

Hi
 
I'm an advanced administrator but have absolutely no coding skills and am trying to teach myself some basic APEX and VisualForce.
I am having some difficulty understanding standard controller extensions and was hoping that someone can give me a little guidance here. I have scoured the discussion boards but have failed miserably in locating a post that I could understand so apologies in advance if this is a topic that has already been dealt with.
 
I'm trying to build a VF page that will allow users to mass update the Contacts on an Account e.g. phone numbers, flag as inactive etc.
 
My code:
 
public class accountContactList {
    public PageReference save() {
        return null;
    }

  public Account getAccount() {
    return [select id, name,
             (select id, name, firstName, lastName, title, phone, mobilePhone, email from Contacts limit 5)
             from Account where id =
             :ApexPages.currentPage().getParameters().get('Id') ];
}

public String getName() {
  return 'Account Contact List';
  }
}
 
My VF page:
<apex:page controller="accountContactList" tabStyle="Contact">


<apex:pageBlock title="Mass Edit Contacts">

</apex:pageBlock>

<apex:form >
<apex:pageBlock >
<apex:pageMessages />
<apex:pageBlockButtons >
<apex:commandButton action="{!save}" value="Save" id="theButton"/>

</apex:pageBlockButtons>

<apex:pageBlockTable value="{!account.Contacts}"
var="contact">

<apex:column value="{!contact.name}" width="25" />
<apex:column headerValue="Title" width="100">
<apex:inputField value="{!contact.title}"/>
</apex:column>
<apex:column headerValue="Phone" width="15">
<apex:inputField value="{!contact.phone}"/>
</apex:column>
<apex:column headerValue="Mobile" width="15">
<apex:inputField value="{!contact.mobilephone}"/>
</apex:column>
<apex:column headerValue="E-Mail" width="25">
<apex:inputField value="{!contact.email}"/>
</apex:column>

</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>

</apex:page>
The above allows me to access and edit the Account's related Contact records but I am unable to save any changes I make
I have tried adding:
private final ApexPages.standardController the Controller
and
return theController.save();
to the Apex Class but without much success (as described in on p391 of the force.com Developer Guide that I picked up at Dreamforce '08)
Any help/guidance would be most appreciated.
Thanks in advance
Best Answer chosen by Admin (Salesforce Developers) 
zappozappo

I have tried to follow the advice here without success. The save is still not working. I am using 2 custom objects although I cant see why that should be a problem. Here is my apex

 

public class EventsList {
    public EventsList(ApexPages.StandardController controller) {

    }



   public PageReference save() {
        return null;
    }





  public Service__c getService() {
    return [select id, name,
             (select id, name, Actual_Fee__c, Actual_days__c, Employee__c from ServiceEvents__r limit 200)
             from Service__c where id =
             :ApexPages.currentPage().getParameters().get('Id') ];
}

public String getName() {
  return 'Events List';
  }
}

 

Here is my VF

 

<apex:page standardController="Service_Event__c"  extensions="EventsList" tabstyle="Schedules__tab" sidebar="false" showHeader="false">
    <apex:pageBlock title="Hello {!$User.FirstName}!">
        You are displaying Schedules from the {!Service.name} Service record.
    </apex:pageBlock>
    <apex:form >
    <apex:pageBlock title="Schedules" >
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!save}"/>
            </apex:pageBlockButtons>
        <apex:dataTable value="{!Service.ServiceEvents__r}" var="a" cellPadding="4" border="1">
              <apex:column >
               <apex:facet name="header">Service Event</apex:facet>
                {!a.Name}
              </apex:column>
              <apex:column headerValue="Actual Fee">
                    <apex:inputField value="{!a.Actual_Fee__c}"/>
              </apex:column>
              <apex:column headerValue="Actual days">
                    <apex:inputField value="{!a.Actual_days__c}"/>
              </apex:column>
              <apex:column headerValue="Employee">
                    <apex:inputField value="{!a.Employee__c}"/>
              </apex:column>
        </apex:dataTable>
    </apex:pageBlock>
    </apex:form>   
</apex:page>

All Answers

DSchachDSchach
Your code refers to a controller in the <apex:page> tag.  Instead, use

standardcontroller="Contact" extensions="accountContactList"

That way you can use the standard save method.  Otherwise, there are ways to call a custom save() method if you want to use a custom controller.

The rule of thumb is this: Custom controllers overwrite every standard function, so if you want to use any, you must recreate them.  Extensions add to existing functionalities and can reference the standard functions if you wish to use them.

Here's a sample custom save method:

public void save() {
update record;
}

I hope this helps.

dchasmandchasman
Pretty much on target - a few things to note:
  • custom controllers do not really overwrite anything and are not related to the standard controller in any way at the code level. The standard controller is actually just a custom controller written by my team and made available as one potential building block.
  • extensions can also be very useful with custom controllers (e.g. to customize a third party application)
  • you can instantiate the standard controller (and standard list controller too) via Apex Code and use it as a building block inside your custom controllers
The design pattern we use for extensions concept is called a Mix In (there are other patterns e.g. Dependency Injection, Chain of Responsibility, etc that come into play also) and the basic idea is that your code gets "mixed into" a dynamically constructed delegating controller that gives your code first crack at handling messages (get property, set property, and invoke action). You can use this powerful concept to add additional data /or behavior, augment existing data/behavior (e.g. do your stuff then chain to the controller's method), completely replace (or shadow) stuff.

FYI we require the use of the standard controller in VF pages that are the targets for an Action/Override in order to insure that the basic behavioral contract will be adhered to (commonly referred to as an isA relationship in OO lingo) - essentially the platform needs to be able to count on certain common things to be present when allowing customization.


Message Edited by dchasman on 12-28-2008 06:09 PM
aapt.devaapt.dev
Thanks David
 
I'm getting the following error, however:
 
Id value 0018000000Mif1y is not valid for the Contact standard controller (the id being that of the Account).
 
Alex 
 
BTW, we recently met at the Sydney Power User Group meeting on your last trip down under.
AlexYAlexY
a final solution, using standard controller and no apex:
 
<apex:page standardController="Contact" recordSetVar="contacts" tabStyle="Contact" sidebar="false">

<apex:form >
<apex:pageBlock title="Mass Edit Contacts" mode="edit">
<apex:pageMessages />
<apex:pageblockButtons location="top">
<apex:commandButton value="Save" action="{!Save}" />
<apex:commandButton value="Cancel" action="{!cancel}"/>
</apex:pageBlockButtons>
<apex:pageBlockTable value="{!selected}" var="contact">
<apex:column headerValue="Name">
<apex:outputField value="{!contact.name}"/>
</apex:column>
<apex:column headerValue="Title">
<apex:inputField value="{!contact.title}"/>
</apex:column>
<apex:column headerValue="Phone">
<apex:inputField value="{!contact.phone}"/>
</apex:column>
<apex:column headerValue="Mobile Phone">
<apex:inputField value="{!contact.mobilePhone}"/>
</apex:column>
<apex:column headerValue="Email">
<apex:inputField value="{!contact.email}"/>

</apex:pageBlockTable>
</apex:pageBlock>
</apex:form>
</apex:page>
zappozappo

I have tried to follow the advice here without success. The save is still not working. I am using 2 custom objects although I cant see why that should be a problem. Here is my apex

 

public class EventsList {
    public EventsList(ApexPages.StandardController controller) {

    }



   public PageReference save() {
        return null;
    }





  public Service__c getService() {
    return [select id, name,
             (select id, name, Actual_Fee__c, Actual_days__c, Employee__c from ServiceEvents__r limit 200)
             from Service__c where id =
             :ApexPages.currentPage().getParameters().get('Id') ];
}

public String getName() {
  return 'Events List';
  }
}

 

Here is my VF

 

<apex:page standardController="Service_Event__c"  extensions="EventsList" tabstyle="Schedules__tab" sidebar="false" showHeader="false">
    <apex:pageBlock title="Hello {!$User.FirstName}!">
        You are displaying Schedules from the {!Service.name} Service record.
    </apex:pageBlock>
    <apex:form >
    <apex:pageBlock title="Schedules" >
            <apex:pageBlockButtons >
                <apex:commandButton value="Save" action="{!save}"/>
            </apex:pageBlockButtons>
        <apex:dataTable value="{!Service.ServiceEvents__r}" var="a" cellPadding="4" border="1">
              <apex:column >
               <apex:facet name="header">Service Event</apex:facet>
                {!a.Name}
              </apex:column>
              <apex:column headerValue="Actual Fee">
                    <apex:inputField value="{!a.Actual_Fee__c}"/>
              </apex:column>
              <apex:column headerValue="Actual days">
                    <apex:inputField value="{!a.Actual_days__c}"/>
              </apex:column>
              <apex:column headerValue="Employee">
                    <apex:inputField value="{!a.Employee__c}"/>
              </apex:column>
        </apex:dataTable>
    </apex:pageBlock>
    </apex:form>   
</apex:page>

This was selected as the best answer