Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I have a visualforce page that I would like to inject custom components (header and footer) if they exist into the page.

According to the docs Creating and Displaying Dynamic Components I can instantiate a custom component like so

Component.c.MyCustomComponent myDy = new Component.c.MyCustomComponent();

but I don't know the name of MyCustomComponent ahead of time, and as mentioned it may not exist. Is there an equivalent of something like:

Component myDy = Type.forName('c:MyCustomComponent'); //does not compile ;)

I am not tied to dynamic visualforce, If anyone knows of an alternative solution I would be very interested.

share|improve this question
add comment

3 Answers

up vote 5 down vote accepted

I have developed a solution, there are shortcomings that I hope someone knows the solution too. The following code snippet allows loading of a visualforce component onto a page dynamically.

public class MyController {

    public transient ApexPages.Component headerComponent { get; private set; }

    public MyController() {
        Type t = Type.forName('Component.c.MyCustomComponent');
        if(t != null) {
            this.headerComponent = (ApexPages.Component)t.newInstance();
        }
    }
}

.

<apex:dynamicComponent componentValue="{!headerComponent}" />

The shortcoming is that, so far as I can tell parameters can not be passed. I would be happy to be proved wrong on this point :)

Credit goes to @Peter for steering me in the right direction on this.

share|improve this answer
1  
Bad practice, but couldn't you have your component check a static variable for an object representing it's properties? Set the static var before calling .newInstance() and clear it after. –  ca_peterson Oct 20 '12 at 3:47
    
Terrible :) but an excellent suggestion –  Daniel Blackhall Oct 20 '12 at 10:52
add comment

I wanted to follow up on this even though its from last year since this was one of the first pages I found when searching.

visual force page with a dynamic component

<apex:page id="thePage">
  <apex:form id = "theForm">
    <apex:dynamicComponent componentValue="{!myCustomComponent}"/>
  </apex:form>
</apex:page>

controller

public class My_Custom_Controller {

  public Account myAccount {get;set;}

  public My_Custopm_Controller() {

    // initialized account logic
  }

  public ApexPages.Component getMyCustomComponent() {
    Component.c.My_Custom_Component customComponent =
      new Component.c.My_Custom_Component(param1=myAccount, param2='My String');

    return customComponent;
  }
}

Notice in the constructor for the component you can set parameters by using key=value pairs.

Component:

<apex:component>
  <apex:attribute name="param1" type="Account" />
  <apex:attribute name="param2" type="String" />

  <!-- The rest of my component -->
</apex:component>

The issue with this however is that this component is no longer kept int he view state. So if have an apex:actionFunction and that calls a method that returns a null page reference this component would get reinitialized if it is sitting inside a panel that you have set as the rerender on the action function.

Assume my component had an inputField for an Account field. If the user had entered anything into that field that has yet to be committed that data would be lost.

I'm currently toying with the idea of on any of my actionFunctions running through the form and storing all the data and storing it in possibly a json string and in the onComplete reset everything.

share|improve this answer
    
This doesn't actually solve the problem I have though. I know how to declare custom components. What I need to be able to do is declare them dynamically –  Daniel Blackhall Aug 3 '13 at 8:56
    
The getter method had a return type of ApexPages.Component. from that you can return whatever custom component you wanted based on some logic. –  Pick Aug 3 '13 at 20:14
    
I don't think you're understanding my issue. The name of the component is unknown, I can't just put logic in the getter –  Daniel Blackhall Aug 4 '13 at 7:18
add comment

I'm just learning about the Type class, but looking at the docs, I would think the syntax you would want to use is:

Type.forName('Component.c.MyCustomComponent');

But as I play with this more, I think the greater problem is what to pass it into.

Component, is either not a concrete class, or Apex is not given access to it.

The docs explicitly state that apex:component is not represented in dynamic Apex. So no dice there. Still, I tried: Component.Apex myComp; (seemed to confuse the hell out of the compiler) Component.Apex.Component; (invalid type)

Finally, this compiles, but throws a null pointer exception:

Type t = Type.forName('Component.c.MyCustomComponent'); Object myComp = (Object) t.newInstance();

And Object, while it exists, probably won't bind to your page, in the end.

I think you've reached one of the limits of the platform, unfortunately.

share|improve this answer
    
You're right. I just got the this: Cannot convert the value of '{!headerComponent}' to the expected type. where headerComponent is an Object. –  Daniel Blackhall Oct 17 '12 at 21:34
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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