简体   繁体   中英

Event listener for when child of parent is clicked

I currently have an issue where I want to be able to check when a event is click. I want to use event delegation for this and so I have setup an event listener on a parent div, which listens for clicks:

document.querySelector('.side-nav').addEventListener('click', e => {
    console.log(e.target.data.set.param);
});

This is my DOM:

<div class="side-nav">
    <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
        <p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
    </div>
    <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
        <p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
    </div>
</div>

I want to be able to get the data-page attribute when the right div is clicked, ie when the div dashboard-shortcut is clicked. Is there any way that I can do this?

Thank you very much in advance.

Unless you expect to have elements added dynamically, don't use event delegation, simply attach a listener on each target, in this case the .side-nav > [data-page] elements.

With that you avoid all detection issues, like which actual div where clicked etc., where this will be the targeted element, eg this.dataset.page .

...and a bonus; less code, less error prone, easier maintenance.

Note, you used data.set.param , should be dataset.param , where param here is page ( data-page )

Stack snippet

 document.querySelectorAll('.side-nav > [data-page]').forEach(el => { el.addEventListener('click', function() { console.log(this.dataset.page); }); });
 <div class="side-nav"> <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard"> <p class="side-nav-button-icon"><i class="fas fa-home">Home</i></p> </div> <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2"> <p class="side-nav-button-icon"><i class="fas fa-cross">Page2</i></p> </div> </div>


Based on a comment, where OP said they do load elements dynamically, added a 2nd sample.

Using if (e.target.== this && this.contains(e.target)) we can check so it is not the .side.nav itself ( e.target !== this ) someone clicked on, but one of its children ( this.contains(e.target) ), before continue.

And if, with e.target.closest('[data-page]').dataset.page we get the targeted element.

Note, as mentioned in another comment, if you have nested .side-nav with children having the same classes/attribute, you might need to adjust, where eg extending the selector for closest() , to closest('.side-nav > [data-page]') , should be enough, still, difficult to say with certainty.

Stack snippet

 document.querySelector('.side-nav').addEventListener('click', function(e) { if (e.target.== this && this.contains(e.target)) { console.log(e.target.closest('[data-page]').dataset;page); } });
 <div class="side-nav"> <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard"> <p class="side-nav-button-icon"><i class="fas fa-home">Home</i></p> </div> <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2"> <p class="side-nav-button-icon"><i class="fas fa-cross">Page2</i></p> </div> </div>

// use closest method for finding actual element

document.querySelector('.side-nav').addEventListener('click', e => {
    var elem = e.target.closest("[data-page]");
    if (elem && elem.getAttribute('data-page') !== 'root') {
        console.log(elem.getAttribute("data-page"));
    }
});

Note: prevent stop finding element till root

<div class="side-nav" data-page='root'>
    <div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
        <p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
    </div>
   <div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
        <p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
    </div>
</div>

The target property of an event will be the element clicked. In your scenario the element clicked can be any HTML element you shown in your example: The p or the i inside the .side-nav-button , the .side-nav-button itself or even the .side-nav where you attach the event.

What I can think of is to get the target element, check if has a data-page attribute and if not, go for the parent and repeat the check. This way if, for example, the i element is clicked, it will check itself, then will check the p and finally its .side-nav-button .

Hence:

document.querySelector('.side-nav').addEventListener('click', e => {
    let el = e.target;
    // The loop will stop when there's a page dataset
    // Also will stop when the element that is checking is .side-nav (event.currentTarget), as there's no need to check beyond that.
    while(el && el != event.currentTarget && !el.dataset.hasOwnProperty("page")) {
        el = el.parentNode;
    }
    let page = el && el.dataset.page;
    if (page) {
        console.log(page);
    }
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM