Javascript variable is set in one function, but undefined in another function

481 Views Asked by At

I have the following Javascript,

eventManager: {
    $musicGenres : null, // $musicGenres is the selector for a div-container of inputs
    musicGenres : [],

    // Functions
    handle : function(selectors) {
        selectors = (typeof selectors === 'undefined') ? {
            'musicGenres' : '#musicGenres'
        } : selectors; // selectors default values...
        this.$musicGenres = $(selectors['musicGenres']);
        console.log("CHANGED $musicGenres TO " + this.$musicGenres);

        this.$musicGenres.find('input').change(this.reloadMusicGenres);
    },
    reloadMusicGenres : function() {
        console.log("IN FUNCTION $musicGenres IS " + this.$musicGenres);
    },

, call the function eventManager.handle() on my page and trigger the change-Event of one of those inputs, which outputs

CHANGED $musicGenres TO [object Object]
IN FUNCTION $musicGenres IS undefined

what I don't understand. I've set $musicGenres to a new value, but in the reloadMusicGenres-function it stays undefined. Even when I manually access $musicGenres' value through the console by typing in eventManager.$musicGenres it outputs the right value.

Could anybody help me? That really worries me.

4

There are 4 best solutions below

0
On BEST ANSWER

The context of this has changed. The easiest way to address the issue is to reference this outside the function, or pass a data object (as suggested by the two other fine posters, Richard Healy and AlliterativeAlice).

A third way is to explicity bind the context of this. Using jQuery, you can achieve this by calling $.proxy. So, this:

this.$musicGenres.find('input').change(this.reloadMusicGenres);

becomes:

this.$musicGenres.find('input').change($.proxy(this.reloadMusicGenres, this));

$.proxy will return a new function, where this will always be bound to eventManager. If you're interested in moving away from jQuery, Function.prototype.bind is your answer (Edit: an example of which is provided by Zoltan's answer)

Here's some links for documentation on how to use these fine functions:

jQuery proxy: https://api.jquery.com/jQuery.proxy/

Bind function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

0
On

As others already pointed out, your problem is context binding.

IMO the easiest way to fix your code would be to change this line

this.$musicGenres.find('input').change(this.reloadMusicGenres);

to this:

this.$musicGenres.find('input').change(this.reloadMusicGenres.bind(this));

This should solve your problem. No need to change anything else in your code.

0
On

Have you tried in the handle method:

var self = this;
this.$musicGenres.find('input').change(function () {      
     self.reloadMusicGenres();
});

Might be a scoping issue when the reloadMusicGenres function gets called.

0
On

You can pass the object to the change handler like this:

this.$musicGenres.find('input').change(this, this.reloadMusicGenres);

Then in reloadMusicGenres():

reloadMusicGenres : function(e) {
    console.log("IN FUNCTION $musicGenres IS " + e.data.$musicGenres);
}