James Patterson

programmer, photographer, cinema lover, geek

Modifying HTML Output for XForms in EPiServer

This is a post which has been a long time coming, sitting in my queue for months (actually well over a year) so I hope it's helpful in some way now that I've finally posted it.

As you probably know, the standard output of XForms in EPiServer is tables. Modifying the HTML output by these forms isn't that obvious and there isn't really a friendly way of doing it as you need to modify quite a large string. Even in EPiServer CMS 7 the XForms implementation has remained pretty much the same as in version 6 so code in this post should work just fine in both versions.

The Public Templates include an example of handling some XFormControl events within the Global.asax.cs file. Within the file there is a ‘Global XForm Events’ region containing a number of event handlers. The HTML output of the a form can be changed by modifying the LoadFormEventArgs.FormDefinition property within the XFormControl.BeforeLoadingForm event handler.

Quick Example

Below is a modified version of the Global.asax.cs file. The BeforeLoadingForm event handler shows a simple example of how to modify the FormDefinition string.

public class Global : EPiServer.Global
{
protected void Application_Start(Object sender, EventArgs e)
{
XFormControl.ControlSetup += new EventHandler(XForm_ControlSetup);
}

public void XForm_ControlSetup(object sender, EventArgs e)
{
XFormControl control = (XFormControl)sender;

control.BeforeLoadingForm += new LoadFormEventHandler(XForm_BeforeLoadingForm);
}

public void XForm_BeforeLoadingForm(object sender, LoadFormEventArgs e)
{
XFormControl formControl = (XFormControl)sender;

e.FormDefinition = "<h3>Your modified form output.</h3>" + e.FormDefinition;
}
}

When the the code within the BeforeLoadingForm event handler is run it will prefix every XForm viewed on the website with a heading of “Your modified form output.”

Modifying the XForms HTML

I knew what to do, there are many ways of modifying the FormDefinition string, but I was looking for a quick solution that was proven to work well. After I asked on Twitter, Marcus Lindblom kindly sent me a sample of code he had used which I could modify for my own use and I've been using (almost) the same code since.

Below is an example modification I use on almost every EPiServer project I work on. The HTML which it outputs has become relatively standard at my place of work.

XFormControl formControl = (XFormControl)sender;

string content = e.FormDefinition;string regexMatchStringTables = "]*?&gt;([^&lt;]*)?()?(.*?)()?([^&lt;]*)?";

string matchEvaluatorTables = "<fieldset class="\&quot;xForm\&quot;">$3</fieldset>";

content = Regex.Replace(content, regexMatchStringTables, matchEvaluatorTables, RegexOptions.Singleline | RegexOptions.IgnoreCase);

string regexMatchStringRows = "]*?&gt;(.*?)";

string matchEvaluatorRows = "<div class="\&quot;formRow\&quot;">$1</div>";

content = Regex.Replace(content, regexMatchStringRows, matchEvaluatorRows, RegexOptions.Singleline | RegexOptions.IgnoreCase);

string regexMatchStringEmptyCells = "]*?&gt;(\\s*)";

string matchEvaluatorEmptyCells = "$1";

content = Regex.Replace(content, regexMatchStringEmptyCells, matchEvaluatorEmptyCells, RegexOptions.Singleline | RegexOptions.IgnoreCase);

string regexMatchStringCells = "]*?&gt;(.*?)";

string matchEvaluatorCells = "$1";

content = Regex.Replace(content, regexMatchStringCells, matchEvaluatorCells, RegexOptions.Singleline | RegexOptions.IgnoreCase);

e.FormDefinition = content;

When this code executes a form surrounded in tables similar to this:

<table id="id_matrix">    
<tbody>
<tr>
<td valign="top">
<!-- form control -->
</td>
</tr>
<tr>
<td valign="top">
<!-- form control -->
</td>
</tr>
<tr>
<td valign="top">
<!-- form control -->
</td>
</tr>
</tbody>
</table>

Will be transformed into a HTML structure like this with fieldset tag and div tags for each row of form fields:

<fieldset class="xForm">    
<div class="formRow">
<!-- form control -->
</div>
<div class="formRow">
<!-- form control -->
</div>
<div class="formRow">
<!-- form control -->
</div>
<div class="formRow">
<!-- form control -->
</div>
</fieldset>

Further transformations include having additional classes added to the form row div tags depending on whether the orientation of checkboxes or radio buttons should be horizontal or vertical.

Also if you plan on modifying the output HTML of all XForms on your website you might want to add the following couple of lines before your code. This would be at the top of the BeforeLoadingForm event handler in the example above. The conditional statement will just cause the method to return without further execution if the form is a system form (like file properties within the File Manager). Since system forms don't have a creator the CreatedBy property returns null.

if (e.EditMode || String.IsNullOrEmpty(formControl.FormDefinition.CreatedBy))    return;

© 2017 James Patterson