6

I have multiple visualforce components that each have their own controller that is extended from a base abstract class. For example:

Visualforce Page:

<apex:page>
    <c:MyFirstComponent />
    <c:MySecondComponent />
...

MyFirstComponent 1:

<apex:component controller="MyFirstComponentController">

MyFirstComponentController Class:

public class MyFirstComponentController extends BaseController {

MySecondComponent 2:

<apex:component controller="MySecondComponentController">

MySecondComponentControllerClass:

public class MySecondComponentController extends BaseController {

BaseController :

public abstract class BaseController {
    BaseController(){
        getSomeData();  // Here's the problem
    }
}

Right now for every component instance on the page a BaseController instance is constructed causing the getSomeData() method to fire but this is not necessary considering the data is the same for all components on the page. What is the best way to avoid this?

I was thinking perhaps to remove the controller from the components themselves and instead add those controllers as extensions on the page which I would then pass their instance as an attribute to each component... but since each extension extends the BaseController I would still have duplicates for every component type I have on the page.

Is there a different structure I could use to allow for this without causing these redundancy issues?

  • +1 for titling the post such that it is likely to be found again by others with the same issue – cropredy Jan 16 '16 at 0:37
6

I'd use a CommonDataController to pass this data around:

public class CommonDataController {
    public CommonDataController(ApexPages.StandardController controller) {
        getSomeData();
    }
    public CommonDataController getCommonData() {
        return this;
    }
    // getSomeData not relevant to this example, but should exist.
}

In your BaseController, provide a holding place for this:

public abstract class BaseController {
    protected CommonDataController commonData;
    public void setCommonDataController(CommonDataController data) {
        commonData = data;
    }
    public CommonDataController getCommonDataController() {
        return commonData;
    }
}

Then, your page just includes CommonDataController once:

<apex:page ... extensions="CommonDataController">
    ... <c:myWidget commonData="{!commonData}" /> ...

And each component uses that data:

<apex:component ...>
    <apex:attribute name="commonData" assignTo="{!commonDataController}" type="CommonDataController" description="..." required="true" />

At this point, you have non-static data populated from a common point that allows inter-component communications, shared data resources, etc. The constructor is called only once, and each extension class is provided access to the common data.

  • Getting the following error when attempting to deploy the component: Error: Read only property 'c:myWidget.commonDataController' – Xtremefaith Jan 15 '16 at 22:36
  • @Xtremefaith It might need to be all marked up as global instead of public. I did have that problem previously. – sfdcfox Jan 15 '16 at 22:42
  • I added global to the base controller class and replaced the protected commonData with global but still getting the read only property... – Xtremefaith Jan 15 '16 at 22:52
  • 1
    @Xtremefaith Hold on. It's in my one of my dev orgs. I'll update this answer in a bit. – sfdcfox Jan 15 '16 at 22:57
  • I switched commonData to public and added { get; set; } and now its working... – Xtremefaith Jan 15 '16 at 23:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.