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 am designing a custom input form that will be data-driven and will display things like input fields, input text components, custom inputs that I create, etc. The elements on the form will be largely data-driven so I could create it with dynamic vf binding like so:

<apex:repeat... var="inputobj">
  <apex:outputpanel rendered="{!inputobj.type == 'standardinputfield'}"
    <apex:inputField required="{!inputobj.isRequired}" value="{!inputobj.data[f.apiName]}"
  </apex:outputpanel}"
  <apex:outputpanel rendered="{!inputobj.type == 'something'}"
  ...
  </apex:outputpanel}" 
  <apex:outputpanel rendered="{!inputobj.type == 'something else'}"
  ...
  </apex:outputpanel}"
  ...
</apex:repeat>

I've used this pattern in the past and it works reasonably well but the vf becomes quite unwieldy as you create more types (both from a development and performance perspective) and you can't really reuse and extend the vf like you can with abstract and virtual classes.

My idea is that the inputobjects will have a method which generates a dynamic vf component for itself and then just repeat over those components. Has anyone built something similar or run into any issues with this?

My main concern is ending up with an unholy mess of UI mixed in with business logic or running into performance issues with dynamic vf components.

share|improve this question
    
This question will probably get closed, @grigriforce, because it has best practice in the title. Check out / Join in on the meta question and answers on bestpractice questions –  Peter Knolle Dec 20 '12 at 0:10
1  
@PeterKnolle I'LL get in on the meta discussion but there definitely does not appear to be consensus that these types of questions should be closed. –  Greg Grinberg Dec 20 '12 at 4:19
    
Also, while the question title says best practices I am asking for design-patterns or thoughts on a fairly specific implementation of dynamic vfcomponents. –  Greg Grinberg Dec 20 '12 at 4:27
    
Please try to edit your question, it does ask for design patterns, and is too open question IMO, and does not fit the Q&A type of site. I will not close the Q for now, but will wait for your edit. –  Saariko Dec 20 '12 at 5:18
    
@Saariko I've created a question in meta to discuss whether this question should be closed. It's 1AM where I am but I'll take a look at this question with a fresh brain tomorrow to clean it up. –  Greg Grinberg Dec 20 '12 at 5:59
add comment

2 Answers 2

I think the first things you should look to use are Dynamic Visualforce Components. The introduction of this feature was meant to address some of the challenges that you are facing. This allows you to simplify your Visualforce markup by moving the logic of the markup (view) rendering to your Apex Controller. Some will argue that this is bad because it mixes View responsibilities into your Controller, thus breaking the MVC design, but this can also be a really powerful feature if used appropriately.

There is a good example here of returning a outputPanel from the controller.

Aside from this, you can also look to create some of your own Visualforce Components to keep your markup pages a little cleaner.

share|improve this answer
    
Sorry if it wasn't clear but I'm perfectly aware of dynamic visualforce components. That is what I was referring to in my question when I said dynamic visualforce. I'm looking for best practices and pitfalls I should watch out for if I decide to go down that route. –  Greg Grinberg Dec 19 '12 at 20:58
1  
Oh I see. I was confused by your VF example. I think the only pitfall that I can think of is the complication of the controller logic as I mentioned in my post. I don't know of any performance issues. Personally, I'd opt to create some Custom Visualforce Components and skip the Dynamic Visualforce Components to keep the presentation and logic separated. –  Kevin O'Hara Dec 19 '12 at 21:07
add comment

In a solution I'm building, I adopted the following as pattern.

In the controller, I have a couple of publicly visible elements:

  1. A public Map<String,Object> returned from a method called getViewBag().

  2. a public method named getControlTree() that returns the dynamically generated control tree.

The page looks like this:

<apex:page controller="MyPageController">
  <apex:sectionHeader title="My Section Title" />
  <apex:pageMessages id="pageMessages" />
  <apex:form id="theForm">
    <apex:dynamicComponent id="dynComp" componentValue="{!ControlTree}" />
  </apex:form>
</apex:page>

In the getControlTree Method, I first check if my Map is null. If it is, I initialize it by adding field names and objects. These field names are read from another custom object. The values are chosen based on a "type" of the field, so I add a boolean for example if the field is a checkbox.

With the Map built, I then build the control tree. My getControlTree method returns a PageBlock component which is the container for the hierarchy of form controls.

The knack is configuring the right binding expression on the dynamically created forms. For example, I do this:

Component.Apex.InputText ctl = new Component.Apex.InputText();
ctl.label = field.label;
ctl.expressions.value = buildBindingExpression(field.name);

with the helper function:

private string buildBindingExpression(string fieldName) {
  String expr = '{!ViewBag[\'' + fieldName + '\']' + '}';
  return expr;
}

So the binding expression {!ViewBag['Surname']} refers to the object obtained by m_viewBag.get('Surname')

I encountered four main problems:

Firstly, SelectLists required special handling. The options part has to be bound to a List<SelectOption> and cannot be bound to List<String> or string[] as I expected. The value part of the SelectList must be bound to a String. If you choose to make the SelectList multiselect, the value might have to be a String[] or a List<String>. Haven't tried. Don't know.

Secondly, the list of possible controls seems limited to Checkbox, Radio, SelectList and Textbox and there doesn't seem to be a way of marking a control as mandatory (prove me wrong).

Thirdly, validation. If a textbox is numeric only, or an email address - or if a field is a datepicker, there doesn't seem to be a way of rendering the right control. Component.Apex.InputField will render the right control(s) but can only be bound to sObjects.

Fourthly, there doesn't seem to be a way of programmatically setting html5 pass-through attributes, so I can add an InputText and set the type to "email", for example.

For the above reasons, I'll probably soon re-write my dynamic page to do the control-tree generation on the client with heavy JavaScript support.

It just occurred to me I could create a custom object with a property for every type of possible property, and bind InputField instances to the appropriate property on instances of my custom object - but that would be desperate and possibly a bit dumb.

share|improve this answer
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.