Dynamic Visualforce Components, why they scare the ish out of me
Dynamic Visualforce Components are coming and they scare me…a lot. Before we can even begin to discuss why we need to review the basics of the model-view-controller pattern. If you aren’t familiar with the MVC pattern here is the basic run down when it comes to web apps that use MVC. Model, this represents your database and contains information on they fields in your database, validation rules, relationships, etc. View, this is the visual display of a model or many models. It says output the fields of a record in HTML on some web page and style them this way. This is where you can visually control how the data is displayed to the user. Controller, this is the code that retrieves and manipulates data from the Model and then prepares it for the View to use. A web app will most likely consist of many Models, Views, and Controllers. Some people may want to overcomplicated the MVC pattern, and it does vary slightly based on the platform or framework, but for the most part this is exactly how it works 97% of the time. So in the force.com world it looks a little like this:
Model
These would be custom objects, you can add fields, create validation rules, and build relationships with other objects.
View
Visualforce pages are the view and allow you to output information from the model as an HTML webpage.
Controller
One or many Apex classes associated with a Visualforce page. Here you can query and manipulate data before it is sent to the view for output.
So what does any of this have to do with Dynamic Visualforce Components (DVCs)? The reason is that DVCs allow developers to completely mangle and destroy the model-view-controller design pattern. They allow you to completely define the display from the controller. So basically MVC becomes M(VehCiv) or perhaps Model Viewroller as the View and the Controller start to get all mixed up. Big flipping deal you might say, all of the other hip cool web technologies (Rails) allow you to inject markup from the controller. Yes, they do, and there are people in those communities that feel the exact same way I do about mixing aspects of MVC, just because you can doesn’t mean you should.
Here is a very basic example of how mixing up the MVC can cause trouble. Let’s say you are working on a project where you have a web designer who is great at making spiffy looking websites and a developer that understands all the back end work. If you keep the View and the Controller separate these people can work individually on their part of the project. When you start to combine the View and the Controller the web design guy might be waiting for the developer to get the output setup so he can style it. Or maybe even worse you end up have a web designer starting to poke around in controller code, not ideal.
Mixing the View and the Controller also makes things more complicated and difficult for others to understand. When looking through a controller you now have to start mentally separating the view code and the logic code. For the consultants out there that sometimes have to inherit other’s code I do not envy you when you have to dig through someone else messy code, DVCs will make it messier.
Okay Jason, we get the point, but there are times when we need DVCs to meet the project requirements! Are there? Do you really need to use them? Doubtful. Yes, there are some use cases out there that can only be solved with DVCs but these are actually pretty rare. So if you think you need to use DVC’s, think again, and the ask someone else, perhaps on the force.com developer forums, and then if you still think you need them go for it. Personally, I still can’t think of a super great example for DVCs, but I’m sure after this post I’ll be inundated with use cases where only DVCs can save the day!
So here is an example of using DVC vs not using them. This is actually the example taken from the recent Force.com Summer 11 webinar. The goal is to get an output that looks like this:
An unknown number of tabs is the dynamic piece that needs to be solved. Here is one way to do it with DVCs. First the page. One thing I will point out right way is that when you look at this page you have no idea what constitutes the dynamic components. There is nothing that lets you know if they are a table, a div, text, etc. You would need to go look in the controller to see exactly what the dynamic component is made of. It is less markup but it is also inherently less descriptive and as mentioned before more difficult to understand. This is one of the core advantages to staying true to the MVC pattern. On a View it should be dead simple to understand the generated markup and output.
<apex:page controller="TopOpportunityController"> <apex:stylesheet value="{!$Resource.CustomTableCSS}"/> <apex:sectionHeader title="Top 10 Open Opprtunities"/> <h1>Total Expected Revenue from Top 10 Opportunities:</h1> $ <apex:dynamicComponent componentValue="{!OppTotal}"/><br/><br/> <apex:dynamicComponent componentValue="{!tabbedView}"/> </apex:page> |
Next the controller. Notice that we are querying the data but also directly manipulating and defining the view in this controller. For me, when these two areas start to combine it can become blurring on exactly what code is interacting with the Model and what code is interacting with the View.
public with sharing class TopOpportunityController { private List<Opportunity> topOpportunities; public Double opportunityTotal {get;set;} public TopOpportunityController (){ topOpportunities = [SELECT closeDate, TotalOpportunityQuantity, Id, Name, AccountId, Account.Name, Probability, ExpectedRevenue, stageName, Amount, Account.Open_Opportunities_Total__c FROM Opportunity where isClosed=false ORDER BY Account.Open_Opportunities_Total__c DESC, Account.Name, ExpectedRevenue DESC LIMIT 10]; } public Component.Apex.TabPanel getTabbedView(){ Component.Apex.TabPanel panel = new Component.Apex.TabPanel( switchType = 'client', title = 'Top 10 Opportunities'); String lastAccountId; opportunityTotal = 0; for (Integer i = 0; i< topOpportunities.size(); i++){ Opportunity o = topOpportunities[i]; opportunityTotal += o.ExpectedRevenue; //If we have a new Account record, need to create a new Tab if (lastAccountId != o.AccountId){ Component.Apex.Tab acctTab = new Component.Apex.Tab(); acctTab.label = o.Account.Name; panel.childComponents.add(acctTab); } Component.Apex.OutputText oppText = new Component.Apex.OutputText(escape = false); oppText.value = ''; //If this is a new tab, start a new <table> if (lastAccountId != o.AccountId){ oppText.value += '<table class="customT"><thead class="customT"><tr class="customT"><th class="customT">Opportunity Name</th><th class="customT">Probability</th><th class="customT">Stage</th><th class="customT">Expected Revenue</th></tr><tBody class="customT"></thead><tBody class="customT">'; } oppText.value += '<tr><td class="customT">' + o.Name + '</td>'; oppText.value += '<td class="customT">' + o.Probability + '</td>'; oppText.value += '<td class="customT">' + o.StageName + '</td>'; oppText.value += '<td class="customT">' + o.ExpectedRevenue + '</td>'; oppText.value += '</tr>'; if ( (i == topOpportunities.size() -1) || o.AccountId != topOpportunities[i+1].AccountId ){ oppText.value += '</tBody></table>'; } panel.childComponents.get(panel.childComponents.size() -1 ).childComponents.add(oppText); lastAccountId = o.AccountId; } return panel; } public Component.Apex.OutputText getOppTotal(){ Component.Apex.OutputText oppTotal = new Component.Apex.OutputText(); oppTotal.expressions.value='{!opportunityTotal}'; return oppTotal; } } |
So how would you do it mister smarty pants? Oh, I’m glad you asked. I would still use Dynamic Visualforce, just not Dynamic Visualforce Components. In my approach I want to look at the controller first. Notice that this controller has nothing related to the structure and style of the View. It only queries and process information from the Model. This should make it easier to understand exactly what the code is doing from a logic standpoint as you do not need to mentally separate the View logic. Some of the variables control how the information will be displayed on the page and this is okay, this is exactly what a controller should do. One thing to notice is the use of Maps. Map support was recently added to Visualforce as Dynamic Visualforce and is it is fan-freakin-awesome. I would bet it will solve 95% of your dynamic Visualforce needs. The other 5% is for Dynamic Visualforce Components.
public class TopOppsController { public List<Id> accountIds {get; set;} public Map<Id,String> acctIdNameMap {get; set;} public Map<Id,List<Opportunity>> acctIdToOppsMap {get; set;} public Opportunity totalOppAmount {get; set;} //User Opportunity object amount field as wrapper for total, outputField will format currency public TopOppsController(){ buildOppList(); } public void buildOppList(){ //Instantiate variables accountIds = new List<Id>(); acctIdNameMap = new Map<Id,String>(); acctIdToOppsMap = new Map<Id,List<Opportunity>>(); totalOppAmount = new Opportunity(Amount = 0); //Query the Opps List<Opportunity> opps = [SELECT CloseDate, Id, Name, AccountId, Account.Name, Probability, StageName, Amount FROM Opportunity WHERE isClosed=false ORDER BY Account.Open_Opportunities_Total__c DESC, Account.Name, Amount DESC LIMIT 10]; //Process the opps for(Opportunity opp : opps){ //Increment total amount totalOppAmount.Amount += opp.Amount; //Add accountId and Name to map, these Id -> Name map values can be used in Visualforce page acctIdNameMap.put(opp.AccountId,opp.Account.Name); //Add Opps to Account ID -> List<Opps> map, the List values in this map can be use in Visualforce datatables if(acctIdToOppsMap.get(opp.AccountId) == null){ acctIdToOppsMap.put(opp.AccountId,new List<Opportunity>()); accountIds.add(opp.AccountId); //We add account Ids to list and then we can iterate over this in page and pull values from Maps in the controller } acctIdToOppsMap.get(opp.AccountId).add(opp); } } } |
Next up is my Visualforce page. One of the first things you will notice is that I had to use a little bit if jQuery magic. In my first attempt I tried to use an apex:repeat component inside of an apex:tabPanel but this simply does not work. So a bit unwillingly I turned to jQueryUI to address the tab issue. The good news is that using the jQuery UI tab panel is ridiculous easy: 1) Create a div that will represent the tab panel. 2) In this div create list of <a> links where href is the Id of a seperate div representing the corresponding panel. 3) Four lines of jQuery javascript. I’ll admit this is not 100% native where as DVCs are but this approach is actually very simple. It also makes it easier to see what the view is doing, and actually provides complete control over the tab panel style, and interaction. Even if you did use the native tab panel, it is doing the tab switching with javascript anyway ;-P .
So all that aside the page should be pretty easy to understand. With out any type of inline comments you’d be able to see we have a list of <a> links that is outputting an account name. Then for each one of these names we also have a corresponding data table. Keeping the View out of the controller makes it much easier to see how the page is formatted….or at least I think it makes it easier. You lose this type of natural documentation when using DVCs.
You can see a working example by clicking here.
<apex:page controller="TopOppsController" > <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js"/> <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.12/jquery-ui.min.js"/> <apex:stylesheet value="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/ui-lightness/jquery-ui.css"/> <script type="text/javascript"> var j$ = jQuery.noConflict(); j$(document).ready(function() { j$("#tabs").tabs(); }); </script> <apex:sectionHeader title="Top 10 Opps!"/> <h1>Total Amount from Top 10 Opportunities: </h1> <apex:outputField value="{!totalOppAmount.Amount}"/><br/><br/> <div id="tabs"> <ul> <apex:repeat value="{!accountIds}" var="acctId"> <!-- Loop through list of account Ids --> <li><a href="#tabs-{!acctId}">{!acctIdNameMap[acctId]}</a></li> <!-- use account Id to get values from acctIdNameMap --> </apex:repeat> </ul> <apex:repeat value="{!accountIds}" var="acctId"> <!-- Look through list of account Ids --> <div id="tabs-{!acctId}"> <apex:pageBlock mode="edit"> <apex:pageBlockTable value="{!acctIdToOppsMap[acctId]}" var="opp" width="100%" > <!-- use account Id to get list of opps from acctIdToOppsMap --> <apex:column value="{!opp.Name}"/> <apex:column value="{!opp.Probability}"/> <apex:column value="{!opp.StageName}"/> <apex:column value="{!opp.Amount}"/> </apex:pageBlockTable> </apex:pageBlock> </div> </apex:repeat> </div> </apex:page> |
So in the end DVCs have a purpose but more often then not you will probably not need them to meet your specific requirements. The real danger is using them when you really don’t need to and I’m hoping everything I’ve listed in this post explains why you should make a conscious effort to only use them when absolutely necessary. In the end this will make your apps easier to understand and then when you leave your company to go start the next million dollar start up the poor sap that inherits your code won’t go insane trying to understand the mess that is your controllers.

OMG – Were you somehow listening to the Force.com Dev Meetup last night in Chicago? I had the exact same thoughts and discussion with Josh Birk the Salesforce.com Developer Evangelist!
I told him I was worried that this will open the door to folks putting view layer logic in the controller layer! He stated it was like having a tool in your toolshed which you may never need to use, but if you need it its there so you can use it. Still waiting to hear a concrete use case myself.
This is too funny! lol.
I agree with you. DVCs might break the MVC pattern, however, having alternatives for doing certain things is awesome. Hopefully good documentation on best practices for VF development will avoid going with DVCs as a first option.
One possible Use Case (just a possibility, not a golden unicorn that proves the positions to the contrary are wrong):
In my org, we have various web forms that are in development. The web forms are massive and will eventually draw from hundreds of field. Due to our industry, the data that needs to be captured in these forms is constantly changing. …not just the data for a field, but the fields themselves, mind you.
With Dynamic Components, it is possible for our business to allow users that receive these changing requirements to manage the content presented in our Web Forms vs. waiting for our development arm (which is a fully tapped resource with many weeks lead time). Therefore, for expediency, Visualforce Component COULD be applied as a means of quickly changing fields across dozens of Web Forms without requiring development OR modifying multiple VF pages.
Of course, I reserve the right to have completely misunderstood the concepts here.
Hey Jason — Thanks for the thoughtful post. I agree that in general Dynamic Visualforce Components are for specialized use cases. We state that pretty clearly in the docs. I also agree that the example in the webinar wasn’t an ideal use case either.
The real use case for DVCs are for pages with very complex rendering logic. Maybe this isn’t something you’ve had to support in your work, but we’ve seen some really complex and convoluted things that customers and partners are trying to do. At the extreme end of the spectrum, for example, are partners trying to build metadata-driven CMS-like frameworks on VF. One problem in these cases is that the pages are hard to maintain. Defining rendering logic in Apex code, rather than markup, is often easier and more natural. The other thing to note is that complex pages like these have a bigger problem. Because of how the VF framework works behind the scenes, these pages can result in huge component trees, unnecessary processing, and bloated view state — all of which combined can have a serious impact on performance. DVCs are a way to write faster pages. I’m working on an example to highlight this for my Dreamforce presentation.
Beyond that, I wanted to (respectfully) rebut a few of your MVC related points:
1) You point out that DVCs pollute the Controller with the view. Fair enough, but there’s nothing stopping you from structuring your DVC Apex code in a separate ViewHelper class, and outside of the Controller itself.
2) You give the classic example of a UI designer responsible for the view and the coder responsible for the controller. In my 20 years of software development, I’ve never come across this in the real world. Maybe a designer generats HTML mockups, but the person implementing the VF/JSP/ASP is almost always the same as the person writing the controller code.
3) Even if the above were the case, it would argue against making use of JavaScript technologies like JQuery in your view. Since the designer should be decoupled from the code.
4) Speaking of JavaScript, it often handles a lot of controller-type responsibility. So JavaScript is out if you want to be an MVC purist and keep things separated.
I’m going to agree with Stephan on this one. The injection of the exact piece of markup I need, instead of several calls to controller to determine the conditional layout is preferable. I’ve built 2 CMS’ now and this is something I would’ve loved to have had. Instead I had a meta-meta-data language in one, and deeeeeeep templating and component reliance in the other.
I was thinking about MVC from the other direction just yesterday. I’m starting to build applications that are pushing past the 50% JavaScript:50% Visualforce/Apex mark so now I’m using MVC within MVC and the lines are getting blurry.
An example of an authority who generates View-stuff server-side is Google. All those maps and visualisations are requested from our side using JS, but Google is almost certainly using server-side code to generate all that beautiful markup before sending it our way.
Love the post, these are the kinds of things we should be debating because the times, they are a-changing.
… and I would be very very grateful if some very smart person out there in the community could bake up an HTML-factory library because I’m not keen to build HTML manually on the server-side (wink-wink nudge-nudge Steve:).
In general, if you need describes on the controller side, it’s easier to use DVC to build the view.
For example, think of the pages in the setup screen that allow you to create new fields on custom objects or custom settings. It would be pretty bizarre building those in VF without DVC. In fact, the custom settings ones _are_ in VF (e.g. listCustomSettings.apexp), and they use an internal-only hack version of DVC that’s existed for some time.
@t fizz
What about field sets? It sounds like these are a perfect example for your use case.
@Stephan Morais
All great points, I knew this post would foster a lively debate but I think it’s good to get this stuff out in the open and get input from the experts like yourself. I think what would really help is some good examples of when to use DVCs as this is a big question mark for a lot of people.
@Rich Unger
I looked at those pages and it’s not quite clear to me how DVCs are advantageous. I’m totally fine with using describe statements to assist with the generation of of the html I just don’t think this html (ie vf components) should be defined in the controller unless absolutely necessary. For those pages could you use a describe statement to populate a list of data and then on the VF page iterate over this data and control the layout using Visualforce components on the page rather than in the controller?
You probably could, but you’d end up with far, far more verbose code. You’d be doing a giant if statement in the view (if it’s _this_ type of field, then use this field type). And it’s not like you’re specifying visual markup in the controller. It’s a pretty high level component. The markup (that is, the actual html) is still in the component definition, which is in the view.
I see where you’re coming from, but I still think there’s some cases where readability and maintainability are better served with DVCs than with a mess of logic in the page itself.
@Rich Unger
Rich, I think I am bit confused on what area you are specifically referring to. In the custom settings area I see this page /setup/ui/listCustomSettings.apexp which is the main custom settings page and then /setup/ui/viewCustomSettings.apexp when viewing a specific custom setting. These are both essentially data tables. Is this the area where you are using DVCs? The only dynamic piece I see is the Data Type column. What about creating a visualforce component that takes in meta data as an attribute and outputs the correct formatting?
Or… are your referring to the wizard process you go through when creating a new field. I can see this being much more dynamic.
@Stephan Morais
Great discussions, even though some of my initial arguments have been a bit squashed I love the dialog. I am thoroughly looking forward to your DF11 session. Your session last year was probably the best one I attended.
You previously mentioned huge component trees and bloated viewstates. Are elements that are not rendered included in the component tree? When it comes to view state this is a serialized version of your controller, yes? I’ve found the biggest culprit to large view states is large collection type elements, not necessarily complex markup…but I could be off. Would you not have potentially the same problems with DVCs if you still have to maintain state?
Viewstate is a whole topic unto itself, and I’ll cover it my DF preso as well. If you haven’t yet, do check out this post on Devloperforce:
http://wiki.developerforce.com/index.php/An_Introduction_to_Visualforce_View_State
To answer your specific question, yes, even components that are not rendered do end up in the component tree — since after a postback state could change such that they would need to be rendered.
Generally complex markup isn’t the main culprit, but we’ve seen many cases where it is. Again, I’ll have more to share on this once I whip up a better example for my preso…
Why do I read these posts when I haven’t a clue what any of it means? Because I love my Jason! I like the comments too
Yes, I’m referring to the more dynamic parts of the custom settings UI. editCustomSettingsData.apexp is one example.
Thanks for the post; I was curious about use cases as well.
P.S. Your mom rocks!
@Wes I wasn’t too sure how serious you were with that comment and I’ve probably missed where you wanted to go with it… but I was bored this evening and so went off on this little HTML/APEX tangent http://bit.ly/ksfpz9 Probably completely irrelevant but code for thought anyway.
I’ll side with Jason even though he uses jQuery as controller within the “view”. In MVC I put the most value on a purely model-focused Model: because I want to resuse Model across many UI components and many applications within an organization or beyond. I find the Visualforce/Apex “Controller” class blurs model (data retrival and logic that manipulates data) with controller (actions that invokes behavior exposed by the model and actions that direct the flow of visual presentation). In a larger software structure it is preferable to place the Model into a separate bundle (plug-in) that can then be shared across many UIs.
Speaking of separate bundles, in SF we only have the single flat folder so all class files are in the same space. This, I hope, will eventually evolve so we can bundle classes and get back this basic architectural design pattern.
Simon, about your HTML generator project. I took a quick look and here are my thoughts: We’ll need code to handle all the element types, plus various attributes, plus handling stuff like style and script. Even then the user of the project tool will often need to hand code complex situations. I have written quite a few HTML / XML generators and I think best way to get started is to have an extensive set of well-tested DOM manipulating utility code. These already exist in languages such as Java. Can we reach out and reuse this code? Otherwise, I think, the project will either have very large class files or many smaller classes in the single SF folder structure. Building this amount of code, in the apex environment, is going to be time consuming because, the tooling is nowhere near the capability of Java in the Eclipse environment. Too bad there is no way to develop utility classes (e.g no interaction with MDML) off line.
Jason, big thank you for a very educational posting and everyone for the educational discussion. I’m looking forward to DF11 and Simon’s presentations.
I’m going to use your ideas right way and I’m particularly thankful for the concise example on how to include jQuery (which I love) with the very powerful tools that apex provides. Your post also showed me how to use apex maps to store data and then use it in visualforce. I’ve been reading the manuals and searching the web all day looking for an example like this!
So can you tell us how you really feel!
Nice write up never would of thought about it that way. But of course I’m not a coder and I tend to get a headach looking at code
I totally agree that this allows you to break the MVC model, which I personally feel VF/Apex do a very good job of implementing. However, I just found a real world practical use for this. You can display a preview of an outbound email based on an email template using this, where the email template has merge fields. For example, suppose the email template starts with this:
“Dear {!Account.FirstName} {!AccountLastName} …”
Then you could use the following code to preview the email with the merge fields resolved.
Controller code:
Id emailTemplateSelected ; // ID of an Email Template,
emailTemplateSelected = … ; // Your logic, or passed in thru VF
public Component.Apex.OutputText getPreview () {
body = [select Body from EmailTemplate where Id = :emailTemplateSelected].Body ;
Component.Apex.OutputText ot = new Component.Apex.OutputText() ;
ot.expressions.value = body ; // Note use of expressions, which allows you to dynamically use merge fields
ot.rows = 10 ;
ot.cols = 80 ;
return ot ;
}
Visual Force:
And when you view the email preview, voila: it will actually show the Account FirstName and LastName. I have no idea if SFDC had this in mind when rolling out DVC, but I suspect not. One of our customers needed this. As they say, necessity is the mother of invention
Can’t tell you how much time you just saved me. I opted to go the jQuery route for the same reasons you highlight. Burying UI code in the controller is a mess.
Sometimes you may have a view whose entire purpose is to render or display information without further interaction, like a VisualForce page rendered as pdf.
Developing this in pure controller logic simplifies development by magnitudes, especially when you use configurable definitions via custom fields, e.g. using json for layout and css for styles.
In this case, Visualforce only adds to the complexity, not only in terms of markup but also in terms of patterns to be used to meet an end.
With dynamic VisualForce components you can dynamically construct the whole output in your controller and render it with a single apex:outputText in your Visualforce page. At that point, the actual visual design of the view is taken care of in which ever custom object fields you use to define contents, layout and styles, e.g. your “template”.