7

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.

3 Answers 3

9

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.

2
  • 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. Oct 20, 2012 at 3:47
  • Terrible :) but an excellent suggestion Oct 20, 2012 at 10:52
4

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.

3
  • 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 Aug 3, 2013 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, 2013 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 Aug 4, 2013 at 7:18
0

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.

1
  • You're right. I just got the this: Cannot convert the value of '{!headerComponent}' to the expected type. where headerComponent is an Object. Oct 17, 2012 at 21:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .