Ouse Creative Ltd

Intuitive Internet Solutions

blog - Getting started with Mura CMS - Building Forms

Mura CMS is a powerful content management system with enough out of the box functionality to get a website up and running relativly quickly and proffessionaly. It's also very flexible and allows developers to extend it functionality in almost any direction, however if you don't know where to start it can be a steep learning curve! But don't give up hope, in this article we're going to discuss the basics of Mura's forms module and look at how to extend Muras form Module to work with a custom form response!

Begin at the beginning...

So let's start with a brief tour of the Mura Form module! There are 2 ways to create a new form in Mura; the first being it's own form builder. This tool is geared towards non-techinal persons  who want to add simple forms to their website but don't want to get their hands dirty with any HTML. It's a simple point and click/ click and drag editor which can be used to build simple but effective general purpose forms. Simply click the the field types you want in your form, drag them into the order you want them to be in and your done! Well, nearly, both options allow you to add a confirmation message and an email address to send the form submissions to in addition to storing them within Mura.

The second method for creating a form in Mura is by selecting the by selecting the 'Add Form with Editor' button which will open up a WYSIWYG Editor instance asking for a title and some content, of course the content should contain a form. Unlike Mura's usual editor an extra toolbar is available for the various form controls. This method allows for greater flexibility at the expense of a little more complexity. Most of the time this is editor you want to be using.

...And keep going...

Using the the second method allows you to change the action of a form, this means that we can point our Mura form at a custom script or alternative page to perform a custom action. However! I would only reccomend doing this if you want to submit to a third party service, if you have been given some form code to embed for a newsletter sign-up or other service then simply create a new form, click 'source' and paste the code, enter a title, and  publish.

If however you are wanting to perform custom actions, before, or after Mura handles form then You will be wanting to hook into Mura's event model! The Mura event Model surrounding forms requires a bit of explanation before one can start hacking away. So below is an ordered list of the pertinent events for handling forms.

onForm{subType}BodyRender

This Event is the first (and only) rendering event for the form, (For those interested it originates from the mura.content.dataCollection.dataCollectionBean object) if you wish to implement your own custom logic for rendering your forms or specific subType of form then simply add this event to your site level or theme level event handler.

public function onFormBodyRender(required $) output=false returntype='string'{
  var theForm = $.event('formbean');
  var theFormBody = theForm.getBody();

  // Do some custom redering stuff with the body.
  return theCustomResponse;
}

Important! If you choose to do this, and you wish Mura to still handle the response to the data you must include the `display_objects/dsp_form_protect.cfm` within the body of your form, and your form must submit it's content ID along with its Site ID. A quick peek through Mura's code shows us that Mura uses a method on the 'dataCollectionManager' called 'renderForm' to perform this function so you could invoke that method in addition to your custom code.

public function onFormBodyRender(required $) output=false returntype='string'{
  var theForm = $.event('formbean');
  var theFormBody = theForm.getBody();

  // Do some custom redering stuff with the body.
  var theCustomResponse = theForm.getDataCollectionManager().renderForm({
    theForm.getContentID(),
    theForm.getSiteID(),
    theFormBody,
    theForm.getResponseChart(), // This is numeric flag.
    arguments.$.content('contentID'), // The content ID of the page serving the form.
    arguments.$ 
  });

  // And Mura has wrapped your form in all its required stuff
  // read the code here: 'requirements/mura/content/dataCollection/dataCollectionManager.cfc'
  // to ensure it doesn't conflict with your own custom code.
  return theCustomResponse;
}

Now we can display our forms with a little more control. This is useful for adding custom hidden fields, injecting custom javascript validations or setting up forms for AJAX submission! Hurrah! Now what happens when we actually want to submit the form...

onBeforeFormSubmitSave and onBeforeForm{subType}SubmitSave

A quick note, before we get into these events; when Mura processes the submission of a form, by default the submission is handled at the point on the page where the form is displayed. Therefore if  you have any custom code, display objects or event handlers that may redirect away from the page or manipulate the Form Scope before mura attempt to display the form your result may be skewed of missing entirely!

Back on track... Mura will execute both the onBeforeFormSubmitSave and onBeforeForm{subType}SubmitSave events in sequence, this event takes place before Mura persists the data, but after it has validated it. If your interested in whether Mura thinks the form data is valid then you can use the 'getErrors' method on the '$.event('formDataBean')' to view all the validation errors or you can just inspect the '$.event('acceptData')' property for a quick true/ false response and the '$.event('acceptError')' property for whichever error message Mura has deemed to blame for the validation failure. Armed with this knoweledge you can perform custom validations in the event. However! Mura doesn't check the 'acceptData' property when deciding whether or not to persist the data. It uses the 'getErrors' method, so to prevent mura from persisting the data you must call the 'setErrors' method with a struct containing an error name and message and then, if you want mura to display this message add the following snippet:

public function onBeforeFormSubmitSave($){
  var formBean = $.event('formDataBean');
  formBean.setErrors({'ugly': 'The data is too ugly, please prettify it.'});
  $.event('acceptData', 0); // Zero is false.
  $.event.set('acceptError', 'ugly');
}

onAfterFormSubmitSave and onAfterForm{subType}SubmitSave

These events are also fired in sequence, and are useful for responding to form submissions, I recommend using these events for custom post-form actions because the data has been persisted and therefore if you custom code misbehaves at least you still have your data. You also have access to a '$.event('formDataBean').get('formResult')' which contains information about the form submission and the save process, including fields, values and responseId. If your website has some business logic or internal process to trigger when the form is submitted and you want Mura to persist the data too this is the best place to put the code.

... Until you get to the end.

onFormSubmitResponseRender and onFormSubmitErrorRender,  onFormSubmitPollRender, and onBeforeFormSubmitRedirect

The next four events to look at are actually optional... I say that because they are invoked in a disply_object file (/display_object/datacollection/dsp_response.cfm) which can be copied into your own site or theme display_objects folder and override the default display mechanisms and subsequently prevent these two events from firing.  That said, if you want to make use of the event to customise the Mura default form response then add them to your event listener and ensure your return the custom output to be displayed. The first event to fire will be the 'onFormSubmitPollRender', it is fired if the submitted form is a poll, by default any response from your custom event handler will completely replace Mura's default output.

Next either 'onFormSubmitResponseRender' or 'onFormSubmitErrorRender' will fire depending on the value of the previously mentioned '$.event('formDataBean').getValue('acceptData')'. The latter event can be used to output a custom error message, again this will replace Mura's default error message. Mura does not re-display the form in the event of a validation error, this can often be frustrating when creating custom data collection forms so I would reccomend overriding this event to to output an error message and to invoke the $.renderEvent('onForm#bean.getSubType()#BodyRender') event to trigger a re-display of the form. 

The 'onFormSubmitResponseRender' is the happy path rendering event. By default this will simply output the form confirmation message set in form editor in a paragraph with the success class. If you, like me, like to reward users with a little more than a bit of thank you text you can either override this event to provide a more substantial follow on to the form or make use of the next and final event: 'onBeforeFormSubmitRedirect' in any of the previous events you can set a 'request.redirect_url' which will cause Mura to redirect the user to another page after the form has been submitted. So you 'onAfterFormSubmitSave' you can decide to set a redirect_url if the form has been succefully submitted and saved. Meaning rather than displaying a simple message you can send the user on to a different page entirely, but the 'onBeforeFormSubmitRedirect' is fired first.. why? I'm not sure seeing as you need to manually set the redirect_url in a prior event anyway any logging or processes you want to run could have been run prior to this point.. but there it is, feel free to find a use case for it!

And that concludes a deep-ish dive into what Mura does with forms, and what hooks are open to you to extend this functionality. Below is  Gist example of me using these events to create a Form that submits asynchronously! Try it yourself!

Article by David Polehonski, Lead Developer
8th December 2015
View more articles by David

More Articles...