5
\$\begingroup\$

I am trying to create simple registration form with Backbone. I need to validate fields on blur, and whole form on submit.

HTML:

<form>
        <div><input name="name" type="text" placeholder="Name"/></div>
        <div><input name="surname" type="text" placeholder="Surname"/></div>
        <div><input name="email" type="text" placeholder="Your mail"/></div>
        <div><input name="password" type="password" placeholder="Password"/></div>
        <div><input name="pagename" type="text" placeholder="Page name"/></div>

        <input type="submit" value="Go"></input>
</form>

Model:

app.__definitions.models.Signup = Backbone.Model.extend({
    url: '/app/signup',

    defaults: {
            name: '',
            surname: '',
            email: '',
            password: '',
            pagename: ''
    },

    validateOne: validator.validateOne,

    validate: function(fields) {
            var result = validator.validateAll(fields);
            if (result !== true) return result;
    }
 });

View:

app.__definitions.views.Signup = Backbone.View.extend({
    el: $('form'),

    events: {
        'submit': 'onFormSubmit',
        'change input[type!="submit"]': 'onInputChange',
        'blur input[type!="submit"]': 'onInputChange',
        'focus input': function(e) {
                this.resetInputErrors(e.target);
        }
    },

    templates: {
            'error': _.template('<span class="error"><%=error%></span>')
    },

    initialize: function() {
            this.model = new app.__definitions.models.Signup();

            this.model.on('invalid', this.onModelInvalid, this);
    },

    getInput: function(name) {
            return this.$el.find('[name="' + name + '"]');
    },

    onModelInvalid: function(model, errors) {
            var _this = this;
            _.each(errors, function(error, name) {
                    _this.showInputErrors(_this.getInput(name), error);
            }) 
    },

    onFormSubmit: function(e) {
            e.preventDefault();
            var model = this.model;

            this.$el.find('input[name]').each(function() {
                    model.set(this.name, this.value);
            })
            this.model.save();
    },

    onInputChange: function(e) {
            this.model.set(e.target.name, e.target.value);
            var result = this.model.validateOne(e.target.name, e.target.value);
            if (result !== true) this.showInputErrors(e.target, result)
    },

    resetInputErrors: function(target) {
            var $target = $(target);
            $target.removeClass('incorrect')
            $target.parent().find('.error').remove();
    },

    showInputErrors: function(target, errors) {
            var $target = $(target);
            var errorsHTML = '';

            this.resetInputErrors(target);

            for (var i = 0; i < errors.length; i++) {
                    errorsHTML += this.templates.error({error: se.errors.get(errors[i])});
            }

            $target.addClass('incorrect'); 
            $target.parent().append(errorsHTML);
    }
    });

Init:

 app.views.Signup = new app.__definitions.views.Signup();
 app.routers.Router = new app.__definitions.routers.Main({hashChange: true}); 

Questions:

  1. Do I understand right how to make Backbone application?
  2. Where is the mistakes? What can I do better or clearer?
  3. Is there a better way to connect model with inputs on my form, or my getInput is ok?
  4. In my case I don't need to use the collection? Am I right?
\$\endgroup\$
2
\$\begingroup\$

Generally it looks like your know what your doing, maybe you could be more efficient by removing the blur event since you wouldn't need to save/validate if the input is already populated or left empty, this will also save you calling onInputChange twice when an input is changed.

Backbone will automatically create this.$el from the el property so you can just do.

el: 'form' and then this.$el would be created for you.

Finally i would use listenTo rather than on for example.

this.model.on('invalid', this.onModelInvalid, this);

would be done like this using listenTo.

this.listenTo(this.model, 'invalid', this.onModelInvalid);

This allows you to keep track of events on the object and then remove them all at once later on.

\$\endgroup\$
-1
\$\begingroup\$

I don't know too much about backbone, but here are my tips, i don't like, why?

1 - This is ugly: app.__definitions.models.Signup, i don't like to use globals, you should avoid it, and "Signup" what? your app i suppose but if you've another "sign up" in your app what you would call it? Ok, maybe you just have one, but try to explain more what you want in your variables.

2 - You're manipulating too much DOM elements in your methods, avoiding then to reuse them.

3 - Use more dependency injection, you're using unknown objects inside your methods, do you know about Law of Demeter (LoD) or principle of least knowledge ?

4 - One function one thing, you're doing too much inside of your functions.

like i said before, i don't know too much about backbone, but if this framework doesn't encourages you to modularize your code, run to another framework.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.