Velocity forms

In this tutorial you learn how to develop a form in velocity without writing HTML.

In most websites user input is collected. This is regularly done by using HTML forms with input elements and submit buttons.

In velocity you can create your own HTML pages with input elements, but you might prefer using our built-in methods to create forms without writing a single line of HTML code. Advantages are:

  • All your forms have the same look and feel.
  • You do not have to worry about using the right CSS classes.
  • You do not have to worry about how the data submits have to be handled.
  • The submits are automatically validated and error messages are presented to the user in a uniform way.  
  • When you upgrade to a higher user interface version, no maintainance is needed.

For a simple form, containing just one text field, these advantages are not that big, but imagine a form, with several data types, like images, dates, tag lists, etc, these velocity methods can provide much efficiency gains and increased maintainability.

1. Creating a form and submit the data

Suppose you want to create a form on a class in your blueprint, called 'contact moment'. These are the steps:

  1. Create a page.
  2. Get this class.
  3. Create a record to store the data provided by your user.
  4. Get a form for this record, add a button, and render the form.

Here is the code example:

$document.surround()
#set($clazz = $application.getClazz('contact moment'))
#set($dialog = $session.newRecord($clazz))
#set($form = $service.newXForm($dialog))
#set($void = $form.addSubmit('Send', 'submit'))
$form.render()

Now your form is ready to preview, but the submit is not handled yet.

You can add more submit buttons on the form. Make sure each button has its own command. The command is used as value of the parameter 'cmd' in the request.

When the user submits the form, the same velocity file is called using ajax. To handle the submit, do the following:

  1. Get the submitted form from the request
  2. Get the dialog record from the form

Now you have three options:

  1. Replace the form html with something else, for example a success message.
  2. Replace the entire page with the result of a new url.
  3. Add validation warnings to the form

Here is the code example for situation A:

#set($form = $request.getXForm())
#set($dialog = $form.getRecord())
$form.replace("This is the submitted record<br>$dialog.toHTML()")

The complete example looks like this:

#set($cmd = $request.get('cmd'))
#if($cmd == 'submit')
    #set($form = $request.getXForm())
    #set($dialog = $form.getRecord())
    $form.replace("This is the submitted record<br>$dialog.toHTML()")
    #stop
#end

$document.surround()
#set($clazz = $application.getClazz('contact moment'))
#set($dialog = $session.newRecord($clazz))
#set($form = $service.newXForm($dialog))
#set($void = $form.addSubmit('Send', 'submit'))
$form.render()

Required fields are checked during the submit. Clazz validations (other then required fields) are not executed during the submit of the form. These are only checked during the save process (see below).

The replace method on $form replaces the form with the given html fragment in the current document. You can use any correct html fragment.

In option B, you replace the complete document by using Service.reload(String url). In this case the url is executed and the complete document is replaced by the response. I.e.

$service.reload('/succeededpage.vm').

For option C, see section 3, Other processing.

2. Saving the data

If you want to save the submitted data, just add a save button. When this button is pressed, the form does the regular checks:

  • incorrect data
  • required fields

If the data is not correct, the form is returned (using ajax) displaying the errors.

If the data is correct, the same script is called. In the script the method save is called on the form. Now the form validates the data.

If a validations fails, the form is returned (using ajax) displaying the errors.

If no validation failes, and the data is saved correctly, the succeeded page is called.

#set($cmd = $request.get('cmd'))
#if($cmd == 'save')
    #set($form = $request.getXForm())
    $form.save('/succeededpage.vm')
    #stop
#end

$document.surround()
#set($clazz = $application.getClazz('contact moment'))
#set($dialog = $session.newRecord($clazz))
#set($form = $service.newXForm($dialog))
#set($void = $form.addSubmit('Save', 'save'))
$form.render()

 

3. Other processing

You can also add more checks on the submitted data. Here is an example (for a blueprint with a class 'contact moment' and a field 'date'):

#set($cmd = $request.get('cmd'))
#if($cmd == 'submit')
    #set($form = $request.getXForm())
    #set($dialog = $form.getRecord())
    #if($dialog.get('date').before($application.newDate()))
        $form.addSubmitFailure('wrong date', 'date')
        $form.render()
        #stop
    #end
    $form.replace('Do something else')
    #stop
#end

$document.surround()
#set($clazz = $application.getClazz('contact moment'))
#set($dialog = $session.newRecord($clazz))
#set($form = $service.newXForm($dialog))
#set($void = $form.addSubmit('Send', 'submit'))
$form.render()

In line 9 the form is replaced by another html fragment in the current document. You can also replace the complete document by using Service.reload(String url). In this case the url is executed and the complete document is replaced by the response. I.e.

$service.reload('/succeededpage.vm').

 

4. Use your own layout

In the example above, your form has the same layout as defined in the blueprint of your application. In case you want a different layout for a particular situation, you can create your own layout.

#set($layout = $clazz.newLayout('single layout'))
#set($section = $layout.addParagraphSection('Paragraph 1')) 
#set($void = $section.addSectionField('product'))
#set($void = $section.addSectionField('first name'))
#set($void = $section.addSectionField('last name'))
#set($void = $section.addSectionField('email'))
#set($section = $layout.addParagraphSection('Paragraph 2')) 
#set($void = $section.addSectionField('note'))


You provide the new layout when you create the XForm. All other steps are the same.

#set($form = $service.newXForm($dialog, $layout))
#set($void = $form.addSubmit('Send', 'submit'))
$form.render()

Instead of paragraphs you can also use paging or tabs 

  • Paragraphs
    With paragraphs you create different sections within one page, they are shown vertically. You can use tabs within paragraphs.

    #set($section = $layout.addParagraphSection('Paragraph title')) 
  • Paging
    With the paging method you create different pages and you can seperate the form. It's possible to use paragraphs and tabs on pages. 

    #set($section = $layout.addPageSection('Page title')) 
  • Tabs
    When you're using tabs, you create different tabs within pages or paragraphs.

    #set($section = $layout.addTabSection('Tab title'))


Field label location
When you are defining your layout you can change the location of the label, this could vary per section but it’s not recommended because it will look messy. For the layout you can define a field label location. There are two different options:

  • Above
  • Left

Description location
When using a description there are three different ways you can show them:

  • As information button at the field label (this is the default)
  • As information button at the value
  • Above the value

5. Create a new class

Instead of using an existing class from the blueprint, you can also create your own class. First create a  class, next add fields.

 #set($clazz = $application.newDialogClazz())


Within this class you can define fields with the methods addField(String) and addField(String, String).

#set($void = $clazz.addField('name'))


You can define as many fields as you need. The variable $void is used when you're not going to use any other method on the field. 

You can also add some logic in creating the clas, like adding an email field only if there's no user record in the session.

#set($void = $clazz.addField('Full name'))

#if(!$session.getUserRecord())
    #set($emailField = $clazz.addField('E-mail', 'email'))
    $emailField.setRequired(true)
#end

#set($void = $clazz.addField('Photo', 'image'))
#set($void = $clazz.addField('Phone number', 'integer'))
#set($void = $clazz.addField('Street address'))
#set($void = $clazz.addField('City'))
#set($void = $clazz.addField('State'))
#set($void = $clazz.addField('Country'))
#set($void = $clazz.addField('Postal code'))

It's also possible to add a description to a field.

#set($photoField = $clazz.addField('photo', 'image')
$photoField.setDescription('Upload a photo')

The data of the form is submitted in the same way as the other examples, but since the class is not known in the blueprint, the data can not be saved in the database. You can do whatever you want with the submitted data, like printing it to screen.

#set($cmd = $request.get('cmd'))
#if($cmd == 'submit')
    #set($form = $request.getXForm())
    #set($dialog = $form.getRecord())
    $form.replace("This is the submitted record<br>$dialog.toHTML()")
    #stop
#end

#set($clazz = $application.newDialogClazz())
#set($void = $clazz.addField('Full name'))

#if(!$session.getUserRecord())
    #set($emailField = $clazz.addField('E-mail', 'email'))
    $emailField.setRequired(true)
#end

#set($void = $clazz.addField('Photo', 'image'))
#set($void = $clazz.addField('Phone number', 'integer'))
#set($void = $clazz.addField('Street address'))
#set($void = $clazz.addField('City'))
#set($void = $clazz.addField('State')
#set($void = $clazz.addField('Country'))
#set($void = $clazz.addField('Postal code'))

$document.surround()
#set($dialog = $session.newRecord($clazz))
#set($form = $service.newXForm($dialog))
#set($void = $form.addSubmit('Send', 'submit'))
$form.render()

 

6. Notes

When you want to test your file from the editor, do not use the preview option. Use the blue button at the top of the editor instead. This button opens the file by its own url. This is necessary to handle the submit correctly.