Validations / Overview

While frontend validations should never be a substitute for backend validations, we still sometimes need them to make simple checks that would spare us additional requests to the server. Webface.js offers a nice set of validations and also a simple way to display validation errors for the form fields that triggered them.

Suppose we have a simple comment form which only has a text field with the comment text and we want to make sure that this field is not null and also that the length of the comment is not less than 30 characters. Let's start with the html:

The first thing to notice here is that FormFieldComponent is more than just a textarea, but is actually a div, which wraps <textarea> and another <div> where our validation errors will show up. This is intentional, since in our app a text field is also responsible for displaying its own validation errors and it's only logical to combine this all into one component.

data-component-part="value_holder" attribute on the <textarea> element means that this dom element's value (or .val property) is now associated with the .value attribute of the component and whenever there are changes on either side, it gets updated on the other. We won't have to write any special code to make this work, FormFieldComponent already contains that functionality.

webface_rails has a form helper f.textarea, however Webface.js doesn't have or need a standard component for textareas, because you can just use FormFieldComponent with it, just like we do in our example, as FormFieldComponent has all the necessary functionality.

The <div> with data-component-attr="validation_errors_summary" obviously connects the component's attribute of that name to the .innerText property of that dom element. Again, no additional code is required - errors will just appear in it, you'll just need to style this div accordingly (red font color, perhaps!).

Now, we'll write the Javascript code for the CommentFormComponent that creates and runs validations:

export class CommentFormComponent extends extend_as("CommentFormComponent").mix(FormFieldComponent).with() {
  constructor() {
    super();

    this.validations = {
      "content.value": { "isNotNull"    : true },
      "content.value": { "isLongerThan" : 5    }
    };

    this.event_handlers.add({
      event: "click",
      role:  "submit",
      handler: (self,event) => {
        if(self.validate({ deep: true })) { // "deep" means validate child components too.
          // if validations pass - send a request to create new comment here
          console.log("Form is valid!");
        }
      }
    });

  }
}

If the text field is empty or it is 5 characters long or less, a list of all validation errors will be displayed in the appropriate dom element below the actual <textarea> field. If the validations pass, you will see a console message saying "Form is valid!"

Validations can be defined on both the component itself and on its children. In fact, the most likely scenario is defining validations on children, because:

  1. You will most likely be using standard Webface.js components for form fields and you don't really want to redefine them because of a single validation you need to add.
  2. Each form is different. Validations on one FormFieldComponent do not usually apply to other forms or even a field with another name which is the same Webface.js component. Thus, defining validations on a parent that contains those fields is the right way to go.

To define validations, you assign on object to component's this.validation property - you most likely want to do that in the constructor, but you can also do it some place else, as well as add or remove validations from this object dynamically. The syntax for defining validations is the following:

"[role].[attribute_name]": { "[validation 1 name]" : [argument], "[validation 1 name]" : [argument] }