-2

As in this example, i like to create HTML elements and attach them onclick functions that is part of the object instance, any way to do this? when clicking it getting :

Uncaught ReferenceError: getObj is not defined

function DataSources() {

  var newCheckbox = document.createElement("input");
  newCheckbox.type = "checkbox";
  newCheckbox.addEventListener("click", function() {
    this.ds_checkbox("test2");
  }, false);

  document.getElementById("multi_select").append(newCheckbox);
  this.addLabel = function() {
    var label = document.createElement('label');
    label.innerHTML = "test";
    label.addEventListener("click", function() {
      this.getObj("test");
    }, false);
    document.getElementById("multi_select").append(label);
  }
  this.getObj = function(key) {
    console.log(key);
  };
  this.ds_checkbox = function(p) {
    console.log(key);
  };
}
var datasources = new DataSources();
datasources.addLabel();
<div id="multi_select">
</div>
user63898
  • 29,839
  • 85
  • 272
  • 514

1 Answers1

2

You have several options to solve your problem:

  • Store this in a variable at constructor execution time for further use by the event callback
  • Use an arrow function as the event callback, to retain this at declaration time
  • Use Function.prototype.bind() to force this value to the class instance

In the following code I used the first option with this line:

var self = this;

function DataSources() {

  var self = this;
  var newCheckbox = document.createElement("input");
  newCheckbox.type = "checkbox";
  newCheckbox.addEventListener("click", function() {
    self.ds_checkbox("test2");
  }, false);

  document.getElementById("multi_select").append(newCheckbox);
  this.addLabel = function() {
    var label = document.createElement('label');
    label.innerHTML = "test";
    label.addEventListener("click", function() {
      self.getObj("test");
    }, false);
    document.getElementById("multi_select").append(label);
  }
  this.getObj = function(key) {
    console.log(key);
  };
  this.ds_checkbox = function(key) {
    console.log(key);
  };
}
var datasources = new DataSources();
datasources.addLabel();
<div id="multi_select">
</div>

You could also replace event callbacks with arrow functions like this:

function DataSources() {

  var newCheckbox = document.createElement("input");
  newCheckbox.type = "checkbox";
  newCheckbox.addEventListener("click", () => {
    this.ds_checkbox("test2");
  }, false);

  document.getElementById("multi_select").append(newCheckbox);
  this.addLabel = function() {
    var label = document.createElement('label');
    label.innerHTML = "test";
    label.addEventListener("click", () => {
      this.getObj("test");
    }, false);
    document.getElementById("multi_select").append(label);
  }
  this.getObj = function(key) {
    console.log(key);
  };
  this.ds_checkbox = function(key) {
    console.log(key);
  };
}
var datasources = new DataSources();
datasources.addLabel();
<div id="multi_select">
</div>
Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • Thank you very much it worked, can you explain why i need to save "this" as self? – user63898 Jul 12 '21 at 14:15
  • 1
    Because in a regular (not arrow) function, `this` is being evaluated at execution time of the current function, not taking into account the surrounding context. On the other hand, a variable can be resolved in the surrounding context thanks to JavaScript's closures. – Guerric P Jul 12 '21 at 14:27