0

I am trying to call a prototype method from a jquery event handler. I have the code like this:

$('#' + this.ID + ' .selMake').on('change', this.getCarModel());

I get an error saying: Uncaught TypeError: Object [object global] has no method 'getCarModel'

What am I doing wrong here?

8
  • @wootscootinboogie No it isn't, since that code isn't in a callback function.
    – Barmar
    Commented Sep 9, 2014 at 20:29
  • 1
    Related: stackoverflow.com/questions/24173440/save-access-to-this-scope
    – Travis J
    Commented Sep 9, 2014 at 20:35
  • 1
    You must pass a function to .on(), not the result of a call!
    – Bergi
    Commented Sep 9, 2014 at 20:35
  • Can you please show the full code, including the surrounding function?
    – Bergi
    Commented Sep 9, 2014 at 20:37
  • @Bergi Added the full code Commented Sep 9, 2014 at 20:40

3 Answers 3

1

The first thing you need to do is remove the parentheses from the function. What your code is currently expecting is for getCarModel to return a function which is then being called when the event is triggered.

It looks like this is what you would like to do:

 $('#' + this.ID + ' .selMake').on('change', that.getCarModel);

Not this:

 $('#' + this.ID + ' .selMake').on('change', that.getCarModel());

If you want to call the function that way, you can do as follows:

 var that = this;
 $('#' + this.ID + ' .selMake').on('change', function () {
     that.getCarModel();
 });

Above, you are passing an anonymous function as an argument which will execute the code inside of it.

In the functions above, the definition of this will depend on the element that triggered the event. If you want the definition of this to be tied to your this object, you can do the following:

The most simple, understandable way is to use the that variable:

var that; 
$('#' + this.ID + ' .selMake').on('change', that.getCarModel); // This will execute the function this.getcarModel

You can also use the bind method in browsers that support ES5.

$('#' + this.ID + ' .selMake').on('change', this.getCarModel.bind(this));
0
1

The second argument to .on() should be a function. You're calling the function when you bind the handler, not when the event occurs. It should be:

var self = this;
$('#' + this.ID + " .selMake').on('change', function() {
    self.getCarModel();
});

You need to use the local variable self so this will be saved in the closure. See

"this" keyword in event methods when using JavaScript prototype object

for details about this.

0

Use this code:

vehicleSelect.prototype.getCarMakes = function() {
  // Optional parameters
  var options = {};

  var select = $('#' + this.ID + ' .selMake'),
      that = this;

  select.on('change', function(e) {
    that.getCarModel();
  });

  // Callback function to be called when the API response is returned
  function success(res) {
    for (var i=0; i<res.makes.length; i++) {
      $("<option>",{
        value: res.makes[i].niceName,
        html: res.makes[i].name
      }).appendTo(select);
    }
    select.removeAttr("disabled");
    select + $(' option[value="placeholder"]').html('Select Make');
  }
  // Oops, we have a problem!
  function fail(data) { console.log(data); }
  // Fire the API call
  this.res.api('/api/vehicle/v2/makes', options, success, fail);
};

For why you can't just use select.on('change', this.getCarModel) see this question (which also provides alternative solutions).

0

Not the answer you're looking for? Browse other questions tagged or ask your own question.