Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the id of a clicked parent element in a card?

I'm trying to make certain "cards" that display next to each other, and when the card is clicked, I want to get the id of the card. However, my function gets the id of the child elements when I click it, which is undefined, rather than of the parent card, unless I click on the border of the card div. How do I make sure it gets the id of the card specifically?

Here is the HTML:

<div id="parentCard" onclick="getID(event)">
  <div id="child1">I'm a child</div>
  <div id="text">
    <p>Text 1</p>
    <p>Text 2</p>
    <p>Text 3</p>
  </div>
</div>

Javascript:

function getID(event){
  console.log(event.target.id);
}
like image 556
malhi3 Avatar asked Dec 08 '18 14:12

malhi3


People also ask

How do I find the ID of a clicked element?

To get the clicked element, use target property on the event object. Use the id property on the event. target object to get an ID of the clicked element.

How do I know which ID is clicked in jQuery?

Answer: Use the jQuery attr() Method You can simply use the jQuery attr() method to get or set the ID attribute value of an element. The following example will display the ID of the DIV element in an alert box on button click.


Video Answer


3 Answers

Grab the target element of the event (the element that was clicked).

Here I've used destructuring to get the id, tagName, and parentNode properties from the target.

If the clicked element is a card div element log the id, otherwise log the id of the parent element.

Note: this assumes that the cards won't have nested HTML any deeper than they are in your example or parentNode won't apply to the right parent element.

const parent = document.getElementById('parentCard');
parent.addEventListener('click', handleClick, false);

function handleClick(e) {
  const { id, tagName, parentNode } = e.target;
  console.log(tagName === 'DIV' ? id : parentNode.id);
}
<div id="parentCard">
  <div id="child1">I'm a child</div>
  <div id="text">
    <p>Text 1</p>
    <p>Text 2</p>
    <p>Text 3</p>
  </div>
</div>
like image 82
Andy Avatar answered Oct 18 '22 01:10

Andy


Try with Event.currentTarget which

Identifies the current target for the event, as the event traverses the DOM. It always refers to the element to which the event handler has been attached, as opposed to event.target which identifies the element on which the event occurred.

function getID(event){
  console.log(event.currentTarget.id);
}
<div id="parentCard" onclick="getID(event)">
  <div id="child1">I'm a child</div>
  <div id="text">
    <p>Text 1</p>
    <p>Text 2</p>
    <p>Text 3</p>
  </div>
</div>
like image 2
Mamun Avatar answered Oct 18 '22 01:10

Mamun


Every time the user clicks somewhere on a page, the user agent will determine which "non-compound" element was clicked on and fire an event of type "click" event with that element as event target.

A "non-compound" element here means one that does not have descendant elements (it may have descendant nodes, like text, for instance).

Since your cards will typically be compound elements -- containing other elements (which may contain other elements in turn) -- there is no guarantees about which of these elements will be the click event target.

The user agent is a machine and cannot think for you and know that that the user "clicks on a card". If the card contains a button or a link or an image, all the user agent will do is tell you which of these the user has clicked on, through the means of the target property on the event -- you need to determine the fact that from your perspective, a card was clicked on.

There are at least two ways to determine said fact:

  1. Find out which card element is or contains the clicked element:

    function get_card(element) {
        for(; element; element = element.parentElement) {
            if(is_card(element)) return element;
        }
    }
    

    How do you know, traversing ancestor list, that an element is a card? As far as the document object model is concerned, it's just a div element, with an onclick attribute and an ID. You may have div elements with defined id and onclick attributes in your document that are not cards.

    Adding a class to an element is a natural way to, well, classify it:

    <div class="card">
        <!-- descendant elements -->
    </div>
    

    With the above we decide and now assume that every card element will include "card" in the list of its class names. Now you can write your is_card function (used in get_card), as follows:

    function is_card(element) {
        return element.classList.contains("card");
    }
    

    With a working get_card(element) function in your program you can now reliably answer the question "which card, if any, contains element?". In combination with a single event listener on, say, the window object you can now know which card the user clicks on:

    addEventListener("click", function(ev) {
        var card = get_card(ev.target);
        if(card) {
            /// A card was clicked, do something about it.
        }
    }
    

    As you can see, you don't even need to add listeners to every card, adding one to one container element of your choice (or window as is the case above) is all you need with this solution.

    Now, this is a case of a so-called linear-time algorithm -- the "deeper" your cards (descendant elements containing other descendant elements in turn), the longer average time it will take to locate the card for a descendant element. But it's nothing to worry about with "click" handling and performance of modern JavaScript runtimes, if I am allowed to be general here.

  2. Use the [so-far experimental] CSS4 and the pointer-events: none rule for card's children. Assuming every card includes the class "card", you can specify that no descendant element will have pointer events enabled -- these will never fire "click" events, the card element will instead:

    .card > * {
        pointer-events: none;
    }
    

    The support for pointer-events is still experimental but I know that recent Google Chrome and Firefox do support it. You have to be careful here though -- like, are you prepared to disable interactivity for some of card's elements? What if you have form elements there, which are typically interactive? You need to assess these kind of requirements yourself.

There is a third solution, but I consider it inferior to at least the first solution. For the sake of completeness, assigning an event listener on each card may be wasteful, especially if there are many cards on each page. However, in any case, if you attach a "click" listener to a card like you yourself did, the element the listener for the event type "click" was added to, is available with the ev.currentTarget property! Meaning that no matter which descendant element fires the "click" event, the event will reach the card element, through its capture and bubbling phases, and the currentTarget property value will always refer to the element the listener is added to -- in this case the card element. Of course, this solution implies that the listener is attached to every card.

like image 2
amn Avatar answered Oct 18 '22 01:10

amn