Controller Component Communication
Occasionally you will want to have controller to controller communication between you Visualforce page and a Custom Component. The sample below provides a sample framework to facilitate this communication.
The first step is to create a virtual class that every controller that needs to communicate with a component controller will extend.
public with sharing virtual class PageControllerBase {
private ComponentControllerBase myComponentController;
public virtual ComponentControllerBase getMyComponentController() {
return myComponentController;
}
public virtual void setComponentController(ComponentControllerBase compController) {
myComponentController = compController;
}
public PageControllerBase getThis() {
return this;
}
}
Basically we are declaring a field compController to hold a reference to the component controller instance. We also set up a getter to return the instance of the page controller. Finally, we create a virtual method to set the compController. It is useful to make these virtual so that you can simply extend this class in your page controller and, if required, cast the component controller to a specific type (assuming that your component controller extends the class below).
The next step is to create a virtual class for the ComponentController something like this:
public with sharing virtual class ComponentControllerBase {
public PageControllerBase pageController { get;
set {
if (value != null) {
pageController = value;
pageController.setComponentController(this);
}
}
}
}
This class simply defines a property to contain the page controller. This value will be passed by using an attribute on the component markup. Again, these methods are defined as virtual in case you need special handling or casting for the page controller.
Once you have created these two virtual classes you can now create component controllers and page controllers that extend these classes. This will imbue your controller implementations with the ability to communicate with each other. Below is a sample implementation of a component controller.
public with sharing class MyComponentController extends ComponentControllerBase {
private Integer myValue = 3;
public Integer getIntValue() {
return myValue;
}
public void incrementValue() {
myValue++;
}
}
The code above is simply defining a getter and a method that will later be called by the page controller. The last method in the class is implementation specific to this controller.
The component markup is shown below.
<apex:component controller="MyComponentController" >
<apex:attribute name="pageController"
type="PageControllerBase"
assignTo="{!pageController}"
required="true"
description="The controller for the page." />
<apex:outputPanel layout="block" style="font-size: 12pt; border: 1pt solid black; width: 250px;">
<center>
<apex:outputText value="This is in the component." />
<br/>
<apex:outputText value="initial int value: {!intValue}" />
</center>
</apex:outputPanel>
</apex:component>
The are to pay close attention to is the definition of the pageController attribute. We are setting the type to PageControllerBase. This allows you to reference any controller that extends the PageControllerBase class.
The page controller implementation is shown below.
public with sharing class MyPageController extends PageControllerBase {
public MyComponentController myComponentController { get; set; }
public override void setComponentController(ComponentControllerBase compController) {
myComponentController = (MyComponentController)compController;
}
public override ComponentControllerBase getMyComponentController() {
return myComponentController;
}
public PageReference callComponentControllerMethod() {
myComponentController.incrementValue();
return null;
}
}
In this implementation we are overriding the setComponentController and getMyComponentController methods. We do this so that we can cast the component controller to the specific implementation that we are creating and also reference the MyComponentController declared field - myComponentController.
In addition to the overrides there is an implementation specific action method that calls the incrementValue method of the component controller implementation.
Finally, the page markup that uses this controller is shown below.
<apex:page controller="MyPageController" showHeader="false">
<center>
<apex:outputPanel layout="block" style="font-size: 16pt; margin-top: 50px; width: 400px">
<h2>Sample Illustrating How to Establish Communication Between Page and Component</h2>
</apex:outputPanel>
<apex:outputPanel layout="block" style="width: 300px;">
<hr/>
<h1>Component Shown below:</h1><hr/>
<c:MyComponent pageController="{!this}" />
<hr/>
<br/><br/>
<apex:form >
<apex:commandButton style="font-size: 12pt; color: black"
action="{!callComponentControllerMethod}"
value="Call Component Controller Method"
rerender="output" />
<br/>
<apex:outputText value="Clicking the button above will call the
method on the component controller to increment the initial
value from the component above." />
</apex:form>
<apex:outputPanel id="output" style="font-size: 12pt;">
<center>
<apex:outputText value="{!myComponentController.intValue}" />
<hr/>
</center>
</apex:outputPanel>
</apex:outputPanel>
</center>
</apex:page>
The sample page simply displays the initial value held by the component controller using the component and provides a button to call the action method on the page controller to exercise the incrementValue method on the component controller.
Here is a link to a page that implements the technique shown above.
http://ls-developer-edition.na6.force.com/MyPage
Cheers