0
votes

I have two views in Backbone. Register view and login view.

Login view

define(['text!templates/login.html'], function(loginTemplate) {
var loginView = Backbone.View.extend({
    el: $('#content'),

    events: {
        "submit form": "login"
    },

    login: function(e) {
        e.preventDefault();
        $.post('/user/login', {
                email: $('input.login-email').val(),
                password: $('input.login-password').val()
            }, function(data) {
                console.log(data);
            }).error(function(){
                $("#error").text('Unable to login.');
                $("#error").slideDown();
            });
    },

    render: function() {
        this.$el.html(loginTemplate);
    }
});

return new loginView;
});

Register view

define(['text!templates/register.html'], function(registerTemplate) {
var registerView = Backbone.View.extend({
    el: $('#content'),

    events: {
        "submit form": "register"
    },

    register: function(e) {
        e.preventDefault();
        $.post('/user/register', {
            emailaddress: $("input.email").val(),
            password: $("input.password").val()
        }, function(data, textStatus, jqXHR) {
            console.log(data);
        });
    },

    render: function() {
        this.$el.html(registerTemplate);
        this.delegateEvents();
    }
});

return new registerView;
});

And I undelegate the events from the currentView before switching in another. But the backbone view model calls the delegateEvent() function in its constructor. So, when I open the page in the browser and get the login view, and want to submit the form, there are two request, because the events from both views are delegated. Can I prevent the delegateEvent function in the constructor? I know, that I can use IDs and I will, but I don't like the 'mess' I want only the events from active views.

Thanks a lot.

Edit: here is my router, maybe it is the source of my "bug".

define(['views/register', 'views/login'], function(RegisterView, LoginView) {
var TestRouter = Backbone.Router.extend({
    currentView: null,
    routes: {
        "login": "login",
        "register": "register"
    },

    changeView: function(view) {
        if ( this.currentView != null ) {
            this.currentView.undelegateEvents();
        }
        this.currentView = view;
        this.currentView.render();
    },

    login: function() {
        this.changeView(LoginView);
    },

    register: function() {
        this.changeView(RegisterView);
    }
});

return new TestRouter;
});
2

2 Answers

2
votes

The issue here is that you're declaring the el property manually (el: $('#content')).

In clean code, you don't want to do this. Instead, you want to manage where the view is inserted dynamically in the router or in the parent view. Like so:

var view = new registerView();
view.render().$el.appendTo("#content");

It is very important to separate the layout from the views to keep your code maintainable and not falling on the issue you have here.

0
votes

The solution for my problem is:

When you do not construct all views at injecting them per dependency, they were not constructed and werent delegating their events.

Change

return new registerView;

to

return registerView;

in your view. Please notice the comment of Simon Boudrias and do not declare the views element in it.