Beyerz
Beyerz

Reputation: 828

jQuery off not working as I expected

Resolved!! see the end of the question for the result that I used

I am trying to write a function that can handle my apps paging by routes.

I have a function route() that is called with argument being the route(page) to move to.

route is an object that defines a model that it uses that handles its logic. This model contains 3 functions indexAction - This renders my view and appends it to my page. bindEvents - This is where I have placed all of my click events shutDown - This is instructions to run when moving to a new page

The router function first runs shutdown on the current page, here I have the $(selector).off() and $(selector).remove()

it then runs the enidexAction and bindEvents function.

My issue now is when I return to this page, all my click functions are running twice, then three times etc... its as if the off() never actually unbind from the anchor.

here is an example of one of my models

var NewPageModel = (function() {
var instance;
var modal = 'null';
function createInstance() {
    var object = {
        indexAction: indexAction,
        shutDown: shutDown,
        bindEvents: bindEvents
    };
    return object;
}

function indexAction (data, callback){
    var partials = {};
    ViewManager.render('pageName',{context:data}, partials,function(html){
        ViewManager.appendUnique('#xxx',html,'uniqueID');
        callback();
    });
}

/**
 * Remove modal
 */
function shutDown(){
    this.modal.off();
    this.modal.remove();
}

function bindEvents() {
    if(this.modal!='null'){
        return;
    }
    this.modal = $(PagerManager.pages.newGroup.id);

    this.modal.on('click','div.close', function () {
        shutDown();
    });

    this.modal.on('click', 'button.cancel', function () {
       shutDown();
    });

    this.modal.on('click', 'button.submit', function () {
       //code that submits form information
    });
}

return {
    getInstance: function () {
        if (!this.instance) {
            this.instance = createInstance();
        }
        return this.instance;
    }
};
})();

EDIT!! So I am still learning about the importance of scopes and how they can be applied to functions Here is the working code var NewPageModel = (function() { var instance; var modal; function createInstance() { var object = { indexAction: indexAction, shutDown: shutDown, bindEvents: bindEvents }; return object; }

function indexAction (data, callback){
    var partials = {};
    ViewManager.render('pageName',{context:data}, partials,function(html){
        ViewManager.appendUnique('#xxx',html,'uniqueID');
        callback();
    });
}

/**
 * Remove modal
 */
function shutDown(){
    this.modal.off();
    this.modal.remove();
    this.modal = null;
}

function bindEvents() {
    //This is confused logic, if I use off() in shutdown, I don't need to do this as I need to bind all the events again. hence in shutdown modal=null;
    if(!this.modal){
        return;
    }
    this.modal = $('#modal');

    this.modal.on('click','div.close', function () {
        shutDown().apply(this);
    }).bind(this);;

    this.modal.on('click', 'button.cancel', function () {
       shutDown().apply(this);
    }).bind(this);;

    this.modal.on('click', 'button.submit', function () {
       //here I only use the apply(this) if I use another internal function 
       //code that submits form information
    }).bind(this);;
}

return {
    getInstance: function () {
        if (!this.instance) {
            this.instance = createInstance();
        }
        return this.instance;
    }
};
})();

Upvotes: 0

Views: 156

Answers (2)

SeanCannon
SeanCannon

Reputation: 77966

In the spirit of keeping your syntax and just fixing the bug,

if(this.modal!='null'){ should be if(modal!='null'){

Because this.modal will be undefined at that condition and will just return.

In the spirit of fixing your code, you need to keep a reference to this or it will default to window in the browser.

var modal;
function createInstance() {
    var object = {
        modal : modal,
        shutDown: shutDown,
        bindEvents: bindEvents
    };
    return object;
}

function bindEvents() {
    if(this.modal){
        return;
    }

   // ..... //
    this.modal.on('click','div.close', function () {
        shutDown.apply(this);
    }.bind(this));

   // ..... //
}

Working demo :

http://jsfiddle.net/uyovgdj3/

Upvotes: 1

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93561

You are losing your this in the event handler functions (this will be the element clicked) so the shutDown is not getting the correct this:

this.modal.on('click','div.close', function () {
    shutDown();
});

should be:

var self = this;
this.modal.on('click', 'button.cancel', function () {
   self.shutDown();
});

e.g.

function bindEvents() {
    var self = this;
    if(this.modal!='null'){           /// <<<< !!!!!! WTF
        return;
    }
    this.modal = $(PagerManager.pages.newGroup.id);

    this.modal.on('click','div.close', function () {
        self.shutDown();
    });

    this.modal.on('click', 'button.cancel', function () {
       self.shutDown();
    });

    this.modal.on('click', 'button.submit', function () {
       //code that submits form information
    });
}

Note: I am ignoring the string comparison to null for now as I have no clue what you are doing there :)

As pointed out in comment by @Gurami Dagundaridze you can also retain the correct this using bind (I think the syntax goes like this):

    this.modal.on('click', 'button.cancel', shutDown.bind(this));

Upvotes: 2

Related Questions