How can I prevent href from firing using React onClick? - javascript

trying to make a link element (<a> element) with href.
Why am I using href and not changing history? because I want the option to open in a new tab in browser.
The Problem is, I have a button inside the element, and when you click on it, it triggers the href immediately, before even getting to stopProppagation or preventDefault inside the onClick handler of the button. It’s like 2 different event types…
something like this:
...
const onButtonClick = (event) => {
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
event.preventDefault();
if (clickDisabled) return;
if (!onClick) return;
onClick(event);
}
return (
<a href={someHref}>
<button onClick={onButtonClick}>open menu</button>
</a>
)
Any ideas?

The workaround I ended up using: instead of the button onClick - I used onMouseDown which happens before the href trigger.
Not the best solution, but was good enough in my case.

const onButtonClick = (event) => {
event.stopPropagation();
event.nativeEvent.stopImmediatePropagation();
if (clickDisabled) return;
if (!onClick) return;
onClick(event);
}
const handleLink = (e) => {
e.preventDefault();
window.open('https://URL...', '_blank');
}
return (
<a href={someHref} onClick={handleLink}>
<button onClick={onButtonClick}>open menu</button>
</a>
)

Related

How to prevent onmouseout function to get called when onclick has been called already?

I'm trying to create a Like button with an input with the type image which its src changes when it is hovered/clicked. I want to change it when it is hovered and have its previous source back when it is unhoverd. So I used onmouseover and onmouseout to do this. I also used onclick to the src when it is clicked on.
The problem is that when I click on it, it changes as intended but as soon as I move the mouse so it is not hovered anymore, It calls the onmouseout function and this is not what I need.
Edit: There are multiple buttons so I cant't use a boolean variables to check if was clicked.
What should I do to not execute onmouseout when it was clicked on?
<input type="image" src="path" onmouseover="likeHover(this)" onmouseout="likeUnhover(this)" onclick="like(this, '{{post.id}}')">
function likeHover(btn) {
btn.src = '../../static/network/img/heart-pink.png';
}
function likeUnhover(btn) {
btn.src = '../../static/network/img/heart-black.png';
}
function like(btn) {
btn.src = '../../static/network/img/heart-red-filled.png';
}
You could use a boolean variable, and set it to true if the button was clicked.
And use addEventListener in the JS code and not the HTML attributes:
const input = document.querySelector("input[type=image]");
let clicked = false;
input.addEventListener("mouseover", (e) => {
if (!clicked)
e.target.src = '../../static/network/img/heart-pink.png';
});
input.addEventListener("mouseout", (e) => {
if (!clicked)
e.target.src = '../../static/network/img/heart-black.png';
});
input.addEventListener("click", (e) => {
clicked = true;
e.target.src = '../../static/network/img/heart-red-filled.png';
});
<input type="image" src="path">

React: how to have a Link with buttons inside, but make buttons not fire the link onclick

I have this code:
const history = useNavigate();
const navigate = (e) => {
e.preventDefault();
history('/link')
}
const doSomething = (e) => {
e.stopPropagation();
someFunc();
}
return (
<a href="/link" onClick={navigate}>
<span>Some stuff</span>
<button onClick={doSomething}></button>
</a>
);
This doesn't work because the preventDefault does not work because of the stopPropagation(). Of course I could use a div to avoid the link, or just remove the href all together but I'm striving for quality code, so what's the best option? I also can't use a button instead of a because there would be a button inside a button.

The link after e.preventDefault() doesn't load, without jQuery

I want to load a link on click, but it doesn't load. I use preventDefault() to load the animation and setTimeout(). What else should I use?
I try return true, and think to save the path link of the node in a variable and then using location.href to call it. But I don't know how to do it.
<div class="content animated fadeInDown"> Table </div>
<td>
<a class="link" href="./pizzerias/lazzaroni.html">See More</a>
</td>
<script>
let links = document.querySelectorAll('.link');
links.forEach((link)=>{
link.addEventListener('click', (e)=>{
e.preventDefault();
let content = document.querySelector('.content');
content.classList.remove('fadeInDown');
content.classList.remove('animated');
content.classList.add('fadeOutUp');
content.classList.add('animated');
setTimeout(500);
});
});
</script>
preventDefault is doing exactly what the name implies. It prevents the default behavior of an event.
In the case of a link, the default behavior is to redirect the user to the associated href attribute value.
You are preventing this from happening. So it is never going to happen. The setTimeout isn't doing anything either as it is.
If you want to redirect the user after the animation you need to do it explicitely:
links.forEach((link)=>{
link.addEventListener('click', (e)=>{
e.preventDefault();
let content = document.querySelector('.content');
content.classList.remove('fadeInDown');
content.classList.remove('animated');
content.classList.add('fadeOutUp');
content.classList.add('animated');
setTimeout(() => {
window.location.href = e.target.href;
}, 500);
});
setTimeout() require a callback function as its first argument but you only pass the time. It would be
setTimeout(() => {
window.location.href = e.target.href
}, 500)

React onClick and onTouchStart fired simultaneously

I have a div in my React app and I need to handle both clicks and touches. However, when I tap on a mobile, it fires both events.
If I swipe on a mobile or if I click on a normal browser, it works fine, only one event is fired in each case.
How can I handle this tap issue to not fire both events?
<div
className={myClasses}
onClick={this.myHandle}
onTouchStart={this.myHandle}
>
</div>
There is a defined order of when the events get fired (source):
touchstart
Zero or more touchmove events, depending on movement of the finger(s)
touchend
mousemove
mousedown
mouseup
click
If you want to prevent a click event if a touch event is fired before, you can you can use event.preventDefault() in the touchend event handler to prevent the click event from firing.
function App() {
const handleClick = () => {
alert('click');
};
const handleTouchEnd = (event) => {
alert('touchend');
event.preventDefault();
};
return (
<button
type="button"
onClick={handleClick}
onTouchEnd={handleTouchEnd}
>
Click Me
</button>
);
}
However, this is not universally applicable. For example, you cannot prevent a click event by using a event.preventDefault() in a mousedown event. In case you are looking for a solution to this (not sure when this use case applies though), you would have to use a ref instead:
function App() {
const prevent = React.useRef(false);
const handleClick = () => {
if (!prevent.current) {
alert('click');
} else {
prevent.current = false;
}
};
const handleMouseDown = () => {
prevent.current = true;
alert('mousedown');
};
return (
<button
type="button"
onClick={handleClick}
onMouseDown={handleMouseDown}
>
Click Me
</button>
);
}
Solved this problem using similar events between touch and mouse. touchStart/mouseDown or touchEnd/mouseUp. It fires one or another, according to each situation.
<div
className={myClasses}
onMouseUp={this.myHandle}
onTouchEnd={this.myHandle}
>
</div>
To avoid onClick() on touch devices you should check if the page is opened in touch devices or not.
To check weather it is opened in touch devices or not:
if (typeof document !== 'undefined') {
var isTouch = 'ontouchstart' in document.documentElement;
}
Then modify {isTouch ? undefined : this.myHandle} to your mouse event:
<div
className={myClasses}
onClick={isTouch ? undefined : this.myHandle}
onTouchStart={this.myHandle}
>
</div>
This is a few years late but found a solution that was really easy to implement. Looks like this:
import ReactDom from 'react-dom';
export default class YourClass extends Component {
componentDidMount(){
ReactDOM.findDOMNode(this).addEventListener('touchstart', (e)=>{
e.preventDefault();
console.log("touchstart triggered");
});
}
}
Seems like it intercepts and stops all onClick calls on mobile which is exactly what I was looking for

Jquery On("Click") hook on links interefering with each other

Hi I have two Jquery function. One function is set for hash scrolls and the other to show a modal on click. The functions are hooked to Links . I have set empty links with a href="#". However my two hooks are interfering with each other. If I check for empty hashlinks in my first function and return a false then my second function in gallery to display Image modal is deactivated. Is there any way around this. I am sure that the obvious answer is adding some variable to my function. But I want to make a function that will check if the href="#" is true and not scroll but won't interfere with any other function that may be hooked by Jquery on to that link. Also why do the two hooks interfere with each other?
<div>Some text<div>
<div id="gallery>
<div class="item">
<a class="thumbnail thumbnail-sm" href="#" rel="tooltip">
<img src="...jpg" class="img-rounded">
</a>
</div>
<div>
//smooth scroll hashes function.
('a[href*=#]').on('click', function () {
var href = $.attr(this, 'href');
href = href.replace(/^\//, '');
if (href == '#') {
return false;// but if I return false here modal does not work.
}
else { //smooth scroll code here }
return false;// if I return false here my modal function works.
});
//Display gallery item in modal function.
$('#gallery').on('click', '.item a', function () {
$('#myModal').modal('show');
return false;
});
Edit: I am puzzled by this behaviour
if (href == '#') {
return false;// but if I return false here modal does not work.
}
else { //smooth scroll code here }
return false;// if I return false here my modal function works.
When you return false from the event handler, it prevents the default action of the <a> element, but it also stops the propagation of the event -- that means other attached event handlers will not get executed. If you want the event handler for the smooth-scroll jump links to allow for other event handlers on those links to execute, you should just prevent the default action, but still allow the event to propagate. You can do that by calling event.preventDefault(), instead of returning false.
Start your event handlers like this:
$('a[href*=#]').on('click', function (event) {
event.preventDefault();
...
And:
$('#gallery').on('click', '.item a', function (event) {
event.preventDefault();
...
And don't return false from them.
It may be happening because the second case uses event delegation, so as the first event is cancelled, it doesn't bubble for the delegation. Try this:
$('#gallery .item a').on('click', function () {
alert("hhh");
$('#myModal').modal('show');
return false;
});
Hope this helps. Cheers
Have you tried something like this?
('a[href*=#]').on('click', function () {
var href = $.attr(this, 'href');
href = href.replace(/^\//, '');
if (href != '#') {
//smooth scroll code here
}
return false;
});

Categories

Resources