Form system - CityWebConsultants/Iris GitHub Wiki

Iris includes a Form system. This allows for creating fully working HTML forms from simple JSON schemas, including submit handlers that work using the hook system, allowing other modules to hook into the form and extend it if necessary.

Registering a form

To register a form in Iris, use the hook_form_render__FORMNAME hook. Forms in Iris are rendered using the JSON Form library. The hook_form_render hook gets a data object containing a schema, form and value object that can be added to using the JSON Form field types. For example:


iris.modules.myModule.registerHook("hook_form_render__myForm", 0, function(thisHook, data){

  data.schema.title = {

    "type": "text",
    "title": "My title",
    "description": "Put a title here"

  }

  thisHook.pass(data)

})

Additional hooks in the chain can add additional fields so modules can alter this form or one provided by the core system if they need to.

View the JSON Form documentation to see what field types are available.

TODO: Describe field widgets in Iris. Widgets can be used to change how fields are rendered.

Rendering a form

To render a form on a page simply use an embed like:


{{{iris embed="form" formID="login"}}}

Additional parameters can also be passed through which are available in the thisHook object of the render function.


{{{iris embed="form" formID="login" myParam="hello world"}}}


Registering a validate handler

The hook_form_validate__FORMNAME hook can be used to register a validation hook. Here you would add any validation logic to determine the success or failure of this form. Parameters from the form are stored in thisHook.context.params To register a failed submission, extend the data object with an errors array. Each error in an object containing:

  • field (optional)
  • message

If the field id is specified, it will add an 'error' class to the field on the form that has failed validation. Messages will be displayed above the form.


iris.modules.myModule.registerHook("hook_form_validate__myForm", 0, function(thisHook, data){

  if (field == 'failed') {
  
    data.errors.push({
      'field' : 'field_example',
      'message' : 'This field does not pass validation'
    });
 
  }

  thisHook.pass(data);
});

Registering a submit handler

The hook_form_submit__FORMNAME hook can be used to register an action. Parameters from the form are stored in thisHook.context.params. There are 2 ways of ending a form submission, add a message(s) to the current form without a page reload, or redirect to a different page (or the same if you wish). This can be done by extending the data object with either:

  • messages (array of objects)
  • callback (string)

A message is an object containing the fields:

  • type (string)
  • message (string)

Types can be used for styling messages differently, eg, 'notice', 'info' etc.

Callback is a path, relative or absolute.


iris.modules.myModule.registerHook("hook_form_submit__myForm", 0, function(thisHook, data){

  // Do something with the form data stored in thisHook.context.params

  data.callback = '/new/path';

  // Or

  data.message.push({
    'type' : 'info',
    'message' : 'Successfully submitted.'
  });

  thisHook.pass(data);
})

Altering an existing form

By invoking hook_form_render with a rank of 1 or higher, it is possible to make changes to a form once the hook that initially created it has finished.

For example, in order to edit myForm and add a field:


iris.modules.myModule.registerHook("hook_form_render__myForm", 1, function(thisHook, data){

  data.schema.newfield = {

    "type": "text",
    "title": "My extra field",
    "description": "This extra field was added by another module!"

  }

  thisHook.pass(true)

});

Altering the submit handler of an existing form

By invoking hook_form_submit with a rank of 1 or higher, it is possible to make changes or even completely override how a form is handled.

Say we would like to count submissions of myForm:


iris.modules.myModule.registerHook("hook_form_submit__myForm", 0, function(thisHook, data){

  thisHook.pass(function(res) {

    iris.myModule.globals.myFormSubmissions.push(thisHook.context.params);

  })

})

Extending JSON form with custom fields

You may wish to add a custom field type to JSONForm or extend it in another way. For this the Iris forms module provides a iris.modules.forms.globals.registerWidget function that allows you to insert client side JavaScript that changes how JSON form runs. It simply takes a function that will be run on the client side and a name for the extension you're registering. Here's a simple example of a markup field. See JSONForm documentation for more information.


iris.modules.forms.globals.registerWidget(function () {

  JSONForm.elementTypes['markup'] = Object.create(JSONForm.elementTypes['text']);
  JSONForm.elementTypes['markup'].template = '<% if(value && !node.markup){node.markup = value} %><%= node.markup ? node.markup : node.schemaElement.markup  %>';
  JSONForm.elementTypes['markup'].fieldTemplate = true;
  JSONForm.elementTypes['markup'].inputfield = true;


}, "markup");

Running after form render

Since forms are rendered on the client side, you may wish to run some scripts once the form has been rendered on the page. For this, you can type a function to the window using the name of the form.

For example, in order to run a function after a form called myForm has rendered on the page, simply add the following to the front end of your site.


window.formComplete_myForm = function(){
  // Run this code once the form has rendered.
}

Running after all forms render

Once all forms have been rendered, a formsLoaded event is fired. This can be used as follows:


document.addEventListener("formsLoaded", function(){
  // Run this code once all forms have rendered.

});

Forms running without client side JavaScript

Automatically embedded forms are pre-rendered on the server side so that users without JavaScript enabled in their browser can use them. If your form uses AJAX or otherwise fails without clientside JavaScript enabled pass in a dynamicForm = true parameter with your form object in the hook_form_render__ hook. This bypasses the server side rendering.