After reading this post yesterday on Dynamic Visualforce Controllers I decided that I should should stay well away from the subject and leave it to those more experienced and more intelligent than myself to debate. And I am sticking to that decision; no one needs my ignorance muddying the waters.
However one of the comments struck a note with me, probably because it’s a problem that I could solve, and it’s that which I want to focus on.
If you’re not interested in the forthcoming waffle and would rather just skip to the code then you’ll find it over on GitHub.
The problem as I interpreted it was to provide a way from within APEX to quickly and reliably output HTML. It makes sense; writing HTML within code is error prone, not to mention dull. One of the biggest problems is that we’re just creating a string to output – there’s no validation around the structure, missing closing tags, mispelt tags, invalid attributes; they’re all problems that are hard to spot but very easy to create. So whilst creating HTML in code is seen as evil by some, it’s here and possible, so let’s at least try and create the best that we can.
With this in mind I opened up Eclipse, put all of the things I should have been doing to one side and set about trying to create a better way of creating the dreaded HTML.
I decided from the outset that I would write the solution to have a Fluent interface; mainly for readability but also because it reminds me of some of the happier times I had with C#. It also feels like a good fit for this particular functionality… we want to generate HTML like this
<a href="http://google.co.uk">Search</a> <br/>
<input type="button" value="I do nothing"/>
from something like:
.input('button', 'I do nothing');
As you can see there’s a clear corralation between the two, this makes it much more inutive to use, especially if you start breaking lines on the dot.
Implementing the a Fluent style interface isn’t particularly complex; the key is to remember to return a reference to yourself from each method.
Some HTML elements act as containers and can have other elements embedded within them such as a div. Using a simple dot notation here could be confusing for the user; consider the following example:
Where is the anchor tag meant to go? Is it in the div or after the div? It’s not particularly clear. We could add a new method called close or closediv but this then puts the onus back on the developer to remember to close the element they opened. Instead I have chosen to allow another instance of the Fluent interface which in turn describes the HTML to put inside the div. The worse that can happen now is that the developer miss counts the number of closing brackets to add but at least the compiler will assist in picking this up. Using this syntax we can now either appened the anchor:
or add the anchor to the content of the div:
new FluentHTML().div( new FluentHTML().div()
.a('http://www.google.co.uk', 'Search') );
There is another type of container, one that can only contain specific child elements such as an ordered list (ol) which can only have list items (li) as it’s children. In this case the method takes a specialised factory class which restricts the elements that can be added.
With the syntax decided the next step was to implement it. I started out by planning to control the construction of the HTML myself, managing the opening an closing of tags, the consturction of attributes and the addition of the the text. But then I remembered the rather obvious fact that HTML is really just a syntax of XML and that the Force.com platform has a nice object to handle all of that for me. The DOM class certainly made the implementation of this whle thing a lot easier: providing the framework to do the heavy lifting and leaving me to just make sure that I create the correctly named tag. A little bit of tweaking was necessary as I only wanted to output the string that represented the tags that I had added and the toXMLString() method contains the XML header and root but it wasn’t a major problem to clean that up. The biggest problem came in implemeting the container elements such as divs.
My initial thought for bulding the container funtionality was to have the FluentHTML class that represented the child elements of the div expose those nodes and then to add them to the parent div node. There’s just one small problem with that plan… the current implmentation of DOM.Xmlnode doesn’t allow you to add existing nodes as children. Easy I thought, I’ll just call render() on the internal FluentHTML class and add the output as a textnode to the parent div. Another flawed idea! addTextNode() will encode any opening angle brackets into < as you add the text to the node and rightly so. In the end I lumped for the inelegant solution of adding a temporary child node which is numbered and adding the output from the inner FluentHTML object into a map which is keyed by the number of the temporary node. All I need to do then is loop through the map and do a replace when I render the HTML. As I say; it’s not beautiful but it works.
The implementation of the tags themselves is fairly trivial the biggest problem is figuring out which elements to add as parameters, for example should I always offer id as a parameter? This is more a question of what would be useful than actual implementation. The one thing that I will always accept as a parameter in at least one of the overloaded calls is a Map<string,string> of attributes as name value pairs, this means that the user can add whatever they need to to the tag; which also means I don’t need to offer an overloaded call with a billion paramters to cover all possible attributes on the tag.
And that’s pretty much the design of the class – it’s fairly easy really: instantiate a FluentHTML instance, add your tags using the methods avaliable and then when you actually want the HTML call the render() method. Wht could be simpler? At the end of it you know you’ll get some nice HTML out of it and then you’re free to do with it as you please.
The code is available over on GitHub and I will again submit it to the Force.com Code share site in due course. Be warned though, the code that is currently there is very much a first pass at this. I’m sure it could be faster and I’m sure it could be refactored to make it look nicer and on these things I shall work. I shall also be looking at doing everything in a consistent manner: how I chose to implement the tags changed as I was implementing them and this probably shows in the code quite a lot. I also need to spend some time figuring out which attributes on tags to offer as parameters and what combinations of these to present in the overloads. All of these are topics that I’m open to disucssion and opinion about but would like to get sorted before I push ahead and implement the rest of the HTML tag set.
Whilst there is plenty of work left to do I feel as though I have already acheived what I set out to do: to provide a quick and robust way to output HTML from within APEX and all in an evening too – all of which makes me feel happy and that’s a good thing because now I have to go and do all those things I put off to do this instead.