React: Nested onclick also triggers parent - javascript

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:
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>
);

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()} ... />

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.

Related

How can i continuesly using appenTo() when i click a button?

im trying to reverse div with Jquery which when i click a button the divs will reverse and switch place
<div class="player1">
<div class="player1-a">
<div class="pemain p1a">
<h4>Samsudin</h4>
</div>
<div class="cock 1a">
</div>
</div>
<div class="player1-b">
<div class="pemain p1b">
<h4>Joko</h4>
</div>
<div class="cock 1b">
</div>
</div>
</div>
<button class="btn btn-light score_plus" id="score_kiri"><h1>SCORE</h1></button>
whenever this button clicked the div p1b will move to div player1-a and so do div p1a will move to div player1-b.
Here's my jquery code that the divs only move once and dont move again when i click again.
$('#score_kiri').click(function() {
$('#player_kiri').val(i++);
$('.p1a').appendTo('.player1-b');
$('.1a').appendTo('.player1-b');
$('.p1b').appendTo('.player1-a');
$('.1b').appendTo('.player1-a');
$('.p1a').append('.player1-b');
$('.1a').append('.player1-b');
$('.p1b').append('.player1-a');
$('.1b').append('.player1-a');
});
Your issue is that you have hard-coded the elements to move, rather than use relative positions. Effectively saying "make it exactly like this" rather than "move the first one to the end" (which I believe is what you're trying to do).
You can select the first one various ways, here's one:
$(".player1 > div").first()
Using .appendTo(".player1") with this will move the element to the end - so by always moving the first to the end you get your "continuously appendTo". If you have 3, then first will move to the end each time.
This is slightly different from "switching places" but has the same effect when only 2.
Updated snippet:
$("#btn").click(() =>
$(".player1 > div").first().appendTo(".player1")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="player1">
<div class="player1-a">
<div class="pemain p1a">
<h4>p1a Samsudin</h4>
</div>
<div class="cock 1a">1a
</div>
</div>
<div class="player1-b">
<div class="pemain p1b">
<h4>p1b Joko</h4>
</div>
<div class="cock 1b">
1b
</div>
</div>
</div>
<button id=btn>
click me
</button>

Checkbox input triggering Bootstrap accordion collapse event

Hello guys I'm using Bootstrap 5 accordion, the only problem I have is that the input checkbox is triggering the "collapse" event from the accordion, I tried to move the checkbox outside the range of the button from the accordion but that will look horrible.
I'm using Svelte, rendering each accordion with Each block with Data from the backend!
This is my code right now:
<div class="container">
<div class="row">
<div class="col-md-10 col-10 col-sm-10 responsiveFix">
<div class="accordion" id="accordionObjective">
{#each objectives as objective}
<div class="accordion-item">
<h2
class="accordion-header"
id={"heading" + objective.objectiveId}
>
<button
class="accordion-button objectiveTitle collapsed"
type="button"
data-bs-toggle="collapse"
data-bs-target={"#collapse" +
objective.objectiveId}
aria-expanded="false"
aria-controls={"collapse" +
objective.objectiveId}
>
<div class="form-check">
<input
class="form-check-input"
type="checkbox"
value={objective.objectiveId}
id="myCollapse"
checked={objective.value}
on:click={postObjective(
objective.objectiveId,
objective.value
)}
/>
</div>
<span> {objective.title}</span>
</button>
</h2>
<div
id={"collapse" + objective.objectiveId}
class="accordion-collapse collapse"
aria-labelledby={"heading" +
objective.objectiveId}
data-bs-parent="#accordionObjective"
>
<div class="accordion-body">
<span>{objective.description}</span>
</div>
</div>
</div>
{/each}
</div>
</div>
</div>
</div>
The output of this code its
and this is the picture showing my problem after clicking on any checkbox:
I also tried to bind a bootstrap 5 function to the checkbox input but it didn't work
What can I do? Can you throw me any clue? Thank you!
I am not familiar with Bootstrap 5 as such, but a quick glance at your code shows this: <button on:click={postObjective(objective.objectiveId, objective.value )}>
This function is executed at render time and the return value added as the event listener for your on:click
The correct syntax would be <button on:click={() => postObjective(....)}>
As the code is now it probably does not do what you expect.
Edit:
In your case the input is also inside a button, clicking the input will therefore also click the button. To stop this from happening you have to prevent the event from bubbling up, Svelte has a handy helper for that: <button on:click|stopPropagation={() => postObjective(....)}>

How to disable link on Button but when I click on card link should be work

I am Using card and when i click on card its work fine. Now i have added three buttons in cards when i click on button then card link also call. i just want to perform different action from button but not card link.
This is code:
<li class="t-Cards-item #CARD_MODIFIERS#" data-id="#ID#" >
<div class="click t-Card" >
<a href="javascript:void(null);" class="t-Card-wrap" data-id="#ID#">
<div class="t-Card-icon u-color #CARD_COLOR#"><span class="t-Icon fa #CARD_ICON#"><span class="t-Card-initials" role="presentation">#CARD_INITIALS#</span></span></div>
<div class="t-Card-titleWrap"><h3 class="t-Card-title">#CARD_TITLE#</h3>
<h4 class="t-Card-subtitle">#CARD_SUBTITLE#</h4></div>
<div id="outer">
<div class="inner"><button class="msgBtn" >S</button></div>
<div class="inner"><button class="msgBtn2" onClick="return false;">M</button></div>
<div class="inner"><button class="msgBtnBack">L</button></div>
</div>
<div class="t-Card-body">
<div class="t-Card-desc">#CARD_TEXT#</div>
<div class="t-Card-info">#CARD_SUBTEXT#</div>
</div>
<span class="t-Card-colorFill u-color #CARD_COLOR#"></span>
</a>
</div>
</li>
The Problem
Assume there are two divs with two different buttons on them.
<div onClick={handleOutter}>
<div onClick={handleInner}>
// some content ...
</div>
</div>
calling handleOutter will call the handleInner function. this is the default behavior of event propagation in your elements. more info on MDN documentation.
The Solution
You can stop event propagation in the child elements by adding event.stopPropagation() in the handler function in this way:
const btn = document.getElementById('myParentElement');
btn.onclick = function (event){
event.stopPropagation();
// ...
}
more info on MDN documentation.

Want horizontal scroll in mouse wheel scrolling Nuxt js

Here is my simple HTML markup style. So, when I am using the mouse wheel I want to scroll the content horizontally.
`
<div class="col-md-9" style="max-height: 80vh;overflow-y: hidden" id="scroll_container">
<div class="container-fluid" >
<div class="row flex-row flex-nowrap">
<div class="col-md-4">
Card 1
</div>
<div class="col-md-4 mb-4" >
Card 2
</div>
<div class="col-md-4">
Card 3
</div>
<div class="col-md-4">
Card 4
</div>
</div>
</div>
</div>
`
Here's what I did to make it little more "Vue". I set a ref on the HTML element I want to scroll as well as a #mousewheel event. Then in the triggered method, I reference the element by $ref and pretty much do what OP did with the .scrollLeft += e.deltaY.
Here's what it looks like:
<div ref="scroll_container" #mousewheel="scrollX">
...
</div>
...
methods: {
scrollX(e) {
this.$refs['scroll_container'].scrollLeft += e.deltaY;
},
},
I need to add an event listener in vue created life cycle.
document.addEventListener('wheel', (e) => {
document.getElementById('scroll_container').scrollLeft += e.deltaY;
})

Semantic-ui accordion get index of opened item inside onOpen event

I have a semantic-ui accordion. It is working properly. But when user reloads page it is opening the default index item as expected. What I want is to open the lastly active index after page refresh. I decide to use javascript document.cookie to keep last active item's index. My problem is that I cannot get the index of element inside onOpen event.
HTML :
<div class="ui styled accordion sticky">
<div class="item">
<div class="title active">
Users
</div>
<div class="content active">
List
</div>
</div>
<div class="item">
<div class="title active">
Items
</div>
<div class="content active">
List
</div>
</div>
</div>
JQ:
$('.ui.accordion').accordion({
onOpen: function (item) {
setCookie('acordionIndex',this.index);
}
}).accordion('open', getCookie('acordionIndex'));
I found this question This question but the advised solution is not working.
Note : my getCookie and setCookie functions are working properly.
I have solved by trying alternative options. Changed onOpen event to onOpening
$('.ui.accordion').accordion('open', getCookie('acordionIndex') * 1).accordion({
onOpening: function (item) {
setCookie('acordionIndex', this.index('.content') - 1, 2)
}
});

Categories