Animation in javascript works every other time - javascript

I get a dropdown-toggle (id="actions") with image (id=imgAction) in html. I added script in javascript
$(document).ready(function() {
var el = document.getElementById("actions");
if (el.addEventListener)
el.onmouseover = tadaAnimation;
function tadaAnimation() {
$(imgAction).toggleClass('animated tada');
}
});
and it works but every second time. Why it doesn't work every time I hover the dropdown-toggle.

Main problem area it that you are binding only mouseover event handler. You also need to attach mouseout event handler
Every time your mouse enters or leaves a child element, mouseover is triggered, but not mouseenter. So I would recommend you to use mouseenter instead of mouseover
As you are using jQuery bind event using it. I would suggest you to use .hover()
$(document).ready(function () {
function tadaAnimation() {
$("#imgAction").toggleClass('animated tada');
}
$("#actions").hover(tadaAnimation, tadaAnimation)
});

$(document).ready(function() {
var el = document.getElementById("actions");
if (el.addEventListener)
el.onmouseover = tadaAnimation;
el.onmouseout = tadaAnimation; // add this line, should works
function tadaAnimation() {
$(imgAction).toggleClass('animated tada');
} });

Related

Why does my removeEventListener not work?

I am working on building a simple script where a user click's either a blue button or a red button. When the blue button's are clicked the one the user clicks on should fade out, which works fine. However if the user clicks the red button then the fade out on the blue will stop. Like I said the blue buttons work but the red one doesn't.
Looking at various questions and answers on here and other sites I believe that the code I have is correct and it seems that the reason it won't work is because they don't match, i.e. I am not actually removing the add event.
The code I have is below and any help would be appreciated, I am using Adobe Animate to code in:
instance = this;
instance.stop();
//Buttons array
var lowerQuestions = [instance.BTN1, instance.BTN2, instance.BTN4];
//Add an event listener to each button in the array
addEventListeners();
function addEventListeners(){
lowerQuestions.forEach(function(element) {
element.addEventListener("click", function(){
console.log('add listener');
addButtonValue(element);
},false);
});
}
//Remove event listeners when BTN3 is clicked
instance.BTN3.addEventListener("click", removeEventListeners)
function removeEventListeners(){
console.log('prevent');
lowerQuestions.forEach(function(element) {
element.removeEventListener("click", function(){
console.log('remove listener');
addButtonValue(element);
//console.log('hit me here');
},false);
});
}
//Event listener function
function addButtonValue(element){
instance.addEventListener("tick", fadeOut);
element.alpha = 1;
function fadeOut(){
element.alpha -= 0.15;
if(element.alpha <= 0){
instance.removeEventListener("tick", fadeOut);}
}
}
For remove event listener of the element you have two choice. 1- make a copy of element and replace with this one. 2- put name for listener function and pass it to remove event listener.
In your code i suggest first solution. This code can help you, for every single element that you want remove listener should run this code :
function removeEventListeners(){
console.log('prevent');
lowerQuestions.forEach(function(element) {
var cln = element.cloneNode(true);
element.parentNode.appendChild(cln);
element.parentNode.removeChild(element);
});
}
Are anonymous functions able to handle removeEventListener? discusses why anonymous function expressions are not great for event listeners that need to be removed - function expressions produce a different function object each time they are executed, so the remove function never matches the added function.
A simple solution in this case is to create the listener using a standard named function declaration:
function buttonClicked(){
addButtonValue( this);
}
addEventListeners();
function addEventListeners(){
lowerQuestions.forEach(function(element) {
element.addEventListener("click", buttonClicked, false);
});
}
which make the listeners removable by name:
//...
lowerQuestions.forEach(function(element) {
element.removeEventListener("click", buttonClicked, false);
});
//...

Referring to tooltip within event listener to keep it open on hover

Finding myself in a bit of a strange position where I have to reference the tooltip within an instantiation for all tooltips.
$('body').tooltip({
selector: '[data-toggle="tooltip"]',
html: true,
animation: false,
}).on("mouseenter", function (e) {
e.stopPropagation();
var _this = e.target;
$(_this).tooltip("show");
$(".tooltip").on("mouseleave", function () {
$(_this).tooltip('hide');
});
}).on("mouseleave", function (e) {
e.stopPropagation();
var _this = e.target;
setTimeout(function () {
if (!$(".tooltip:hover").length) {
$(_this).tooltip("hide");
}
}, 300);
});
That being said, how can I:
Reference the actual element that is triggering this jQuery call
Keep the tooltip open while either the actual tooltip or element that generated it are being hovered over?
Here is a link to a JSFiddle prototype:
https://jsfiddle.net/cwv57weu/8/
Within your '.on()' call, you can add an 'event' argument to your anonymous function. This will contain all of the data from the event including the element which triggered the event (it will be referenced as 'target').
}).on("mouseenter", function (event) {
$(event.target).tooltip("show");
})
the event argument contains a ton of data, I would play around with it by console.log(event) within your anonymous function to get a feel as to what data is available to you.
Use event.target.
$('body').tooltip({
selector: '[data-toggle="tooltip"]',
html: true,
animation: false,
}).on("mouseenter", function (e) {
var _this = e.target;
$(_this).tooltip("show");
$(".tooltip").one("mouseleave", function () {
$(_this).tooltip('hide');
});
}).on("mouseleave", function (e) {
var _this = e.target;
setTimeout(function () {
if (!$(".tooltip:hover").length) {
$(_this).tooltip("hide");
}
}, 300);
});
e.target is the actual element that the event originated on, while this is the element that the event listener was attached to (equivalent to e.currentTarget).
Note that because of event bubbling, the event will fire on all the containing elements up to body. You may want to use e.stopPropagation() to prevent bubbling, so you only process the deepest element.
I also changed the mouseleave handler on .tooltip to use .one(). Otherwise, every time you enter something, you'll add another mouseleave handler to all the tooltips, without removing the previous one, and soon there will be thousands of handlers running (this is why it's generally wrong to bind event handlers inside other event handlers). I'm not really sure you need both that mouseleave handler and the one you attach to body.

Unbind and rebind click on css transition end

I'm having troubles with the .bind() and .unbind() features. When the button is clicked, it's supposed to change the color of the box. During this time, the button is disabled by unbinding the click function. However, I'm having issues rebinding the click when the css transition completes.
What I have so far is:
$('button').on('click', function(){
$('button').unbind('click');
$('.box').toggleClass('color');
$('.box').one('webkitTransitionEnd transitionend', function(e){
console.log('transition ended')
$('button').bind('click')
});
});
http://jsfiddle.net/t6xEf/
You need to pass the click handler when binding it. So create a function reference then use it while binding the handler.
function click() {
$('button').off('click.transition');
$('.box').toggleClass('color');
}
$('.box').on('webkitTransitionEnd transitionend', function (e) {
console.log('transition ended')
$('button').on('click.transition', click)
});
$('button').on('click.transition', click);
Demo: Fiddle
Also look at the usage of namespaces while registering/removing the handler because if there if some other click handler added to the button we don't want to disturb it
Also do not add a event handler inside another one
Also have a look at .one()
function click() {
$('.box').toggleClass('color');
}
$('.box').on('webkitTransitionEnd transitionend', function (e) {
console.log('transition ended')
$('button').one('click.transition', click)
});
$('button').one('click.transition', click);
Demo: Fiddle
I would use a flag instead of binding/rebinding the event handler:
var animating = false;
$('button').on('click', function() {
if (animating) return;
animating = true;
$('.box').toggleClass('color')
.on('webkitTransitionEnd transitionend', function(e) {
animating = false;
});
});
http://jsfiddle.net/t6xEf/1/
Do not unbind. Use a boolean:
var onTrans = false;
$('button').on('click', toggle);
function toggle() {
if (!onTrans){
$('.box').toggleClass('color');
onTrans = true;
$('.box').on('webkitTransitionEnd transitionend', function (e) {
onTrans = false;
});
}
}
http://jsfiddle.net/jp8Vy/
This is surely not what you want to do. It seems overly complex, and I can't imagine a good use case scenario.
That being said, you need to reattach the functionality to be performed in the final bind statement. You call the function to bind to the click event, but don't tell the function what to attach.
You need something like this:
$('button').bind('click', function() { ... });
However, that probably isn't what you really want. It sounds like you just want to set the button's "disabled" attribute to false, then to true after the animation.

Best way to catch mouseup outside of mousedown element

$('#clickableElement').bind({
mousedown: function(e)
{
console.log('mousedown on element');
$(document).bind('mouseup',function(e){
console.log('mouseup caught');
//Do some magic here
$(this).unbind('mouseup');
});
},
mouseup:function(e)
{
//mouseup within element, no use here.
}
});
I'm trying to catch the mouseup event from a mousedown that's released inside or outside of an element. This code almost works, but the problem is the unbind('mouseup') which is unbinding other scripts attached to the mouseup event (jqueryui). If unbind() is not set then the code gets stacked within mouseup event and called x number of times, where x is the times you've mousedowned.
Route 1: is there some kind of self destructing function that calls itself once and destroys?
Route 2: any way to copy/clone the mouseup function prior to inserting the code, then unbind, then set as previous?
Ideally I'd like to keep this code structure for neatness as I have lots of clickable elements, so binding the document.mouseup outside of element.mousedown would be messy.
Here's the Fiddle I forgot to add http://jsfiddle.net/9gFNk/
Can giv your click event a namespace so only that namespaced event gets unbound, and not any others
$(document).on('mouseup.clickableElement',function(e){
console.log('mouseup caught');
//Do some magic here
$(this).off('mouseup.clickableElement');
});
I created a global object to catch mouse events from the document. It's currently set for mouseup only but can be easily expanded for others. The mouseup code is still customizable within the mousedown functions of the clickable elements so it this handy if you have lots of clickable things like I do.
var MouseCatcher=function()
{
this.init=function()
{
var mc = this;
$(document).bind({
mouseup:function(e)
{
mc.mouseup();
}
});
}
this.mouseup=function()
{
return false;
}
}
var mouseCatcher = new MouseCatcher();
mouseCatcher.init();
$('#clickableElement').bind({
mousedown: function(e)
{
console.log('mousedown on element');
mouseCatcher.mouseup=function()
{
console.log('mouseup called from MouseCatcher');
this.mouseup = function(){return false;}
}
},
mouseup:function(e)
{
//mouseup within element, no use here.
}
});
With "on" event its possible, its may not be an exact solution. Please refer this code
$(document).on('mousedown', function() {
$('#clickableElement').css('display', 'none');
$(document).bind('mouseup', function() {
$('#clickableElement').css('display', 'block');
});
});
http://jsfiddle.net/9gFNk/13/

How to write onshow event using JavaScript/jQuery?

I have an anchor tag on my page, I want an event attached to it, which will fire when the display of this element change.
How can I write this event, and catch whenever the display of this element changes?
This is my way of doing on onShow, as a jQuery plugin. It may or may not perform exactly what you are doing, however.
(function($){
$.fn.extend({
onShow: function(callback, unbind){
return this.each(function(){
var _this = this;
var bindopt = (unbind==undefined)?true:unbind;
if($.isFunction(callback)){
if($(_this).is(':hidden')){
var checkVis = function(){
if($(_this).is(':visible')){
callback.call(_this);
if(bindopt){
$('body').unbind('click keyup keydown', checkVis);
}
}
}
$('body').bind('click keyup keydown', checkVis);
}
else{
callback.call(_this);
}
}
});
}
});
})(jQuery);
You can call this inside the $(document).ready() function and use a callback to fire when the element is shown, as so.
$(document).ready(function(){
$('#myelement').onShow(function(){
alert('this element is now shown');
});
});
It works by binding a click, keyup, and keydown event to the body to check if the element is shown, because these events are most likely to cause an element to be shown and are very frequently performed by the user. This may not be extremely elegant but gets the job done. Also, once the element is shown, these events are unbinded from the body as to not keep firing and slowing down performance.
You can't get an onshow event directly in JavaScript. Do remember that the following methods are non-standard.
IN IE you can use
onpropertychange event
Fires after the property of an element
changes
and for Mozilla
you can use
watch
Watches for a property to be assigned
a value and runs a function when that
occurs.
You could also override jQuery's default show method:
var orgShow = $.fn.show;
$.fn.show = function()
{
$(this).trigger( 'myOnShowEvent' );
orgShow.apply( this, arguments );
return this;
}
Now just bind your code to the event:
$('#foo').bind( "myOnShowEvent", function()
{
console.log( "SHOWN!" )
});
The code from this link worked for me: http://viralpatel.net/blogs/jquery-trigger-custom-event-show-hide-element/
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
$('#foo').on('show', function() {
console.log('#foo is now visible');
});
$('#foo').on('hide', function() {
console.log('#foo is hidden');
});
However the callback function gets called first and then the element is shown/hidden. So if you have some operation related to the same selector and it needs to be done after being shown or hidden, the temporary fix is to add a timeout for few milliseconds.

Categories