Unexpected ionicons behaviour - javascript

Consider this code.
I cannot figure out why it behaves as it does. All I need is the play icon alternating with pause icon everytime I click anywhere inside the <td>. It behaves as expected when I click inside the <td> but outside the icon itself. However, if I click on the icon itself, it behaves fine the first time, and then stops.
'The ionicon is wrapped in the <a> tag, which is a child of the <td> element. The event listener is on the <td>, so what could be the problem?
Thanks.

As #Vijai said your problem with the hover event .. And While I don't know a lot about your project and you really need .empty() on hover or you just need to hide() the icon .. You can try this part of code instead of yours
var hovOn = function(event) {
if($(this).find('a').length < 1){
$(this).html(playButtonTemplate);
}else{
$(this).find('a').show();
}
};
var hovOff = function(event) {
$(this).find('a').hide();
}
Codepen Here

Ok, figured it out. It seems like an artefact that arises from creating an element from a template and the way mouseenter is implemented.
The problem is that the mouseenter event (hoverOn part of the .hover()) triggers when it shouldn't. Each time a new ionicon is created from a template it will trigger the mouseenter event if the cursor moves a little.
Logically mouseenter shouldn't be triggered when the element appears, because mouseenter should trigger when a listener element or its descendent is hovered over, and then only call when the cursor leaves all of the elements associated with the event and then enters again. I think this is an artefact of creating an element from a template like that. Maybe it's because DOM get updated and it discards the fact that the cursor is already within the element. So mouseenter triggers again and in turn triggers creating a new play icon. Then it repeats..
This codepen should explain it well. If you hover over the play button the mouseenter counter will increment each time you move your mouse even a little, because each time a mouse is moved, a new play button is created. If you delete the line that creates a new play button, it behaves as mouseenter should, triggering only when the cursor enters the element.

When you click on the <a> tag it seems it is also triggering the parent <td> hover event. Once solution is try the below code for hover.
var hovOn = function(event) {
if(playOrPause==='play') {
$(this).html(pauseButtonTemplate);
playOrPause = 'pause';
} else {
$(this).html(playButtonTemplate);
playOrPause = 'play';
}
};

Related

Removing a listener class doesn't stop a sound event associated Jquery Javascript

I'm playing a sound when hovering on an image (this is working fine already) and want to include a button to turn this off if desired. Unfortunately I haven't been able to make it work.
My current code goes like:
For creating the sound
//a bunch of code to generate the audio that ends on
var mouseoversound = createsoundbite('mysound.mp3')
For triggering it
$(".play").mouseover(function() {
mouseoversound.play();
});
The listener element
<%= image_tag "image.png", class:'logo-image play' %>
I thought that the simplest solution for disabling it was to remove the class 'listening' for the event (i.e. '.play') in the element listener, so I tired:
$(".sound").click(function(){
$(".logo-image").removeClass("play");
});
//.sound is the class of the button that's intended to block it.
Although the latter script does successfully remove the class 'play' the sound keeps playing every time I hover over the image. What am I missing? shouldn't the sound just stop playing?
Do you see any other solution to this?
Cheers
The issue is because the event handler is bound to the element. Removing the class after the event is bound does not affect that binding. To affect the event handler, you can call off(), like this:
$(".sound").click(function(){
$(".logo-image").off('mouseover');
});
Alternatively, if you want to toggle the sound functionality based on the class, you can keep your current logic and check that the element still has the class in the mouseover handler:
$(".logo-image").mouseover(function() {
if ($(this).hasClass('play') {
mouseoversound.play();
}
});
$(".sound").click(function(){
$(".logo-image").toggleClass("play");
});

.focus() not working on textarea in hover event

So I have this code here.
timeline.afterMilestonePrototypeCreated = function() {
$(MILESTONE_PROTOTYPE_SELECTOR).hover(function(e){
$(this).find('textarea').focus();
});
}
Which should focus the textarea element after it was created. Everything works fine, I've even checked if the event is being called, after creation and hovering. Every other code works, but I'm not able to focus that textarea element. After some googling I've tried to add a setTimeout, which didn't work neither.
Thanks!
SOLVED:
The parent element of the textarea is a dot, and after hovering the dot it becomes a bigger circle and than it's inner elements are becoming visible. The problem was, that when adding the timeout the duration I've set was to short so the css transition for making the textarea visible was still going that's way it wasn't focusing.
Instead of this:
$(this).find('textarea').focus();
Try this:
$(e.target).find('textarea').focus();
This may work, as long as $(this).find('textarea') works as expected:
timeline.afterMilestonePrototypeCreated = function() {
$(MILESTONE_PROTOTYPE_SELECTOR).hover(function(e){
e.preventDefault();
$(this).find('textarea').focus();
});
}
A hover event triggers a focus event, so preventing it will allow the manual focus to occur.

jQuery Click Event Triggering On Multiple Elements (I only want 1)

When my overlay comes up, everything works well, but I added some code to close out the overlay, but this code gets triggered even when I'm just clicking my arrows. The following is the code that's being triggered, which is fine when I'm not clicking the arrows to change the image. But when I click the arrows, the background which is the overlay is also being trigger, so the image is changing but the overlay is also hiding.
$('#overlay').click(function() {
$(this).fadeOut('slow');
});
How can I be able to use the arrows without it also clicking on the background overlay? If you open up the project, you will see what I'm saying.
To open the project:
https://htmlpreview.github.io/?https://github.com/rodriguesandrewb/photo_gallery_v1/blob/master/index.html
To open the repository:
https://github.com/rodriguesandrewb/photo_gallery_v1
You want to use event.stopPropagation(): https://api.jquery.com/event.stoppropagation/
This prevents the event from bubbling (being triggered by other elements)
Your outter most element is #overlay. It means that no matter where you click you'll be always clicking on your #overlay element. That is way your callback is being always triggered and closing your image.
To fix your problem and make your image close only when clicking on it you could use:
$('#changeImage').click(function() {
$(this).closest('#overlay').fadeOut('slow');
});
Ok, there's a ton of code to sort out, so I'm guessing your overlay is
<div id="overlay" style="display: block;"></div>
and your event.target is deep down inside this:
<div class="mainCenter">
<div class="container">
<div id="topFixed">
<input type="text" id="search" placeholder="Search">
</div>
<ul id="gallery">
.......
I'm not 100% sure where your event.target is, (the element you want to click and not everything else). But it's safe to assume that after you click your intended button, the event continues to bubble up the event chain. The event chain is basically your event.target's ancestors which includes#overlay` which is at the very top of the event chain.
To prevent event bubbling (btw bubbling is the default behavior but in instances such as your's it's not desired.) try placing stopPropagation() after or inside at the end of your event handler.
I wish I could be more specific as to where and how to apply this code as it pertains to your source, but you didn't provide the specific areas that concern your eventListeners, eventHandlers, etc...
The #overlay is used in this example but I suggest you use the event.target parent instead. The purpose of this code is to accept an event like 'click' on an element (i.e. button) or multiple elements (i.e. buttons) through their mutually shared parent. That's one place to click for potentially several different buttons. At first you'd think that's non-sense and you'd say, "Sure that button is clicked because the parent was clicked, but now everything the parent is chained to will trigger everything else."
That would be correct except we have stopPropagation(); at the very end of your eventHandler. That will stop propagation of the event bubbling back up the event chain, so there's no more rogue triggers lighting up everywhere. Rogue Triggers® sounds like a great band name. :P
For details and a much better explanation: http://www.kirupa.com/html5/handling_events_for_many_elements.htm
var overlay = document.querySelector("#overlay");
theParent.addEventListener("click", doSomething, false);
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}

JavasScript changing DOM in mouse-event

I have 2 DIVs and in each DIV there's a Button which does something on click.
Now I've added a piece of code to bring the DIVs to front when they get a mousedown. Which works very well. The problem is, that they swallow the mousedown of the inner button... The inner button can only be clicked by double clicking it.
http://jsfiddle.net/nUtz6/
$('div').mousedown(function (event) {
$(this).parent().append($(this));
});
how could I solve this problem? I did it this way because I don't want to increment the z-index of the CSS property to some magic number everytime I click the div. I read that jquery also does the DOM manipulation trick.
The problem seems to occur because I change the DOM right before the click-Event of the button. If I don't do anything in the mousedown, everything works fine.
Just check that the DIV is actually the target of the event :
$('div').mousedown(function (event) {
if (event.target.tagName.toLowerCase() != 'button')
$(this).parent().append($(this));
});
FIDDLE

How can I bind a JQuery event to make it only fire once?

I have a help popup that I want to close when somewhere else is clicked. Here's what I have:
$('.help[data-info]').click(function(){
$('.info[a complicated selector]').toggle(400);
$('*:not(.info[the complicated selector]).one('click','',function(){
.info[the complicated selector].hide(400);
});
})
But one() isn't what I want before it fires for each element on the page. I only want it to fire once.
It looks like you are attaching event handlers to every element in your dom except the help popup? Hmm...
How about this:
Create a single "mask" div that overlays the entire screen, but is transparent (opacity: 0.0). Attach the click event handler only to that mask div. Then open up the info div on top of the overlay div. Clicking anywhere on the page, other than the info div, the event will be captured by the mask div before it gets to anything under it. In your event handler, hide() the info div, and remove the mask div altogether. While testing/experimenting with this, start with a partially opaque mask, not fully transparent).
Make use of a boolean variable and set it to true after first click, so it doesn't trigger the action again:
$('.help[data-info]').click(function() {
var clicked = false;
$('.info[a complicated selector]').toggle(400);
$('*:not(.info[the complicated selector]').one('click','',function() {
if (!clicked) {
.info[the complicated selector].hide(400);
clicked = true;
}
});
})
A couple of options:
You can use the blur event instead of binding a click event to everything but your popup.
Add a transparent, full-page div between the popup and the rest of the page. A click event on the transparent div could handle the hiding.
If you only want to fire once across all your elements, then you may have to manually unbind all the event handlers when any one is clicked or use a flag:
$('.help[data-info]').click(function(){
$('.info[a complicated selector]').toggle(400);
var sel = $('*:not(.info[the complicated selector]);
function hideInfo() {
.info[the complicated selector].hide(400);
sel.unbind('click', hideInfo);
}
sel.bind('click', hideInfo);
})

Categories

Resources