FirstSpirit <RULES>!

One of the great new features of FirstSpirit 5 is the possibilty to create dynamic forms. You can find a lot of information about what you can do with these in the rules section in our ODFS (scroll down on the page to find a demo project with lots of examples).

This article will help you get started with this feature and gives examples ranging from enabling/disabling input components to sophisticated ways of checking for mandatoy fields concerning the translation status of the current page.

A project containing the ready to use examples from this article is attached by the name of example_project.tar.gz.

Enable or disable input components

Our goal is to provide the possibility to align an image in a section only if the editor has actually selected an image. Therefore the form is rather lean in the beginning only allowing the image selection and will be extended with further options later once the editor made a selection.

Technically we use a FS_REFERENCE input component named "st_image" to specify the image and a CMS_INPUT_RADIOBUTTON named "st_imageAlign" to set the desired alignment. You create the form as usual and then switch to the rules tab of the section template to add the following rule:

<RULES>
<ON_EVENT>
<WITH>
<NOT>
<PROPERTY source="st_image" name="EMPTY" />
</NOT>
</WITH>
<DO>
<PROPERTY source="st_imageAlign" name="EDITABLE" />
</DO>
</ON_EVENT>
</RULES>

Using rules we can get and set properties of input components. For this specific example you must put the logic inside an <ON_EVENT>-tag to have it evaluated everytime the editor performs an action in the form. The rule is automatically interpreted when locking the event and on every relevant change event thereafter. Every rule must have a <WITH>-part determining a value that is in turn used in the <DO>-part, the second mandatory part of a rule, to set a property.

The rule above takes the negated boolean value of st_image.isEmpty and sets it to the editable property of "st_imageAlign". This enables the image alignment component as long as the image component is not empty. Or, in pseudo code:

st_imageAlign.editable = !st_image.isEmpty;

Display or hide elements

The next example explains how to hide a complete CMS_GROUP-tag named "cg_image" based on editor actions. In this example we are using a CMS_INPUT_TOGGLE named "st_displayImage" to provide a possibility to the user to activate / deactivate using an image for this section:

<CMS_INPUT_TOGGLE name="st_displayImage" type="checkbox" hFill="yes" useLanguages="no">
<LANGINFOS>
<LANGINFO lang="*" label="Display Image?"/>
</LANGINFOS>
</CMS_INPUT_TOGGLE>

With the toggle in place we can now create the rule on the rules tab:

<RULES>
<ON_EVENT>
<WITH>
<EQUAL>
<PROPERTY source="st_displayImage" name="VALUE" />
<TRUE/>
</EQUAL>
</WITH>
<DO>
<PROPERTY source="#form.cg_image" name="VISIBLE" />
</DO>
</ON_EVENT>
</RULES>

We do have a special situation in this example as CMS_GROUP and likewise CMS_LABEL is a design element and does not have the same properties as other input components. To address this element we can use the #form-object and dot-notation to get the CMS_GROUP-tab by its name.

The rule above features the mandatory parts <WITH> and <DO> again. This time the <WITH>-part is used for a comparison, to determine the value for the <DO> part. We simply set the status of the toggle (true or false) for the visibile property of the CMS_GROUP to only show the image input components when the editor wants to by setting the toggle. Or, in pseudo code:

#form.cg_image.visible = (st_displayImage.value == true);

Validate editors’ input

Up next: Validation of editors’ input. On the one hand this can be used to help the editor by giving information about malformed inputs to allow him or her to check it, on the other hand this can be used to make fields mandatory or only allow input of a specifically given type.

To make a page title "pt_title" mandatory for example you could use the following rule:

<ON_SAVE>
<WITH>
<NOT>
<PROPERTY source="pt_title" name="EMPTY" />
</NOT>
</WITH>
<DO>
<VALIDATION>
<PROPERTY source="pt_title" name="VALID" />
<MESSAGE lang="*" text="The ‘Page Title’ can not be empty!" />
</VALIDATION>
</DO>
</ON_SAVE>

This rule checks the empty property like in the first example to determine if the editor filled the "pt_title" component with any input at all. Our <DO>-part is a bit different in this case as we want to perform a validation in this case. The validation reacts to the value determined in the <WITH>-part and displays an error message to the editor should the condition not be met.

Basically we use the negated value of pt_title.isEmpty again and if this results in false, the given message is displayed to the editor. Or, in pseudo code:

pt_title.valid = !pt_title.isEmpty;

Did you notice how <ON_EVENT> was changed to <ON_SAVE>. The event listening as described above is still the same, but in this case an invalid input prevents saving the changes.

This rule provides the same behaviour as setting allowEmpty="no" on the input component but is more flexible and the preferred way to check mandatory fields as of FirstSpirit 5.0.

Check the input length only for the master language

Most of the time it is not enough to simply check whether a field is empty or not but also how long the input is. Extending our example above we now want to check if the length of the input is between 4 and 25 characters. To make things more interesting we only require this length for the master language and ignore all others.

<ON_SAVE>
<IF>
<EQUAL>
<PROPERTY source="#global" name="MASTER" />
<PROPERTY source="#global" name="LANG" />
</EQUAL>
</IF>
<WITH>
<AND>
<GREATER_THAN>
<PROPERTY source="st_headline" name="LENGTH" />
<NUMBER>4</NUMBER>
</GREATER_THAN>
<LESS_THAN>
<PROPERTY source="st_headline" name="LENGTH" />
<NUMBER>25</NUMBER>
</LESS_THAN>
</AND>
</WITH>
<DO>
<VALIDATION>
<PROPERTY source="st_headline" name="VALID" />
<MESSAGE lang="*" text="The ‘Headline’ must be between 4 and 25 characters long!" />
</VALIDATION>
</DO>
</ON_SAVE>

First of all we check if we are currently using the master language in the <IF>-part. This precondition check is done every time the rule is evaluated. If false is returned, further evaluation of this rule is cancelled. If true is returned, the <WITH>-part is called as described above. If we use the wrong language, the <WITH>-part is not evaluated when changes are made.

In the <WITH>-part we compare the content of the input component with the rules we specified. This could also be done using regular expressions in a <MATCHES/>-tag, please refer to the documentation if you are interested in using these. Last but not least the result of the comparison operation is used to display an error message to the editor in case the rule does not match. Explaining this rule in pseudo code:

if (current_language == master_language) {
pt_headline.valid = pt_headline.length > 4 && pt_headline.length < 25;
}

Mandatory fields with complex logic

Finally a rather sophisticated example to show further possibilites and get your creativity going. In this example the input component "st_text" is supposed to be mandatory and needs to contain more than 10 characters but only if the the page is marked as "Page fully translated for this language" and the section is marked as "Generate section in the output".

<ON_RELEASE>
<WITH>
<NOT>
<AND>
<NOT>
<MATCHES regex=".{10,}">
<PROPERTY source="st_text" name="VALUE" />
</MATCHES>
</NOT>
<PROPERTY source="#global" name="TRANSLATED" />
<PROPERTY source="#global" name="INCLUDED" />
</AND>
</NOT>
</WITH>
<DO>
<VALIDATION>
<PROPERTY source="st_text" name="VALID" />
<MESSAGE lang="*" text="The ‘Text’ length must be over 10 characters!" />
</VALIDATION>
</DO>
</ON_RELEASE>

In the <WITH>-part we check the length of the "st_text" field (this time with a regular expression as mentioned in the previous example) and addtionally consider the properties TRANSLATED and INCLUDED of the #global object which represents everything not related to the form. We do not check these properties in a precondition <IF>-part because this would lead to a "one way situation": Trying to set the status from invalid (back to) to valid by unchecking one of the TRANSLATED or INCLUDED boxes or by fulfilling the length restriction would not be possible. That is because the precondition check would return false and thus cancel the evaluation of the <WITH>-part - which is responsible for changing the status back to "valid". This is a common mistake by the way! As a rule of thumb you should almost never use properties in the precondition the editor can change.

The whole process in pseude code could be expressed like this:

st_text.valid = !(!st_text.value.match(".{10,}") && #global.translated && #global.included);

Conclusion

As you can see from the examples in this article: The rules or dynamic forms functionality of FirstSpirit 5 is really powerful. You can work with a lot of status information and properties of the form fields and your current context to realize even complex rules. Implementing proper rules in your project not only helps to keep the data clean but can also help the editor in many ways when editing content.

An upcoming article on Inside FirstSpirit will be a follow-up to this one explaining ValueServices. ValueServices provide means to store the actual validation logic outside of the rules tab inside a FirstSpirit module programmed in Java to allow even more powerful functionality. Stay tuned!

Did you already work with dynamic forms in one of your projects? Share your use cases and solutions with the community, we would love to see what you come up with!