RactiveJS : Creating simple contact form with validation

February 9, 2016

After reading this article you will be able to:

  • Create html form
  • Use Ractive.js two-way binding
  • Use Ractive.js to create reusable components

This article will show you how to create component that you can reuse on your website. In this example I will use contact form component made in Ractive.js and Bootstrap. You can find links to Ractive.js and Bootstrap at the end.





Step by step instruction

Component template

Let’s begin with template. To create template for Ractive.js you must use <script> tag and assign an unique ID to it. This ID will be used as a refence in Ractive.js code. Within this tag I created simple form using Bootstrap classes.

<div id='main'></div>
    <script id='contactFormTemplate' type='text/html'>
     <div class='container'>
      <p class='head'>Do you want us to send our offer to you?</p>
      {{#if !isVisible}}
       <button class='btn btn-default btn-lg' on-click='showForm'>Yes I do</button>
      {{else}}
      <form>
       <div class="form-group">
        <label for="name" class='labels'>Your name</label><br>
        <input type="text" class="form-control {{class}}" id="userName" placeholder="John Smith" value='{{name}}'>
       </div>
       <div class="form-group">
        <label for="exampleInputEmail1">E-mail address</label><br>
        <input type="text" class="form-control {{class}}" id="userEmail" placeholder="[email protected]" value='{{email}}'>
       </div>
       <div class="form-group">
        <label for="phoneNumber">Phone number</label><br>
        <input type="tel" class="form-control" placeholder="0 800 911 1488" value='{{phoneNumber}}'>
       </div>
       <div class="checkbox">
        <label>
         <input type="checkbox" on-click='websiteExists'> Check if you have a website
        </label>
      </div>
      {{#if userHasWebsite}}
       <div class="form-group">
        <label for="websiteAddress">Website URL</label>
        <input type="text" class="form-control" id="websiteAddress" placeholder="http://example.com" value='{{url}}'>
       </div>
      {{/if}}
       <button class="btn btn-primary send" on-click='submitForm'>Send</button>
       <button class="btn btn-danger cancel" on-click='showForm'>Cancel</button>
      </form>
      {{#if success}}
       <div class='alert alert-success'>
        <p>Thank you for registration.<br> We will contact you very soon.
      </p>
      </div>
      {{/if}}
      {{#if registrationFailed}}
       <div class='alert alert-danger'>
       <p>Please fill all required fields.</p>
      </div>
      {{/if}}
      {{/if}}
     </div>
    </script>

This is a simple form which uses bootstrap classes and Ractive’s on-click event handlers. You can also notice, that we use two-way binding in value property. For example {{name}} will allow us to validate and use data that user type. Next thing you should notice is {{#if !isVisible}}. This is Ractive’s conditional section. It simply shows or hides data according to isVisible variable value. I use this value to show or hide call to action button. When you click that button, value of isVisible changes to true and our form is now visible. To do this, we use function named showForm.

'showForm': function(event) {
        self.toggle('isVisible');
        self.set({
          name: '',
          email: '',
          phoneNumber: '',
          url: '',
          success: false,
          class: '',
          registrationFailed: false,
          userHasWebsite: false
        })
        event.original.preventDefault();
      }

Beside changing value of variable, (self.toggle('isVisible');), this function also clears every field in form. You should notice that I use event.original.preventDefault() to stop browser reloading.

When you click on the checkbox, next field should appear. It happens because checkbox has assigned a on-click function named websiteExists. This function is just a few lines of code:

'websiteExists': function() {
        self.toggle('userHasWebsite');
        self.set('url', '');
 }

It only toggles value of variable userHasWebsite and clears form when you click checkbox again. {{#if userHasWebsite}} does the same as {{#if isVisible}}, except it shows or hides another field in a form. As you can see, conditional sections can be nested in Ractive.js which is very helpful.

Next thing in our template are two buttons. First button calls the function named submitForm, and the second calls function showForm which simply hides our form. Now let’s analyze submitForm function.

'submitForm': function(event) {
        var name = self.nodes.userName.value;
        var email = self.nodes.userEmail.value;
        if (name == '' || email == '') {
          self.set({
            registrationFailed: true,
            class: 'empty-form'
          });
        }
        else {
          self.set({
            success: true,
            registrationFailed: false,
            class: 'filled-form'
          });
          var user = {
            name: this.get('name'),
            email: this.get('email'),
            phoneNumber: this.get('phoneNumber'),
            url: this.get('url')
          };
          // you can add this user to database for example
          console.log(user);
        };
        event.original.preventDefault();
      },

This function validates if required fields are filled. In this example I requiere user to type his name and email. Other fields are optional. If validation passes or not, user will see success or warning message and fields will be highlighted. When validation passes our code also created a object named user which contains all data that user typed in form. You can use it in your e-mail service, database etc. In above example, I simply log this data to console. {{#if success}} and {{#if registrationFailed}} are variables used as before to show or hide some html contente. In this case they are supposed to show user the succes or warning message after he fill the form. Simple.

The JS code

In our JS code we will use functions I mentioned earlier. See code below:

var ContactForm = Ractive.extend({
  oninit: function() {
    var self = this;
    self.set('isVisible', false);
    self.on({
      'showForm': function(event) {
        self.toggle('isVisible');
        self.set({
          name: '',
          email: '',
          phoneNumber: '',
          url: '',
          success: false,
          class: '',
          registrationFailed: false,
          userHasWebsite: false
        })
        event.original.preventDefault();
      },

      'submitForm': function(event) {
        var name = self.nodes.userName.value;
        var email = self.nodes.userEmail.value;
        if (name == '' || email == '') {
          self.set({
            registrationFailed: true,
            class: 'empty-form'
          });
        }
        else {
          self.set({
            success: true,
            registrationFailed: false,
            class: 'filled-form'
          });
          var user = {
            name: this.get('name'),
            email: this.get('email'),
            phoneNumber: this.get('phoneNumber'),
            url: this.get('url')
          };
          // you can add this user to database for example
          console.log(user);
        };
        event.original.preventDefault();
      },

      'websiteExists': function() {
        self.toggle('userHasWebsite');
        self.set('url', '');
      }
    });
  }
})

var form = new ContactForm({
  el: '#main',
  template: '#contactFormTemplate'
});

To create a component use Ractive.extend. Within you should use all the code you want to be reusable in multiple places on your website. You can see our showForm, submitForm and websiteExists I showed in code in earlier section of this article. The new things are:

oninit – event fired when the instance is ready to be rendered

self.set('isVisible', false) – variable isVisible defaults to false in our case

self.on({}) – We place our on-click event handlers within this

Last thing we need to do to use our code is create a new instance of our component. To do this, type:

var form = new ContactForm({
  el: '#main',
  template: '#contactFormTemplate'
});

el – place where we want to render our template

template – html ID or name variable name of our template

You can create multiple contact forms using just one script. All you have to do is create a new object and assign new el data to it.

Using CSS

My CSS code is simple and only styles form, buttons and messages.

.container {
  text-align: center;
}

.form-control {
  width: 400px;
  margin: 0 auto;
}

.send {
  width: 250px;
}

.cancel {
  width: 125px;
  margin-left: 25px;
}

.head, .sub {
  margin-bottom: 35px;
}

.head {
  font-size: 2em;
}

.sub {
  font-size: 1em;
  font-weight: 600;
}

.empty-form{
    border: solid 1px red;
}

.filled-form {
    border: solid 1px green;
}

.alert {
  margin: 0 auto;
  left: 0;
  right: 0;
  width: 400px;
}

Check rest of the code at https://jsfiddle.net/goleksy/yarhgnz8/

Resources:

Kuba Wyrobek Founder, Meteor Developer
Grzegorz Oleksy Junior Meteor Developer