Backbone 101: Model Validation Example

by kyllle

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.2/backbone-min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/3.0.3/normalize.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone-localstorage.js/1.1.16/backbone.localStorage-min.js"></script>
<h2 class="pg-heading">Model validation example</h2>
<p>Simply validates the `name` field making sure the user has input some text.</p>

<div class="js-ctn"></div>

<script type="text/template" class="js-contact">
    <input class="js-input" type="text" name="firm" placeholder="Please enter firm">
    <select class="js-input">
        <option value="all">All</option>
        <option value="123">123</option>
        <option value="456">456</option>
        <option value="789">789</option>
        <option value="000">000</option>
    </select>
    <input type="submit">
</script>

CSS

@import url(http://fonts.googleapis.com/css?family=Roboto:300,400,500);

* {
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}

body {
    font-family: Roboto;
    padding: 16px;
    line-height: 1.5;
    font-weight: normal;
    color: #ccc;
    background: #292929;
    font-size: 18px;
}

h1, h2, h3 {
    font-weight: normal;
}

.pg-heading {
    margin-bottom: 0;
}

a {
    color: #95baf6;
    transition: opacity .3s;
}

a:hover {
    opacity: 0.75;
}

input {
    border: none;
    height: 40px;
    outline: none;
    padding: 0 8px;
}



input[type=submit] {
    padding: 0 16px;
    background: #2196F3;
    color: white;
    transition: background .3s;
}

input[type=submit]:hover {
    background: #1E88E5;
}

input[type=submit]:active {
    background: #1976D2;
}

input[type=text] {
    transition: border-color .3s;
    border: 1px solid white;    
}

input.error {
    border: 1px solid #F44336;
}

JavaScript

console.clear();

// Set up contact model
var Contact = Backbone.Model.extend({
    
    defaults: {
        name: ''
    },
    
    validate: function(attrs) {
        var errors = [];
        
        console.log(attrs);
        
        if(attrs.name.trim().length === 0) {
            errors.push({
                name: 'name'
            });
        }
                
        return errors.length > 0 ? errors : null;
    }
});

// Set up contact view
var ContactForm = Backbone.View.extend({
    
    tagName: 'form',
    
    template: _.template( $('.js-contact').html() ),
    
    events: {
        'click input[type=submit]': 'onFormSubmit',
        'focus .error': 'onInputFocus'
    },
    
    initialize: function() {
        this.listenTo(this.model, 'invalid', this.onFormError, this);
    },
    
    render: function() {
        this.$el.html( this.template( this.model.toJSON() ) );
        
        return this;
    },
       
    onFormSubmit: function(event) {
        event.preventDefault();
                
        this.model.set({
            'name': this.$('.js-input').val()
        }, {
            validate: true
        });
    },
    
    onFormError: function(model) {
        console.log('validationError: The value returned by validate during the last failed validation.', model.validationError);
        
        model.validationError.forEach(function(error) {
            this.$('.js-input[name='+error.name+']').addClass('error');
        });
    },
    
    onInputFocus: function(event) {        
        $(event.currentTarget).removeClass('error');
    }
});

// Create some instances
var contact = new Contact();

var contactForm = new ContactForm({
    model: contact
});

$('.js-ctn').html(contactForm.render().el);