React: Nested onclick also triggers parent
Asked Answered
P

2

22

I used the react version of the slick carousel to make a Netflix like carousel. You can click on a tile and that tile then expands to show the details of that tile.

Example:

enter image description here

This works great thanks to Slicks ability to handle dynamic heights. I want to add a close button the expanded section (as seen in the far right). But that is where I have an issue.

If I add a close button with a onClick handler, it will always trigger the parent Onclick which shows the expanded section.

The showExpanded onclick function just sets a showDetails state.

So my question is:

How can I set a state by clicking on the close button, without also triggering the wrapping parent.

I tried event.preventDefault() and event.stopPropagation() but that didn't do the trick.

Tile click looks like this:

expandTile(){
  this.setState({
    showDetails: true,
    closeTile: false
  });
}

Close button click function as I have it now:

closeTile(e){
   e.preventDefault();
   e.stopPropagation();
   const showDetails = this.state.showDetails;
   if(showDetails){
      this.setState({
        showDetails: false,
        closeTile: true
      });
   }
}

Update: added JSX:

  return (
    <div className={s.itemPreWrapper} key={`${el.title}-item-${index}`}>
      <div className={`${s.item} ${showDetails ? s.showDetails : ''}`}
           onClick={self.state.expandItem}
           data-index={index}
        <div className={s.itemCaret}></div>
        <div className={s.imgWrapper}>
          <img src={el.itemImage}/>
        </div>
        <div className={s.overlay}>
          {el.title}
        </div>
        <div className={s.expandedTile} style={{left: '-'+offset+'px'}}>
          <div className={s.etItem}>
           <div key={`subitem-${index}`} ref="subItem">
            <div className="row">
              <div className={`${s.etClose}`} onClick={self.state.closeTile}><span></span></div>
              <div className="col-xs-12 col-sm-3">
                <div className={`${s.etImage}`}>
                  <img src={el.itemImage} alt="product image" className="img-responsive"/>
                </div>
              </div>
              <div className="col-xs-12 col-sm-9">
                <div className="row">
                  <div className={`${s.etContent} col-xs-12 col-sm-6 col-lg-8`}>
                    <h2>{itemTitle}</h2>
                    <p> {el.description}</p>
                  </div>
                  <div className={`${s.etMedia} col-xs-12 hidden-sm col-sm-5 col-lg-3`}>
                    {media}
                  </div>
                </div>
            </div>
            <div className="col-xs-12 col-md-11">
              {optionsElem}
            </div>
          </div>
          </div>
        </div>
      </div>
    </div>
  );
Plasmosome answered 28/10, 2016 at 11:33 Comment(5)
Added it, thanks for helping out!Plasmosome
e.stopPropagation() should do the trick in these cases. Occasionally when it does not, doing the same with mousedown as well should cut it.Pembrook
So I should substitute the onclick with mousedown? Or do both?Plasmosome
No, I mean it's worth a try to listen to mousedown just to call stopPropagation on it.Pembrook
That worked!! How strange but wonderful! Thanks so much!Plasmosome
P
25

A click event is essentially the result of a mousedown event followed by a mouseup event on the same element, which can propagate around even if stopPropagation is called on a click event.

One solution is to call it on mousedown as well; in its simplest form:

<div onMouseDown={e => e.stopPropagation()} ... />
Pembrook answered 28/10, 2016 at 12:49 Comment(0)
P
25

The solution that worked for me was to place a call to event.stopPropagation() in your child onClick method. This will prevent the parent from being called.

Pennywise answered 7/7, 2017 at 23:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.