Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I assign a function to Object.prototype.click?

Tags:

javascript

I know how to create dynamic elements and append them to existing ones, and how to create click events and attach them. See my snippet below

var container = document.getElementById("container");

var btn1 = document.createElement("button");
var btn2 = document.createElement("button");

btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";

btn1.onclick = function(){ console.log('button 1 clicked'); };   // this works fine
btn2.onclick = function(){ console.log('button 2 clicked'); };   

container.append(btn1);
container.append(btn2);
<div id="container"></div>

I am trying to mimic jQuery's .click() behavior. (I don't want to use jQuery, I just need a shorter way of assigning click events to dynamically created elements).

What I mean, is I would like to extend Object.prototype by adding a function that accepts a function as the parameter, and all it does behind the scenes is assign it to the object's .onclick property.

However, the code runs, but no click event is triggered, and no error is reported.

var container = document.getElementById("container");

var btn1 = document.createElement("button");
var btn2 = document.createElement("button");

btn1.click(function(){ console.log('button 1 clicked'); });  // this doesn't work
btn2.click(function(){ console.log('button 2 clicked'); });  // this doesn't work

btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";

container.append(btn1);
container.append(btn2);

Object.prototype.click = function(fn) {
   console.log('this function never gets executed');
   this.onclick = fn;
}
<div id="container"></div>

I can tell that my extension of Object.prototype.click has not been executed since the console.log() never happens.

Is it because Object.prototype.click is reserved? If so, why am I not being able to override its definition?

What am I doing wrong?

like image 603
Ahmad Avatar asked Dec 14 '22 13:12

Ahmad


1 Answers

There are two issues. First, you should assign to the prototype before you try calling btn1.click(), else the native .click() will be called. (The native .click() method of an element programatically triggers a click event on that element.)

The other problem is that btn1 is an element, not just an object, and HTMLElements have a click property on their prototype. So, even if you assign to Object.prototype.click, HTMLElement.prototype.click will be seen sooner in the prototype chain, and so your Object.prototype.click will be ignored. You'll have to either overwrite HTMLElement.prototype.click or HTMLButtonElement.click:

var container = document.getElementById("container");

var btn1 = document.createElement("button");
var btn2 = document.createElement("button");

HTMLElement.prototype.click = function(fn) {
   console.log('setting up click event');
   this.onclick = fn;
}

btn1.click(function(){ console.log('button 1 clicked'); });
btn2.click(function(){ console.log('button 2 clicked'); });

btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";

container.append(btn1);
container.append(btn2);
<div id="container"></div>

But mutating the built-in objects like this isn't very good practice and can lead to things breaking (such as if a library assumes that .click() will trigger the normal HTMLElement.prototype.click function) - you might consider assigning click property directly to the instance, rather than to the prototype:

var container = document.getElementById("container");

function myCreateElement(type) {
  const elm = document.createElement(type);
  elm.click = function(fn) {
    console.log('setting up click event');
    this.onclick = fn;
  }
  return elm;
}

var btn1 = myCreateElement("button");
var btn2 = myCreateElement("button");

btn1.click(function(){ console.log('button 1 clicked'); });
btn2.click(function(){ console.log('button 2 clicked'); });

btn1.innerHTML = "button 1";
btn2.innerHTML = "button 2";

container.append(btn1);
container.append(btn2);
<div id="container"></div>
like image 52
CertainPerformance Avatar answered Dec 28 '22 02:12

CertainPerformance