This content is archived. See latest version here.

Last updated: Mar 31 2014

Introduction

XForms contains logic to store and present forms and data posted from forms. Together with the forms editor in the EPiServer CMS edit view, it enables editors to create and modify forms and to view form data. The XForms architecture enables customization, allowing developers to adapt the XForms functionality. This document describes how the technology is built up and answers common questions concerning EPiServer XForms.

Basic XForms concept

Editors use the Forms Editor to create forms in edit view. When saved, the content of the form is saved as XHTML and XForms markup.

When the form is presented, it is loaded as web controls and rendered as HTML to the client, so there is no need to install any additional software to support XForms to the client. Note that when using this approach, EPiServer CMS does not support the client-side functionality that may be available when using an XForms browser plug-in.

Folders for forms

Form folders make it possible to organize a group of forms in a folder structure, which can be useful if the site contains many forms. It is also possible to set a default folder for forms for either the entire website or parts of the website, making it easier for editors to manage forms. This is done by adding a dynamic property named “DefaultFormFolder” and then setting the property value to the folder of your choice for the part(s) of the website you want to affect.

When creating a new form page and selecting a form, the default folder will be the starting point for the form selection. When creating new forms, the default folder will be suggested. This property is supported, but is not included in the sample site and is, therefore, not included in the language files.

XForms forms management structure

  1. A form is created in the Form Editor in EPiServer CMS.
  2. Through EPiServer.XForms, the form is converted to XHTML and XForms. Steps 1 and 2 can be repeated until the form has the desired look and functionality.
  3. Through EPiServer.XForms, the form is sent to the client as HTML. It is possible to alter the form before it is presented to the client by attaching to events.
  4. Data is posted and validated. If the input does not pass validation, error messages will be sent to the client. (It is also possible to have additional validation on the client before sending the form to the server. This is done by setting the EnableClientScript property to true on the XFormControl web control.)
  5. Through EPiServer.XForms, form data is passed into the EPiServer CMS data warehouse. It is also possible to send the posted data as an e-mail or to a custom URL.
  6. If the data has been saved to the database, it is possible to load and show the posted data on the website.

EPiServer.XForms namespace

XForm class

This class is a representation of the content and structure of the form. The content of the form is saved as XML. The XML contains the instance node, which contains the data for the form such as field validation, default values for fields etc. It also stores information about the structure of the form. This is stored as XHTML with controls from the XForms namespace. This class is responsible for creating a default XFormData object from its instance node.

The following code shows an example of the content of an XForm. When exporting a form the EPiServer CMS forms editor the form content will be represented in this format.

XML
<root xmlns:xforms=a href="http://www.w3.org/2002/xforms">http://www.w3.org/2002/xforms</a>
      xmlns:xsi=<a href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>>
    <model>
           <instance>
                </Author />
                  </instance>
    </model>
      <table id="id_matrix" border="0">
              <tr>
                  <td valign="top" width="100" height="10">
                                   <span id="id_fields1">Author</span></td>
                  <td valign="top" width="200" height="10">
                      <xforms:input ref="Author" value="" id="id_fields2" size="40" /></td>
              </tr>
      </table>
</root> 
Even though this example shows a form that is structured using HTML tables, there are no limitations for the structure of the form to use other elements, such as the <div> element. In EPiServer CMS the built-in form editor creates a form using HTML tables.

XFormData class

The XFormData class contains information on the content of a posted form. Normally a new XFormData class instance is created when a form is posted, but it is also possible to define an old post when loading a form to be able to re-edit data. This is also the class representing existing data when loading form data for a form.

DataTypes class

The DataTypes class contains information on all the data types available for form fields. These are contained in a public property, Types, which is basically a hash table. The hash table simply contains keys and values, where keys are the unique key for the data type and the value is a regular expression.

When posting form data, all input will be validated against the regular expression for the data type of the input control. If no data type has been specified for the control, the data will be validated against the public string property InvalidDefaultInputRegex. The reason for having a default validation is to prevent malicious data being posted from a form.

EPiServer.XForms.WebControls namespace

XFormControl class

This is probably the most important class when working with XForms. XFormControl is a web control that is used to display an XForms form and makes sure that the input is validated. The class exposes a public method, SubmitForm, to be able to submit form data. The form itself does not trigger the actual posting. This is handled by any existing submit web controls in the form, which is also why it is possible to have several buttons on the same form that may trigger different actions. Of course, it is also possible to call this method from the code.

What happens when the form is loaded?

  1. The BeforeLoadingForm event is triggered. It is possible to alter the XForm definition here by changing the formDefinition property of the LoadFormEventArgs that are sent to the event handler. (For instance you could replace the table structure with a div structure by applying regular expressions to the form content).
  2. The XML from the FormDefinition.Document property is parsed by Page.ParseControl. The parsed controls are added as child controls. Basically these would be Literal controls for the HTML and form web controls derived from XFormControlBase.
  3. For fields that have validation, validation control(s) are added and connected to the corresponding web control.
  4. ControlsCreated is a triggered public event. It is possible to alter the appearence and funtion of the form at this time.
  5. Rendering of the form takes place. All Xform controls are rendered as XHTML.

What happens when data is submitted?

  1. The SubmitForm event for a submit control is triggered. If defined on the submit control, the submit will set values for e-mail and/or custom URL to the forms data property for the XFormControl that it is contained in. The SubmitForm method is called with the channel options set on the submit control. See Sending Form Data for more information on available channels.
  2. Validation will take place to ensure that rules about anonymous users and several postings from the same user are followed. If there are validation errors against these rules StaticValidators will be added to the Page.Validators collection to ensure that validation errors will be thrown. A StaticValidator is a validator that will always give a validation error.
  3. BeforeReadingPostedData is a triggered public event and Page.Validate() is called for the current validation group. If the CancelSubmit property is set to true a StaticValidator is added for all strings in the ErrorMessages array. Any validation errors to the XForm controls will also result in validation errors and the form posting is cancelled with a list of validation errors.
  4. BeforeSubmitPostedData is a triggered public event and any event handlers that sets CancelSubmit to true will cancel the form posting.
  5. The form data is sent to the specified channel. If the user is anonymous a cookie will be set to indicate that the form has been posted.
  6. AfterSubmitPostedData is a triggered public event.

XForms web controls

The following table shows the different controls and their corresponding HTML tags used while rendering themselves:

Web Control

HTML

Input

<input />

Select

<input type=”checkbox” />

Select1, with Rendertype.Full

<input type=”radio” />

Select1, with Rendertype.Minimal

<select></select>

Submit

<input type=”submit” />

TextArea

<textarea></textarea>

Secret

Not implemented yet

Sending form data

It is possible to send an XFormData object to different channels. A channel might be storage in the database, an e-mail address or a URL. The ChannelOptions property is used to specify one or several channels that the data will be sent to.

Channel Name

Description

Database

The entire XFormData object will be serialized and saved to the tblItem table in the database.

Email

The content of the form data is transformed using a predefined XSLT.

CustomUrl

The values for the form will be uploaded to a given URL using the System.Net.WebClient class.

FAQ

How do I work with form postings?

In EPiServer CMS the XForm class has several methods for accessing form data. GetPostedData can be used to list all form data objects that specifies certain criteria such as posted date, form and page ID. In EPiServer CMS there are overloads of this method that supports paging as well. GetPostedDataCount can be used to quickly get the number of users that have posted data to a form and GetPostedDataStatistics can be used to calculate statistics for a form directly in the database.

Can I retrieve previously posted data, modify it and save it?

It is possible to re-edit data that is posted to the database (or another custom location as long as you can load and save the XFormData object). To do this, create an XFormControl object and set its Data property to the XFormData object you want to load. The form will be loaded with the values from the posted data. If the data is posted to the database, the old data will be replaced in the database.

You could also load an XFormData object and modify the object programmatically. By using the Send method it is possible to store the modified content again.

Can I edit the appearance of a form?

There are two main ways to edit the appearance of a form.

  1. Edit the content of the form in the BeforeLoadingFormsEvent. If you do this, you should be aware that it might affect the behavior of the built-in form editor. The LoadFormsEventArgs class has a property, EditMode, that defines if the form is loaded in edit view. This makes it possible to only make changes to the form to the end user, thus not affecting the EPiServer CMS Edit mode.
  2. Attach to the ControlsCreated event for the XFormControl object. The content of the form is parsed and added to the Controls collection. The HTML content will be parsed as Literal controls and the XForm controls as the different controls in the EPiServer.XForms.WebControls namespace. There should not be any problems modifying the HTML content.

If you want to change the appearance of the XForm web controls, it is recommended that you do this by adding or modifying the attribute collection for the control. By using CSS and setting the class attribute for the control, you should be able to do a lot for the appearance of the form control. In EPiServer CMS there is a method, called ExtractXFormControls, that can be used to get an ArrayList containing the input elements for the form.

How do I send a customized e-mail?

When using the e-mail option for sending XFormData the content of the form data is transformed using an XSLT schema. Unfortunately it is not currently possible to specify a custom XSLT schema that is used to transform the form data to an e‑mail. You could still implement your own e-mail handling by adding custom logic to the BeforeSubmitPostedData event on the XFormControl web control. Before exiting your custom logic you should remove the e-mail option from the e.FormData.ChannelOptions property to ensure that the regular e-mail channel is not triggered.

If you simply set e.FormData.ChannelOptions to ChannelOptions.None you will lose any additional channels that the form data is sent to, for example, the Database Channel.

Working with XForms in MVC

When using XForms with MVC all required functionality are automatically injected into the controller when using the base class ActionControllerBase (which for example PageController<T> inherits from). Use the normal HTML-helper Html.PropertyFor in the view to render the XForm.

There are static events on the XFormActionHelper class for both BeforeSubmitPostedData and AfterSubmitPostedData to be able to listen and act on posted data via MVC for the whole site.

It is also possible to handle the posting in a method on the controller. To take more control over the posting, start by adding an XFormParameters instance to the PropertyFor: @Html.PropertyFor(x => x.CurrentContent.MyForm, new{ XFormParameters = new EPiServer.XForms.Util.XFormParameters() { PostAction = "Posted", SuccessAction = "Success", FailedAction = "Failed" } })

In the XFormParameters class, it is possible to specify which methods that should be used when posting the XForm, as well as the methods that should be used when the user gets validation errors, and when the XForm successful gets posted. The controller could look something like this when taking care of the post action:

public class XFormPageController : PageController<XFormPage>
{
    private XFormPageUnknownActionHandler _xformHandler;

    public XFormPageController(XFormPageUnknownActionHandler xformHandler)
    {
        _xformHandler = xformHandler;
    }

    public ActionResult Index(PageData currentPage)
    {
        return View(currentPage);
    }

    #region Success and failed actions

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Success(PageData currentPage, XFormPostedData xFormPostedData)
    {
        return View("Success", currentPage);
    }

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Failed(PageData currentPage, XFormPostedData xFormPostedData)
    {
        return View("Failed", currentPage);
    }

    #endregion

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult DoSubmit(XFormPostedData xFormpostedData)
    {
        return _xformHandler.HandleAction(this);
    }
}

Validation

Validation will be performed automatically when using the XFormHandler on the server side. To enable client validation, just add the HTML-helper EnableClientValidation in your view.

Comments