how can I restore the removed onClick attribute? - javascript

In the addBlocker function, I removed the onClick attribute from the button.
In the removeBlocker function, I need that attribute back along with the handler function which was implemented in the html file.
(I tried another approach where I used element.style.pointerEvents = 'none')
but with that, I can't get clientX and clientY value from the event. Is there any way to get clientX and clientY when pointEvents is set to none?
document.addEventListener('mouseover', function(e) {
if (e.target.type === 'button') {
newBody[i].removeAttribute('onClick');
}
newBody[i].addEventListener('click', e => {
e.preventDefault();
});
const { clientX, clientY } = e;
// newBody[i].style.pointerEvents = 'none';
// const elementMouseIsOver = document.elementFromPoint(clientX, clientY);
let elementMouseIsOver = document.querySelectorAll(':hover');
elementMouseIsOver = elementMouseIsOver[elementMouseIsOver.length - 1];
console.log({ clientX, clientY, elementMouseIsOver });
});
I expect to get back the removed onClick attribute when I run another function or find a way to get e.clientX and e.clientY when style.pointEvents is none.

Try to add the event on mouseleave
document.addEventListener('mouseleave', function(e) {
if (e.target.type === 'button') {
newBody[i].setAttribute('onClick', functionName);
}
})

If you need to restore the attribute value later, you'll have to retrieve it before you remove the attribute and store it somewhere.
Declare a place to store it:
var buttonClick;
Where you're removing it
buttonClick = newBody[i].getAttribute('onClick');
Where you're restoring it:
newBody[i].setAttribute('onClick', buttonClick);
You can even store it on the element itself by using an expando property (basically, a property with an obscure name you're fairly sure won't conflict with anyone else's):
newBody[i].__my_blocker_buttonClick = newBody[i].getAttribute('onClick');
Then where you're restoring it:
newBody[i].setAttribute('onClick', newBody[i].__my_blocker__buttonClick);

Related

Get and keep only original target of mousedown event?

I want to get and keep only the original target element of a mousedown event -- but as the user holds the mouse down, the event.target changes depending on what's under the pointer.
There is a property event.originalTarget which does exactly what I want, but it's only supported by Firefox (reference: https://developer.mozilla.org/en-US/docs/Web/API/Event/originalTarget ).
How can I replicate this behavior using standard event.target?
Figured it out: you need to create flags outside the event listener.
let el = false
let mousedown = false;
document.addEventListener('mousedown', ev => {
if (!mousedown) {
el = ev.target;
mousedown = true;
}
});
document.addEventListener('mouseup', ev => {
mousedown = false;
el = false;
});
So el will be set as the original target for the duration of the mousedown, but on mouseup, it's reset back to nothing.

Check the form element triggered at onclick event

I have a js function inside a web page that trap the position of the click on it. I had to implement it in a way that is recognized if the page contain a form element, and, if so, do a check as to whether that the click that I'm recording is made on one at random form element or not.
I got up to check the form and to learn its elements, but I do not know how to check if the click is made ​​on a single element:
$('*').on('mousedown', function (e) {
// make sure the event isn't bubbling
if (e.target != this) {
return;
}
// do something with the click somewhere
// for example, get the coordinates:
x = e.pageX;
y = e.pageY;
pa = $(location).attr('href');
//Window dimension
var width = $(window).width();
//var width = $getWidth();
var height = $(window).height();
//Check if page contain a form
var elementF = document.querySelectorAll('form');
var fname = '';
var elements = '';
for (var i=0; i<elementF.length; i++){
fname = elementF[i].id;
elements = document.forms[fname].elements;
for (x=0; x<elements.length; x++){
//Now i need to check if element is clicked or not
}
}
What you're doing here is binding a mousedown event to every element on the page. This will be resource intensive and should not be necessary. Also, since it's bound everywhere, the if (e.target !== this){ return; } does prevent it from firing a million times whenever you mousedown on something, but also prevents it from bubbling. Just let it bubble and use e.target and e.currentTarget to tell stuff apart. There shouldn't be any reason to do $('*').on("mousedown")
Why can't you just do this?
$("form").on("click", function(e){
// e.currentTarget will be the form element capturing the click
console.log( $(e.currentTarget).html() );
// e.target will be whatever element you clicked on
// so you can do whatever you want with it
console.log( $(e.target).text() );
// All your handler code here
});
Some possibly helpful stuff
http://api.jquery.com/event.currenttarget/
Is there a difference between $(e.currentTarget) and $(this)?
http://learn.jquery.com/events/event-delegation/
Try
$('*').on('mousedown', function (e) {
var elementClicked = e.target.nodeName;
console.log("element: " + elementClicked)
})

Detect click outside element (vanilla JavaScript)

I have searched for a good solution everywhere, yet I can't find one which does not use jQuery.
Is there a cross-browser, normal way (without weird hacks or easy to break code), to detect a click outside of an element (which may or may not have children)?
Add an event listener to document and use Node.contains() to find whether the target of the event (which is the inner-most clicked element) is inside your specified element. It works even in IE5
const specifiedElement = document.getElementById('a')
// I'm using "click" but it works with any event
document.addEventListener('click', event => {
const isClickInside = specifiedElement.contains(event.target)
if (!isClickInside) {
// The click was OUTSIDE the specifiedElement, do something
}
})
var specifiedElement = document.getElementById('a');
//I'm using "click" but it works with any event
document.addEventListener('click', function(event) {
var isClickInside = specifiedElement.contains(event.target);
if (isClickInside) {
alert('You clicked inside A')
} else {
alert('You clicked outside A')
}
});
div {
margin: auto;
padding: 1em;
max-width: 6em;
background: rgba(0, 0, 0, .2);
text-align: center;
}
Is the click inside A or outside?
<div id="a">A
<div id="b">B
<div id="c">C</div>
</div>
</div>
You need to handle the click event on document level. In the event object, you have a target property, the inner-most DOM element that was clicked. With this you check itself and walk up its parents until the document element, if one of them is your watched element.
See the example on jsFiddle
document.addEventListener("click", function (e) {
var level = 0;
for (var element = e.target; element; element = element.parentNode) {
if (element.id === 'x') {
document.getElementById("out").innerHTML = (level ? "inner " : "") + "x clicked";
return;
}
level++;
}
document.getElementById("out").innerHTML = "not x clicked";
});
As always, this isn't cross-bad-browser compatible because of addEventListener/attachEvent, but it works like this.
A child is clicked, when not event.target, but one of it's parents is the watched element (i'm simply counting level for this). You may also have a boolean var, if the element is found or not, to not return the handler from inside the for clause. My example is limiting to that the handler only finishes, when nothing matches.
Adding cross-browser compatability, I'm usually doing it like this:
var addEvent = function (element, eventName, fn, useCapture) {
if (element.addEventListener) {
element.addEventListener(eventName, fn, useCapture);
}
else if (element.attachEvent) {
element.attachEvent(eventName, function (e) {
fn.apply(element, arguments);
}, useCapture);
}
};
This is cross-browser compatible code for attaching an event listener/handler, inclusive rewriting this in IE, to be the element, as like jQuery does for its event handlers. There are plenty of arguments to have some bits of jQuery in mind ;)
How about this:
jsBin demo
document.onclick = function(event){
var hasParent = false;
for(var node = event.target; node != document.body; node = node.parentNode)
{
if(node.id == 'div1'){
hasParent = true;
break;
}
}
if(hasParent)
alert('inside');
else
alert('outside');
}
you can use composePath() to check if the click happened outside or inside of a target div that may or may not have children:
const targetDiv = document.querySelector('#targetDiv')
document.addEventListener('click', (e) => {
const isClickedInsideDiv = e.composedPath().includes(targetDiv)
if (isClickedInsideDiv) {
console.log('clicked inside of div')
} else {
console.log('clicked outside of div')
}
})
I did a lot of research on it to find a better method. JavaScript method .contains go recursively in DOM to check whether it contains target or not. I used it in one of react project but when react DOM changes on set state, .contains method does not work. SO i came up with this solution
//Basic Html snippet
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="mydiv">
<h2>
click outside this div to test
</h2>
Check click outside
</div>
</body>
</html>
//Implementation in Vanilla javaScript
const node = document.getElementById('mydiv')
//minor css to make div more obvious
node.style.width = '300px'
node.style.height = '100px'
node.style.background = 'red'
let isCursorInside = false
//Attach mouseover event listener and update in variable
node.addEventListener('mouseover', function() {
isCursorInside = true
console.log('cursor inside')
})
/Attach mouseout event listener and update in variable
node.addEventListener('mouseout', function() {
isCursorInside = false
console.log('cursor outside')
})
document.addEventListener('click', function() {
//And if isCursorInside = false it means cursor is outside
if(!isCursorInside) {
alert('Outside div click detected')
}
})
WORKING DEMO jsfiddle
using the js Element.closest() method:
let popup = document.querySelector('.parent-element')
popup.addEventListener('click', (e) => {
if (!e.target.closest('.child-element')) {
// clicked outside
}
});
To hide element by click outside of it I usually apply such simple code:
var bodyTag = document.getElementsByTagName('body');
var element = document.getElementById('element');
function clickedOrNot(e) {
if (e.target !== element) {
// action in the case of click outside
bodyTag[0].removeEventListener('click', clickedOrNot, true);
}
}
bodyTag[0].addEventListener('click', clickedOrNot, true);
Another very simple and quick approach to this problem is to map the array of path into the event object returned by the listener. If the id or class name of your element matches one of those in the array, the click is inside your element.
(This solution can be useful if you don't want to get the element directly (e.g: document.getElementById('...'), for example in a reactjs/nextjs app, in ssr..).
Here is an example:
document.addEventListener('click', e => {
let clickedOutside = true;
e.path.forEach(item => {
if (!clickedOutside)
return;
if (item.className === 'your-element-class')
clickedOutside = false;
});
if (clickedOutside)
// Make an action if it's clicked outside..
});
I hope this answer will help you !
(Let me know if my solution is not a good solution or if you see something to improve.)

Prevent default behavior when setting location.hash

When I do this,
location.hash = "test"
the url is updated and the page homes in on the element with that id.
Is there a way to stop the page from homing in to that element?
Solution
You cannot prevent this behaviour, but you can fool it by temporarily hiding the target, eg. like that (it has nothing to do with jQuery):
// obtain "target" DOM (not jQuery) element and do this:
var original_id = target.id; // save original ID
target.id = null; // set target's ID
location.hash = 'test'; // issue location.hash change
target.id = original_id; // set ID to original value
Generalized solution
Or more general example:
// make target_hash set to a hash you want to not lead you to page section and:
var element = document.getElementById(target_hash); // find element by ID
var original_id = element.id; // save original ID
location.hash = target_hash; // previously defined by you (eg. 'test')
element.id = original_id; // reset ID
Demo / proof
The live example can be as follows, in the event handler attached through jQuery (demo here: http://jsfiddle.net/DaZfH/):
some_link.on('click', function(event){
event.preventDefault();
var target = document.getElementById('target');
var original_id = target.id;
target.id = null; // unset ID
location.hash = 'target';
target.id = original_id;
});
Disclaimer
But indeed others are right: moving you to the correct place in the document is the correct behaviour. If you are doing things like I mentioned, then your solution is pretty hakish and there is definitely a better way to do that.
Is there a way to stop the page from homing in to that element
Yes. Although the hashchange event is not cancelable, you can reset its unwanted behavior like this.
var popY,
popX;
//When location.hash is changed, popstate is the first event to fire
//Use this event to record current state
window.addEventListener('popstate', popstateHandler);
function popstateHandler() {
popY = window.scrollY;
popX = window.scrollX;
}
//Reset scroll position with recorded values when hashchange fires (after page is scrolled)
window.addEventListener('hashchange', hashchangeHandler);
function hashchangeHandler() {
window.scrollTo(popX, popY);
}
That's the basis of it. You might want to do some proofing for IE, and implement your reasons for doing this: Animate scroll, active something etc..
Polyfill for scrollY, scrollX:
if(!('scrollY' in window)) {
Object.defineProperty(window, 'scrollY', {
get: function () {
return window.pageYOffset
}
});
Object.defineProperty(window, 'scrollX', {
get: function () {
return window.pageXOffset
}
})
}

In Javascript, how to get the current id of the div where mouse pointer is?

How to get the id of the div on which the mouse is currently pointing?
I think your best bet is to track mouseover at the document level and maintain the id of the last element hit.
var lastID = null;
var handleMouseover = function (e) {
var target = e.target || e.srcElement;
lastID = target.id;
};
if (document.addEventListener) {
document.addEventListener('mouseover', handleMouseover, false);
}
else {
document.attachEvent('onmouseover', handleMouseover);
}
<div id="the-id" onmouseover="alert(this.id)">some text</div>
You can use a javascript variable to store the current hovered div.. jQuery (or standard JS) could be used to set the event handler to populate the variable.
Visible test at: http://jsfiddle.net/gfosco/Hys7r/

Categories