Mostly about Javascript, Ruby on Rails and other web stuff

Sebastian's Blog

Form Validations With CanJS

During my time using CanJS I haven’t found a canonical way of doing form validations with it, so here I want to share the way I am doing them at the moment.

First let’s start with a model:

1
2
3
4
5
6
var Person = can.Map({
  init: function () {
      this.validatePresenceOf('firstName');
      this.validatePresenceOf('lastName');
  }
}, {});

This model is using the validation plug-in to mix-in the validation functions.

Then we need a control:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var Control = can.Control({

  init: function (ele, options) {
      this.person = new Person();
      this.errors = new can.Map();

      var args = {person: this.person, errors: this.errors};
      var view = can.view('view', args);
      this.element.html(view);
  },

  'form submit': function () {
      // get errors from person if any
      var errors = this.person.errors();

      // pass the errors to our errors observable
      this.errors.attr(errors, true);

      if (errors) {
          console.log(errors);
      } else {
          // proceed to saving here
      }
      return false;
  }

});

Note how I create a errors can.Map and pass it to the view. This map will allow me to show any validation errors to the user. In form submit we retrieve the errors from the form (using the validation plug-in) and pass those errors to the errors can.Map.

Our view looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/mustache" id="view">

  <form>
      <label for="first_name">First Name:</label>
      <input type="text" can-value='person.firstName' name="first_name" />
      {{showErrors errors 'firstName'}}
      <br>

      <label for="last_name">Last Name:</label>
      <input type="text" can-value='person.lastName' name="last_name" />
      {{showErrors errors 'lastName'}}
      <br>

      <input type="submit" value="Save" />
  </form>
</script>

Note the showErrors helper. Which looks like this:

1
2
3
4
5
6
7
8
Mustache.registerHelper('showErrors', function (errors, prop) {
  var attr = errors.attr(prop);
  if (attr) {
      return prop + ' ' + attr[0];
  } else {
      return '';
  }
});

This helper will display the error an error to the user if there is any.

Here is a fiddle with a complete example.

Comments