Tukurai Zeal
Tukurai Zeal

Reputation: 3

Binding events to functions within objects

I'm running into a peculiar issue with jQuery/JS in general.

I'm working on a JS file that let me create portlets for a client site. I'm using SignalR to communicate changes to the users.

The following piece of code gives me a bit of a headache as to why it won't work.

Eenheden: function (poPortlet) {
        this.moPortlet = poPortlet;
        this.Init = function () {
           $(this.moPortlet).find('.portlet-title').text($(this.moPortlet).attr('data-cpv-type') + ' Eenheden')
        };
        this.BindHub = function () {
           CPV.moHub.on('onEenheidUpdate', this.Events.Update);
        };
        this.Events = {
           Update: function (pnId, psStatus) {
              CPV.Log('Error', 'Update: ' + pnId + ' ' + psStatus);
           }
        };
     }

I am trying to bind the function this.Events.Update on the SignalR event onEenheidUpdate. Instances of these Eenheiden objects are not unique on the pages. The idea is that they contain the same data, but can get filtered, creating a different portlet depending on some configs.

My problem is that the onEenheidUpdate function doesn't trigger the proper event. I want to do it like this so I can use references I set for the unique object, such as the jQuery object I set on initialization.

Upvotes: 0

Views: 29

Answers (1)

JoshWillik
JoshWillik

Reputation: 2645

Problem

Your problem is that when jQuery or javascript in general triggers an event callback, the "context" (value of this) is changed. For example

var MyModule = {
    init: function () {
        $('.amazing-element').on('click', function () {
            // This breaks because `
            // `this` is not MyModule
            // When the callback is triggered
            // `this` is `<p class="amazing-element"></p>`
            this.onClick()
        })
    },
    onClick: function () {
        console.log('wee, I was clicked')
    }
}

Function.prototype.bind to the rescue!

var MyModule = {
    init: function () {
        $('.amazing-element').on('click', function () {
            this.onClick()
        }.bind(this))
        // ^ here we bind the context of the callback to the
        // correct version of `this`.
    },
    onClick: function () {
        console.log('wee, I was clicked')
    }
}

So your exact example would look like:

Eenheden: function (poPortlet) {
    this.moPortlet = poPortlet;
    this.Init = function () {
       $(this.moPortlet).find('.portlet-title').text($(this.moPortlet).attr('data-cpv-type') + ' Eenheden')
    };
    this.BindHub = function () {
       CPV.moHub.on('onEenheidUpdate', this.Events.Update.bind(this));
                                                      // ^ change here
    };
    this.Events = {
       Update: function (pnId, psStatus) {
          CPV.Log('Error', 'Update: ' + pnId + ' ' + psStatus);
       }
    };
 }

Upvotes: 2

Related Questions