Fariman Kashani
Fariman Kashani

Reputation: 1024

addEventlistener to all new objects in javascript

I have a cat constructor and I want to add eventListener to all my cat objects, so when I click on them, the counter increases. I don't want to add events one by one by hand. Is there any way to add event to all new objects? Thanks

var counter = document.getElementById("counter").innerHTML;

var Cat = function(name , source , width) {
    this.name = name;
    this.image = new Image(width);
    this.image.src = source;
    document.body.appendChild(this.image);
}

var poplinre = new Cat("Poplinre" , "images/poplinre.jpg" , 500);
var chewie = new Cat("Chewie" , "images/chewie.jpg" , 500);

Upvotes: 1

Views: 54

Answers (3)

Arber
Arber

Reputation: 541

See Event Delegation.

Event delegation allows you to avoid adding event listeners to specific nodes; instead, the event listener is added to one parent.

How JavaScript Event Delegation Works

Upvotes: 0

krampstudio
krampstudio

Reputation: 3611

You can listen for click events globally and target only the images you want to. This way is called Event Delegation, this article gives you some explanation.

To be short, you listen the click event on a common parent node and targets only the wanted elements. In your situation you have to implement something like :

document.body.addEventListener('click', e => {
   if (e.target && e.target.nodeName === 'IMG' &&  e.target.classList.contains('cat')) {
       //only the image is targeted
    }
});

var Cat = function(name , source , width) {
    this.name = name;
    this.image = new Image(width);
    this.image.src = source;
    this.image.classList.add('cat'); 
    document.body.appendChild(this.image);
}

Upvotes: 1

T.J. Crowder
T.J. Crowder

Reputation: 1074038

You basically have two choices:

  1. Add the handler individually, within the Cat constructor

    function incrementCounter() {
        document.getElementById("counter").innerHTML = ++counter;
    }
    var Cat = function(name , source , width) {
        this.name = name;
        this.image = new Image(width);
        this.image.src = source;
        this.addEventListener("click", incrementCounter);
        document.body.appendChild(this.image);
    }
    
  2. Use event delegation: Give your cat images some identifying characteristic (such as a class name) and have a single handler on the container they're being added to (body in this case), and put the handler on body, but have it do the increment only when the event passed through one your cat images:

    document.body.addEventListener("click", function(e) {
        if (e.target.closest(".cat")) {
            document.getElementById("counter").innerHTML = ++counter;
        }
    });
    var Cat = function(name , source , width) {
        this.name = name;
        this.image = new Image(width);
        this.image.src = source;
        this.className = "cat";
        document.body.appendChild(this.image);
    }
    

#2 above uses Element#closest, which is vaguely new, but can be polyfilled for older environments.

Actually, in your specific case, you don't need Element#closest since img elements can't have descendant elements, so you could just look at e.target.className directly. closest is a more general solution (which also works here).

Upvotes: 1

Related Questions