My jsx:
return (
<div onClick={this.clickondiv}>
<i className="zmdi zmdi.." onClick={this.clickonicon} />
</div>
)
How do I prevent the onClick event on the div when I click on the icon?
You can stop the event from propegating up the DOM tree. In your clickonicon do this.
clickonicon(e){
e.stopPropagation();
//Rest of the clickonicon code
}
Related
I am using Bootstrap 5.2 and I have two buttons that can hide content, using the Bootstrap collapse plugin.
<div class="col-12 col-sm-auto">
<span class="pe-2">
<button id="show_movements_button" type="btn" class="btn btn-outline-primary" data-bs-toggle="collapse" data-bs-target="#movements_id">
Show Movements
</button>
</span>
<span class="pe-2">
<button id="show_credits_button" type="btn" class="btn btn-outline-secondary" data-bs-toggle="collapse" data-bs-target="#credits_id">
Show All Credits
</button>
</span>
</div>
such as
<tr class="song_id collapse" id="movements_id">
<td class="col-1">
1
</td>
<td class="col">
</td>
<td class="col">
<div>
<label class="h6">
Piano Concerto no. 1 in E minor, op. 11: I. Allegro maestoso
</label>
</div>
<div class="collapse" id="credits_id">
<div class="lh-1">
<div>
<a href="/container.start?cid=0$=Instrument$708&title=Instruments+%2F+piano" class="small text-secondary">
piano
</a>
<label class="small">
by
</label>
<a href="/container.start?cid=0$=Performer_name$5540&title=Performers+%2F+Evgeny+Kissin" class="small text-secondary pe-1">
Evgeny Kissin
</a>
</div>
</div>
</div>
</td>
</tr>
This work correctly, but I want the name of the button to change to indicate if showing or hiding content so I also have this code
<script>
function listenForButtonCollapse(buttonId, collapseId, buttonShowText, buttonHideText)
{
let button = document.getElementById(buttonId);
let section = document.getElementById(collapseId);
if(section!=null)
{
section.addEventListener('show.bs.collapse',
function()
{
button.innerText=buttonHideText;
}
);
section.addEventListener('hide.bs.collapse',
function()
{
button.innerText=buttonShowText;
}
);
}
}
</script>
<script>
listenForButtonCollapse('show_credits_button','credits_id','Show All Credits','Hide Some Credits');
</script>
<script>
listenForButtonCollapse('show_movements_button','movements_id','Show Movements','Hide Movements');
</script>
Now toggling the Show/Hide Movements button works fine, but when I click on the Show/Hide Credits button for some reason it is also triggering the listenForButtonCollapse() call on the movements button as well as the credits button, so the Movement button is updated with the same (Hide/Show) value as the credits button even though it isn't actually been invoked (so it doesn't hide/show the movements div)
The credits div is within the movements div, so Im assuming that why one button works without problem and the other doesn't but I cant see what I am actually doing wrong.
In order to avoid the current behaviour you need to stop further event propagation. You can do this by using stopPropagation(). This method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases.
function listenForButtonCollapse(buttonId, collapseId, buttonShowText, buttonHideText)
{
let button = document.getElementById(buttonId);
let section = document.getElementById(collapseId);
if (section != null)
{
section.addEventListener('show.bs.collapse',
function(event)
{
event.stopPropagation();
button.innerText=buttonHideText;
}
);
section.addEventListener('hide.bs.collapse',
function(event)
{
event.stopPropagation();
button.innerText=buttonShowText;
}
);
}
}
I've prepared a Code playground to illustrate that this solves your issue:
https://codesandbox.io/embed/bootstrap-5-playground-forked-b28j0g?fontsize=14&hidenavigation=1&theme=dark
Solution Explanation
The events show.bs.collapse and hide.bs.collapse are being triggered for both buttons when clicked. So when you add more than one event listener for those events, when the event occurs, all event listeners are being executed. This is why for example when you click "Hide Movements" and bootstrap triggers hide.bs.collapse
event then this executes all registered event listeners for it - in this case two - one for the show_credits_button and another for show_movements_button button - leading to changing both button texts. To prevent this you need to stop further event propagation with event.stopPropagation() method - this will stop notifying all other event listeners for this event other than the event target one.
I have a div which is wrapped in a Link tag in NextJS. Within the div I have a row of components which are buttons. When I click one of these buttons, they do what they should do, but the Link tag also gets fired from the parent div and we navigate to another page. I have added e.stopPropagation() to the event handlers of the buttons, but it's not making any difference. Can anyone see what I'm doing wrong, please?
The parent component:
<Link href={{
pathname: `/...`,
query: {
var:var
},
}}>
<div>
...
<div className="flex flex-row">
<Button1/>
<Button2/>
</div>
</div>
</Link>
A child button component:
async function handleClick(e) {
e.stopPropagation()
...
}
<button onClick={handleClick}>
...
</button>
I have also tried adding adding the stopPropagation to the onClick as such:
<button onClick={(e) => e.stopPropagation(), handleClick}>
...
</button>
Why is the click still bubbling up to the parent Link, please?
here is the culprit:
<button onClick={(e) => e.stopPropagation(), handleClick}>
try:
<button onClick={(e) => { e.stopPropagation(); handleClick(); }>
live demo on these two different versions:
https://codepen.io/remyho427/pen/NWamxvG
I'm creating my own autocomplete input in Blazor. (something like below)
function FocusOut()
{
document.getElementById("list-item-one").innerHTML = "Focus out";
}
function Click()
{
document.getElementById("list-item-one").innerHTML = "Click";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="search" onfocusout="FocusOut()" />
<ul class="dropdown">
<li id="list-item-one" onclick="Click()">List Item One</li>
</ul>
When I click on the list item, the onfocusout event fires instead of the onclick event. Is there a way to "push" the onclick event?
This isn't a parent child relation, so "stopPropagation" has no effect. Also I know there is a datalist tag, but i'm not using it because of the way it look, feels and behaves in the different browsers.
The problem is that the order of events is OnMouseDown, OnFocusOut, OnClick.
Because of this, your dropdown closes before the OnClick event, so the click is not registered.
A working solution is to replace OnClick with OnMouseDown.
Based on this answer by #DuncanLuk.
I had a similar issue and I added a await Task.Delay(250) in my #onfocusout handler and it worked. You can find the live demo by clicking three vertical dots at top right in ilovedotnet site.
<section id="social">
<div class="dropdown is-right #(MenuCollapsed ? null : "is-active")" #onclick="ToggleMenu" #onfocusout="FocusOutHandler">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="social-menu">
Social
</button>
</div>
<div class="dropdown-menu" id="social-menu" role="menu">
<div class="dropdown-content">
<a href="https://ilovedotnet.org/" target="_blank" class="dropdown-item">
I Love DotNet
</a>
</div>
</div>
</div>
</section>
#code {
internal bool MenuCollapsed { get; private set; } = true;
internal void ToggleMenu()
{
MenuCollapsed = !MenuCollapsed;
}
internal async Task FocusOutHandler()
{
// to avoid race between mouse click of anchor tag Navigation. without this delay Navigation
// is not getting executed when item is clicked from mouse
await Task.Delay(250);
MenuCollapsed = true;
}
}
I currently have a a parent div and a child div in the middle of the parent div. I want to be able to close the parent div only on clicking outside of the child div. How would I go about doing this? I have my code currently set up as below, with the triggerParentUpdate to set true or false whether to show div.
<div onClick={this.props.triggerParentUpdate} className="signupModalContainer">
<div className="embed-responsive embed-responsive-16by9">
<form action="action_page.php">
<div className="container">
<button onClick={this.props.triggerParentUpdate} type="button" className="closebtn">X</button>
</div>
</form>
</div>
</div>
the onclick function in the first div (className="signupModalContainer") makes it so that when I click that div or any of the child divs, all the divs close. if I take that onclick function out, then the divs close via the closebtn.
Thank you!
Create a handler for the child div's onClick event handler, which stops the propagation/bubbling up of the event to the parent.
Refer to Event.stopPropagation method for more info.
class SomeComponent extends Component {
handleCloseButton = e => {
// This stops the event from bubbling up.
// So it won't trigger the parent div's "onClick" to fire.
e.stopPropagation();
this.props.triggerParentUpdate(e);
}
render () {
// ...
return (
<div onClick={this.props.triggerParentUpdate} className="signupModalContainer">
<div className="embed-responsive embed-responsive-16by9">
<form action="action_page.php">
<div className="container">
<button onClick={this.handleCloseButton} type="button" className="closebtn">X</button>
</div>
</form>
</div>
</div>
);
}
)
I have a simple modal component:
function Modal(props) {
return (
<div className={cx(styles.overlay, { show: props.show })} onClick={props.onClose}>
<div className={styles.modal}>
<span className={styles.closeBtn} onClick={props.onClose} />
{props.children}
</div>
</div>
)
}
the onClose prop triggers closing the modal, hence I attach it to styles.overlay (dark overlay that you typically see on modals that when clicked dissmises it) and to styles.closeBtn (a close button for modal).
The whole flow works besides the fact that anything inside styles.overlay when clicked on also dismisses the modal, which is not functionality I was after, hence I need to only dismiss it if that specific element is clicked not its children.
function Modal(props) {
return (
<div className={cx(styles.overlay, { show: props.show })} onClick= {props.onClose}>
<div className={styles.modal} onClick={e => e.preventDefault()}>
<span className={styles.closeBtn} onClick={props.onClose} />
{props.children}
</div>
</div>
)
}
I think, the best way is to have your overlay and your modal in two separate div, but this should work.
Add onClick(e)={e.stopPropagation();} to the modal dialog's click handler; this should prevent it from propagating to the overlay.
Hope it works! Good luck!