sçuçu
sçuçu

Reputation: 3070

First view undesireably renders from second view when an input field event triggered in Backbone app?

I have views each with a model and a template and one form model instance to render them from their respective templates. Form model instance is accessible from both view to render their templates. It is needed to update this form model instance on every character typed, and set the model of the current view of the two views with this form model instance. For this I have an keyup event on input elements in both views, which has different number of input views. Second view has all the same typed, named, id, input fields with the first view and some different ones.

When I am on the second view with more input fields and click and type a character in the input field both views have, the first view renders. Calling this.unbind() from one of the view before it routes to the other view did not work.

What is the reason for this? I do not have an event to render it when this is done. mainrouter:

    define([
    'jquery',
    'ratchet',
    'underscore',
    'backbone',

    'forms/formsdatamodel',
    'login/loginview',
    'register/registerview',

    'home/homeview',
    ],
    function($, Ratchet, _, Backbone, FormsDataModelInst, LoginView, RegisterView, HomeView){
        var MainRouter = Backbone.Router.extend({
            routes: {
                "": "render_home",              
                "login": "render_login",
                "register": "render_register"
            },
            initialize: function(){
                this.model = FormsDataModelInst;
                this.listenTo( this.model, 'change', this.render_home );//this solved render_home problem.
            },
            render_home: function(){
                if( this.model.get('loginp') == true ){ //show you app view for logged in users!
                    this.homeView = new HomeView();
                    this.homeView.render();
                }
                else { //not logged in!
                    Backbone.history.navigate("/login", {trigger:true});
                }
            },
            render_login: function(){ //display your login view
                this.loginView = new LoginView;
                //this.loginView.delegateEvents();
                this.loginView.render();
            },
            render_register: function(){ //display your register view
                this.registerView = new RegisterView;
                //this.registerView.delegateEvents();
                this.registerView.render();
            },
        });

        return MainRouter;
});

loginview:

    define([
    'jquery',
    'ratchet',
    'underscore',
    'backbone',

    'login/loginmodel',
    'text!login/logintemplate.html',

    'forms/formsdatamodel',

    ],
    function($, Ratchet, _, Backbone, LoginModel, LoginTemplate, FormsDataModelInst){
        var LoginView = Backbone.View.extend({

            el: $('body'),

            initialize: function(){
                this.model = new LoginModel();
            },

            template: _.template( LoginTemplate ),

            render: function(){ //display your login view
                this.$el.html( this.template( FormsDataModelInst.attributes ) );
            },
            events: {
                'keyup input#username' : 'updateModel',
                'click #loginbutton' : 'login',
                'click #renderregisterbutton' : 'render_register',
            },
            updateModel: function(e){
                e.preventDefault();
                var elm = e.target;
                FormsDataModelInst.set( elm.id, $( elm ).val() );
                this.model.set( FormsDataModelInst );

                console.log( "1-FormsDataModelInst:" + JSON.stringify( FormsDataModelInst.attributes ) );
                console.log( "2-this.model.set(...):" + JSON.stringify(this.model.attributes) );
            },
            login: function(e){
                e.preventDefault();
                this.model.save();

                console.log( "3-this.model.save():" + JSON.stringify(this.model.attributes) );
            },
            render_register: function(e){
                e.preventDefault();
                this.undelegateEvents();
                Backbone.history.navigate("/register", {trigger:true});
            },
        });

        return LoginView;
});

registerview:

    define([
    'jquery',
    'ratchet',
    'underscore',
    'backbone',

    'register/registermodel',
    'text!register/registertemplate.html',

    'forms/formsdatamodel',
    ],
    function($, Ratchet, _, Backbone, RegisterModel, RegisterTemplate, FormsDataModelInst){
        var RegisterView = Backbone.View.extend({

            el: $('body'),

            initialize: function(){
                this.model = new RegisterModel();
            },

            template: _.template( RegisterTemplate ),

            render: function(){ //display your login view
                this.$el.html( this.template( FormsDataModelInst.attributes ) );
            },
            events: {
                'keyup input#username' : 'updateModel',
                'keyup input#phone' : 'updateModel',
                'keyup input#email' : 'updateModel',

                'click #registerbutton' : 'register',
                'click #renderloginbutton' : 'render_login',
            },
            updateModel: function(e){
                e.preventDefault();
                var elm = e.target;
                FormsDataModelInst.set( elm.id, $( elm ).val() );
                this.model.set( FormsDataModelInst );

                console.log( "FormsDataModel:" + JSON.stringify( FormsDataModelInst ) );
                console.log( "this.model.set(...):" + JSON.stringify(this.model.attributes) );
            },
            login: function(e){
                e.preventDefault();
                this.model.save();

                console.log( "this.model.save():" + JSON.stringify(this.model) );
            },
            render_login: function(e){
                e.preventDefault();
                this.undelegateEvents();
                Backbone.history.navigate("/login", {trigger:true});
            },
        });

        return RegisterView;
});

Upvotes: 0

Views: 42

Answers (2)

sçuçu
sçuçu

Reputation: 3070

In mainRouter the listener:

this.listenTo( this.formsDataModelInst, 'change', this.render_home );

causes the problem of rendering loginview undesirebly on typing in registerview. Because on registerview keyup is bound to updateModels and this changes both registermodel and formsDataModelInst. this change triggers above written event which routes to the loginview and renders it.

Above listener is needed when loginp property of the formsDataModelInst changes, to decide which View to render as implemented in mainRouter render, but not changes in the other properties like the ones updated on keyup events on form.

Change it to:

this.listenTo( this.formsDataModelInst, 'change:loginp', this.render_home );

Upvotes: 0

machineghost
machineghost

Reputation: 35813

When you instantiate a View you setup event bindings on the el of that View. It doesn't matter if a different View also uses the same inputs; as long as the first View is still around its event handlers will continue to listen for and respond to events.

You had the right idea by trying to call this.unbind() ... except that Views don't have an unbind method. They do however have a undelegateEvents method, which I think is what you're looking for.

Upvotes: 1

Related Questions