setTimeout triggering too quickly - javascript

I have a tooltip(which is just a div) that appears when on the mouseover event of another element.
I am trying to make the tooltip hidden on the mouseleave event of the the main element, however, I want the tooltip to remain visible if the mouse is over the tooltip.
The tooltip is being position directly underneath its element.
My code is as follows:
var option_hide_timeout;
$(".option").mouseover(function () {
showTooltip($(this));
});
$(".option").mouseleave(function () {
option_hide_timeout = setTimeout(hideTooltip(), 2000); // delay the hiding to allow the mouse to enter the tooltip
});
$("#option_tt").mouseenter(function () {
clearTimeout(option_hide_timeout);
});
$("#option_tt").mouseleave(function () {
hideTooltip();
});
function showTooltip(parent) {
var parentPos = parent.position();
$("#option_tt").css({
visibility: "visible",
left: parentPos.left,
top: parentPos.top + $(parent).height()
});
}
function hideTooltip() {
$("#option_tt").css("visibility", "hidden");
}
The problem is that the tooltip hides immediately after the mouse leaves the main element.
The problem is persistent across Chrome, Firefox, Opera and IE.
No matter what the value of the delay(2000 in my code is just an example, it would more likely be shorter in practise), it triggers immediately.
I have tried using both mouseover/mouseout and mouseenter/mouseleave - both produce the same results, which leaves me with the conclusion that the line:
setTimeout(hideTooltip(), 2000);
is not correct.
Placing an alert in the mouseleave event assures me that the code is being called.
Am I missing something obvious? If so, a pointer in the correct direction would be greatly appreciated.

Change
option_hide_timeout = setTimeout(hideTooltip(), 2000);
to
option_hide_timeout = setTimeout(hideTooltip, 2000);
The added parenthesis makes the function being immediately called instead of being given to setTimeout.

I seem to have fixed my own issue.
$(".option").mouseleave(function () {
option_hide_timeout = setTimeout(hideTooltip(), 2000); // delay the hiding to allow the mouse to enter the tooltip
});
should be:
$(".option").mouseleave(function () {
option_hide_timeout = setTimeout(function () { hideTooltip() }, 2000);
});
It was very simple and I should have realised this before posting.

Related

Undo .removeAtribute function

I'm looking for a solution to restore a removed attribute. I'm not an experienced programmer, so I'm not sure where to start when sharing my code, so I'll try to give some context below.
I have an image of a map that has several hidden overlays. These overlays are activated by a series of adjacent buttons.
Each of these buttons has a mouseover and mouseout event, which temporarily reveals the overlay. They also have an onclick event that permanently displays the overlay. I've used a .removeAtribute function to remove the mouseout event so that my overlay is permanent.
All other layers are still visible with the mouseover and mouseout events (so that you can make comparisons).
When I onclick another overlay button, it clears the previous one, however, now the mouseout event for the previously selected button is still inactive, so hovering over it causes the overlay to appear permanently.
How can I restore the mouseout event after I've removed it?
I have tried to use .setAttribute("onmouseout"), but I've had no luck in making that work.
Hopefully, this all makes some sense; I'll post some of my code below, which might help give further context.
function btn01On() {
document.getElementById("btn01").removeAttribute("onmouseout");
}
function btnClear() {
document.getElementById("btn01").setAttribute("onmouseout");
}
<button id="btn01" class="map-button map-button1"
onclick="MM_showHideLayers('InfoCurrentExc','','show','OverlayCurrentExc','','show');btn01On();" onmouseover="MM_showHideLayers('OverlayCurrentExc','','show')" onmouseout="MM_showHideLayers('OverlayCurrentExc','','show')">
Current Excavation
</button>
Usually setting up event handlers using onevent attribute, (although oldest method for event handling) is not the recommended way, See https://developer.mozilla.org/en-US/docs/Web/Events/Event_handlers#dom_event_handler_list.
I recommend using EventTarget.addEventListener and EventTarget.removeEventListener for your case. Try the code below
const mouseoutHandler = function() {
MM_showHideLayers('OverlayCurrentExc', '', 'show');
};
const mouseOverHandler = function() {
MM_showHideLayers('OverlayCurrentExc', '', 'show');
};
const button01 = document.getElementById("btn01");
button01.addEventListener("mouseover", mouseOverHandler);
function btn01On() {
if (!mouseoutListener)
button01.addEventListener("mouseout", mouseoutHandler);
}
function btnClear() {
if (mouseoutListener) {
button01.removeEventListener("mouseout", mouseoutListener);
mouseoutListener = null;
}
}
const clickHandler = function() {
MM_showHideLayers('InfoCurrentExc', '', 'show', 'OverlayCurrentExc', '', 'show');
btn01On();
}
button01.addEventListener("click", clickHandler);
I was lucky enough to find someone who had a fix for this problem. I'll share the code below for anyone who might land here with a similar request.
I don't fully understand how this code works so if someone has a good explanation feel free to share it.
// Remove mouse outs
function btn01On() {
document.getElementById("btn01").removeAttribute("onmouseout");
}
// keep mouse outs
const buttonIds = ["btn01"];
const mouseOuts = {};
buttonIds.forEach((id) => {
const el = document.getElementById(id);
if (el) {
mouseOuts[id] = el.getAttribute('onmouseout');
}
});
const restoreMouseOutEvent = () => {
buttonIds.forEach((id) => {
const el = document.getElementById(id);
if (el && mouseOuts[id]) {
el.setAttribute('onmouseout', mouseOuts[id]);
}
});
}

jquery onblur not firing

I am trying to get an onblur/onfocus combination working for a pair of text boxes which I am selecting via class in jquery. I am not getting any errors in debug, but the blur function never seems to be called. When debugging my breakpoint in the blur function is not hit.
$(document).ready(function () {
var row = $(this).closest('tr');
$('.editClass').click(function () {
var editBoxes = $(row).find('.editClass');
var focus = 0;
$(editBoxes).focus(function () { focus++ });
$(editBoxes).blur(function () {
focus--;
setTimeout(function () {
if (!focus) {
alert('LOST FOCUS'); // both lost focus
}
}, 50);
});
});
});
Pretty sure the problem here was that the editBoxes were dynamically added to the page. This was not apparent in my question. Since they were dyncamically added I need to use
$(document).on('blur', '.editBoxes', function (){
...
}
The last two lines of your code example should be this
});
});
This is needed for closing the ready and click function call.
Another possible problem is that you wrap the focus and blur listeners in a click handlers. Why did you do this?

First click will not work

The first click does not work but every click after does perfectly. Is there anything I'm doing wrong or is it the site? (I'm using JS Fiddle by the way)
$("a").click(function () {
var x = document.getElementsByTagName("a");
$(x).click(function () {
var y = this.parentElement.parentElement;
$(y).hide("slide", {
direction: "right"
}, 1000);
});
});
In your code the first click will register another click handler which is actually doing the work so when the first click happens there is no handler which is actually hiding the parent element.
Also here you are attaching a new click handler in each click of the anchor element.
Instead you can just add the hide logic in the first click handler itself like
$("a").click(function () {
$(this).parent().parent().hide("slide", {
direction: "right"
}, 1000);
});
Demo: Fiddle
On your first click, you are executing a function that adds another click listener, so it won't be executed until it is clicked again. Try something like this:
function yourFunction() {
var y = this.parentElement.parentElement; // this may have to be slightly modified - I'm not sure of the rest of your code
$(y).hide("slide", {
direction: "right"
}, 1000);
}
$("a").click(function () {
var x = document.getElementsByTagName("a");
$(x).click(yourFunction);
yourFunction(); // calling yourFunction here also ensures it's called on the first click
});
Edit: this is redundant. Arun P Johny has a much cleaner solution. This is what I get for staying up all night.

prevent all MouseClick event until page load

I have a situation in which i have to prevent all MouseClick events until the page loads.
i have 1 javascript function defined on page load like
onload="init();"
Now in function init(), we are showing tree and select a particular node of it.
function init() {
ExpandAncestors(node);
ExpandNode(node);
setTimeout("treeScrollToView()", 1000);
}
Now i want to prevent all the mouse click event on tree/page until whole tree is not fully shown.
I have searched through some of the posts related to my question but that uses event.preventDefault() but i dont have Event object here.
Any help is greatly appreciated.
You can use:
CSS
body {
pointer-events:none;
}
and then on page load reactivate them
$(document).ready(() => {
$('body').css('pointer-events', 'all') //activate all pointer-events on body
})
Explanation
pointer-events:none; blocks all mouse interaction with the elements it's applied to - Since the body is usually the parent of all the elements in your page, it would case them not to react to any mouse interaction at all.
Keep in mind that all mouse interaction would be blocked this way, not only mouse clicks but mouse hover, mouse up's etc etc..
I think the basic need is to prevent user from clicking the tree area. I would prefer to display an overlay div rather than playing with the tree mouse click events.
You can show a loading overlay on the tree part until it is loaded. once done, you can hide the loading and show your original tree.
Ref: How to completely DISABLE any MOUSE CLICK
JavaScript Only
You can have an event listener along with a boolean. onclick disables a click. oncontextmenu disables right clicks.
(function(){window.onload = function () {
var allowClicks = false;
document.onclick = function (e) { !allowClicks&&e.preventDefault(); }
document.oncontextmenu = function (e) { !allowClicks&&e.preventDefault(); }
document.getElementById('myElement').onload = function () { allowClicks = true; }
}());
myElement is your element which you can replace with whatever
Use this with one element
If you want to disable mouse clicks for just one element, do:
(function(){window.onload = function () {
var allowClicks = false,
elem = document.getElementById('myElement');
elem.onclick = function (e) { !allowClicks&&e.preventDefault(); }
elem.oncontextmenu = function (e) { !allowClicks&&e.preventDefault(); }
elem.onload = function () { allowClicks = true; }
}());
onload="init();" here you can have event object.
pass event as argument.
onload="init(event);"
now you can use that in init() function.
Try utilizing $.holdReady()
$.holdReady(true);
$(window).off("click");
$("*").each(function(i, el) {
this.onclick = function(e) {
e.preventDefault();
}
});
function init() {
$("div").on("click", function() {
alert($.now())
})
}
setTimeout(function() {
$.holdReady(false);
}, 7000)
$(function() {
init()
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<body>
<div>click</div>
click
</body>

Jquery - .one does not unbind

i have the following situation:
i have an animated graph, at the end of the animation i want to add a click handler to a "dead" link, which then hides the actual slide and shows the next. i bind it with .one, cause i dont want to fire it again after loading.
so it works, it shows the next slide, but the event is not unbinding.
even if i unbind it manually it fires the event.
can someone give me a clue?
thx
jesta
$("li#slide3").off().on("click", $(this), function() {
$("#slide3 .device").animate({opacity:1}, 1000, function() {
$("#slide3 .device").animate({opacity:0}, 1000, function() {
console.log($("li#slide3 img.graph_adds").data("height"));
$("li#slide3 img.graph_adds").animate({height:$("li#slide3 img.graph_adds").data("height")}, 1500, function() {
$("#book_container").one("click", "a#book", function(ev) {
ev.stopImmediatePropagation();
ev.preventDefault();
if (!animBook) { initialiseAnimatedImages(); }
$("li.active_slide").fadeOut(500, function() {
$("li#slide4").addClass("active_slide").fadeIn(1000);
resetSlides();
}).removeClass("active_slide");
});
});
});
});
});
so, i think i found the solution. the animation was the problem. cause there were multiple devices and graphs with my code-structure each device was firing the function code, so device1 fired, then the two graphs fired two time, then device2 fired them again and so on.
with the .promise().done() structure all is just fired once, the animation works and all events are just fired once. now it should work too that i bind the elements in the .on()-statements, cause now they should bind only once then...but...nevah change a running system ^^
$("li#slide3").on("click", $("div.slide3"), function(ev) {
$("#slide3 .device").animate({opacity:1}, 1000).promise().done(function() {
$("#slide3 .device").animate({opacity:0}, 1000).promise().done(function() {
console.log("slide3-height: "+$("li#slide3 img.graph_adds3").data("height"));
$("li#slide3 img.graph_adds3").animate({height:$("li#slide3 img.graph_adds3").data("height")}, 1500).promise().done(function() {
console.log("slide3 click");
if(!$("a#book").hasClass("slide_4") ) {
$("a#book").addClass("slide_3"); }
});
});
}).promise().done(function() { console.log("div.slide3 anim don") });
});
Here is JQuery command that removes all bindings from the element:
$("#book_container").unbind(); //to flush previously bound actions

Categories

Resources