Search code examples
javascriptoopecmascript-6constructoraddeventlistener

Multiple event listeners being added to dynamically created elements


I am creating and appending elements via class object constructor with a button press, and need each individual element created to have an event listener that will call a method from a class to return the values of the object tied to the element.

Everything seems to work fine when I have a single element that was created. When I have two or more elements, it will output n results where n = the amount of elements that were created. 4 elements created = 4x the outputs, which ruins anything that I want to do with the data output.

For example, if I have one element that has the properties of square and red, then clicking it correctly outputs square and red. But if I add an element with the object properties of circle and green, then clicking on EITHER element will output both 'square red' and 'circle green'

// Utility function
function onEvent(event, selector, callback) {
    return selector.addEventListener(event, callback);
}

onEvent('click', submit, function() {
    let shape = new Shape(shapeInput.value, colorInput.value);
    shape.createShape();
    output.innerHTML = `${shape.shapeColor} ${shape.shapeName} `

    shapeContainer.addEventListener('click', function (e) {
        let target = e.target;

        if (target.matches('div')) {
            output.innerHTML = `${shape.getInfo()}`;
        }
    });
});

I have tried looking for ways to check if the element already has an event listener and to ignore it, but didn't have any luck. I have also tried to add a removeEventListener section, to no success. Is there something I'm missing here or am I completely wrong with my approach?


Solution

  • Hope I did not respond let. this will work for you.

       'use strict';
    
        // Selectors 
        const shapeContainer = select('.shape-container');
        const submit = select('.submit');
        const shapeInput = select('.shape-input');
        const colorInput = select('.color-input');
        const shapeSelector = select('.shape');
        const output = select('span');
    
    
        class Shape {
            constructor(name, color) {
                this._name = name;
                this._color = color;
            }
    
            set shapeName(name) {
                if (name instanceof Shape && this._name.length > 0) {
                    this._name = name;
                } else {
                    throw new TypeError('Shape name is invalid');
                }
            }
    
            get shapeName() {
                return this._name;
            }
    
            set shapeColor(color) {
                if (color instanceof Shape && this._color.length > 0) {
                    this._color = color;
                } else {
                    throw new TypeError('Color is invalid');
                }
            }
    
            get shapeColor() {
                return this._color;
            }
    
            createShape() {
    
                let element = {
                    tag : document.createElement('div'),
                    color : this._color,
                    name : this._name,
                }
    
                document.querySelector('.shape-container').appendChild(element.tag);
                element.tag.style.cssText += 'background-color:' + element.color;
    
                // Shape definition
                if (this._name == 'circle') {
                    element.tag.classList.add('circle', 'shape');
                } else if (this._name == 'square') {
                    element.tag.classList.add('square', 'shape');
                } else {
                    throw new TypeError('shapeName is invalid');
                }
                element.tag.addEventListener('click', function () {
                    console.log(element.color," ",element.name)
                    if (element.tag.matches('div')) {
                        output.innerHTML = getInfo(element);
                    }
                });
            }
        }
        // Utility functions 
        
        function select(selector, parent = document) {
            return parent.querySelector(selector);
        }
    
         function onEvent(event, selector, callback) {
            return selector.addEventListener(event, callback);
        }
    
        function getInfo (e) {
            console.log(e.color,e.name)
            return `${e.name} ${e.color}`;
        }
    
        let arr = [];
    
        onEvent('click', submit, function () {
            let shape = new Shape(shapeInput.value, colorInput.value);
            arr.push(shape);
            console.log(arr);
            shape.createShape();
        });