Jquery - .one does not unbind - javascript

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

Related

How to trigger jquery event handler only if events happened in a specific order?

I have the following case. I'm using Bootstrap tabs with MarionetteJS. Whenever a tab click event is fired, I would like to call my handler only after show.bs.tab event is fired for this tab. I do not want to fire my handler if only shown.bs.tab event is fired, since ocassionally I show specific tabs programmatically by calling tab('show') method.
So basically only call handler after the following sequence of events click -> shown.bs.tab
The way I got it to work is the following:
var clicked = false;
this.$el.on('click', 'a[data-toggle="tab"]', function(e) {
clicked = true;
});
this.$el.on('shown.bs.tab', 'a[data-toggle="tab"]', function(e) {
if (clicked === true) {
var moduleId = $(this).attr("data-module");
App.vent.trigger("resultTabClicked", {
module: moduleId
});
}
clicked = false;
});
This is a far cry from an elegant solution is there a better way to achieve this? Perhaps with promises?
If you want to avoid global variables you could attach data to the element itself.
this.$el.on('click', 'a[data-toggle="tab"]', function(e) {
$(this).data('clicked', true);
});
And then
if ($(this).data('clicked') === true) {
...
}
.data() is a jQuery method by the way but you can attach the status anyway you see fit
You can attach the handler to both events and then use event.type and event.timeStamp to keep track of the order in which the events have happened. In the common handler, the event with the highest timestamp happened last; this should help determine when you've struck the right order so as to fire the desired code. See the concept verification demo below:
$(function() {
var times = {click:0,mouseenter:0,mouseleave:0};
$('div.mydiv').on('mouseenter mouseleave click', function(e) {
times[e.type] = e.timeStamp;
$('div.out').text( JSON.stringify( times ) );
});
});
div
{
padding: 20px;
margin: 10px;
border:1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="mydiv">hover or click HIRE</div>
<div class="out"></div>

setTimeout triggering too quickly

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.

Add onRightClick to JavaScript lib Hypertree

I'm currently working (a repo is here) on a Hypertree graph, which I want to use from the JavaScript InfoVis Toolkit. The issue is as follows: I added the specific events to the Hypertree, which are onClick and onRightClick.
Events: {
enable: true,
onClick: function(node, eventInfo, e) {
ht.controller.onComplete();
},
onRightClick: function(node, eventInfo, e) {
ht.controller.onComplete();
},
},
Then I simply attached the veent handlers to the Hypertree labels, just modifying demo-code a little:
//Attach event handlers and add text to the
//labels. This method is only triggered on label
//creation
onCreateLabel: function(domElement, node){
domElement.innerHTML = node.name;
$jit.util.addEvent(domElement, 'click', function () {
ht.onRightClick(node.id, {
onComplete: function() {
ht.controller.onComplete();
}
});
});
$jit.util.addEvent(domElement, 'rclick', function () {
ht.onClick(node.id, {
onComplete: function() {
ht.controller.onComplete();
}
});
});
},
That's pretty straight forward. The documentation for Hypertree events is in Options.Events.js. Now I load the page... and I have the left.clicks. But no right clicks... I want the RightClicks to move the graph and the onClicks to open a link from the DOM Element node. Can someone please give me a pointer here?
Best,
Marius
$jit.util.addEvent(obj, type, fn) is a shortcut for obj.addEventListener(type, fn, false). So you are trying to bind to 'onrclick' event. But there is no such event in javascript. For detecting right click you just need to replace your 'rclick' to 'mouseup', and in callback you should check for button to be the right one. Here is the code:
$jit.util.addEvent(domElement, 'mouseup', function (event) {
// detecting right button
if (event.button != 2) {
return;
}
ht.onClick(node.id, {
onComplete: function() {
ht.controller.onComplete();
}
});
});
Also you don't need to use Options.Events.js for this purpose, so you can remove that code
The only fault I can see in the "Events"-section, is a trailing comma behind onRightClick. It really shouldn't affect the code if you use IE>8, but it's worth a try.
Ok, this is an answer on why I think your solution is not working.
$jit.util.addEvent(domElement, 'rclick', function ()
There is no such jquery event as 'rclick'.
Typically using jquery you would detect a right-click using the following:
$('#element').mousedown(function(event) {
if (event.which === 3) {
alert('Right mouse button pressed');
}
});
Hence in your example you would use 'mousedown' instead of 'rclick'. However, looking at the documentation for addEvent:
$jit.util.addEvent(elem, 'click', function(){ alert('hello'); });
The example seems to suggest that the event object can not be passed in to addEvent's function parameter, meaning that it won't be possible to detect that the right mouse button has been clicked.
Might be worth posting your question directly to InfoVis' author, as I too will be interested to see whether it is possible to hook-up the right mouse button.

Jquery chaining a click event does not trigger

My hover events are triggered, if I removed the hovered events, click still does not get triggered. What could be the problem?
items = '<li></li>';//some html content
list.html(items);
list.show().children().
hover(function () {
alert('hover');
}, function () {
alert('gone');
}).
click(function () {
alert('clicked'); //this is never reached when I click a list item.
});

How can I bind events to the appended element?

I tried to show an error message using the jquery effect fadeTo and tried to hide the message by appending a button and using fadeout but doesn't seem to work.
What I did was:
$("#sub_error")
.fadeTo(200, 0.1, function()
{
$("#sub_error")
.html(error.join("<br/><br/>"))
.append('<br/><input type="button" name="err_ok" id="err_ok" value="ok">')
.addClass('subboxerror')
.fadeTo(900,1);
});
$("#err_ok").click(function()
{
$("#sub_error").fadeOut("slow");
});
What am I doing wrong, could someone help me?
the #err_ok element doesn't exist at first so the .click() handler is not applied to it.
You can solve this by putting
$("#err_ok").click(function () {
$("#sub_error").fadeOut("slow");
});
in a function and call the function after creating the element in the DOM.
Edit: This should be a full solution:
$("#sub_error").fadeTo(200, 0.1, function() {
$("#sub_error")
.html(error.join("<br/><br/>"))
.append('<br/><input type="button" name="err_ok" id="err_ok" value="ok">')
.addClass('subboxerror')
.fadeTo(900, 1);
bindEvents();
});
function bindEvents() {
$("#err_ok").click(function() {
$("#sub_error").fadeOut("slow");
});
}
There is also a "live" function that binds events to future created DOM elements too.
FWIW, there are filed tickets about fadeTo/fadeOut bugs on the JQuery bug tracker.
There are a couple of ways to do this. One, you can append the click handler to the element after it is inserted:
$("#sub_error").fadeTo(200, 0.1, function() {
$("#sub_error")
.html(error.join("<br/><br/>"))
.append('<br/><input type="button" name="err_ok" id="err_ok" value="ok">')
.addClass('subboxerror')
.fadeTo(900, 1)
.find('#err_ok')
.click( function() {
$("#sub_error").fadeOut("slow");
});
});
Or two, you can use the live event handler so that any element with the "err_ok" id will get the click handler whenever it's created.
$('#err_ok').live('click', function() {
$('#sub_error').fadeOut('slow');
});

Categories

Resources