jQuery touchstart on multiple element - javascript

I looking for a solution for iOS, like hover in the 'desktop world'.
I have a lot of image item on my page, and when the user move his finger across the images, the actual image gets opacity 0. (so one move hides all item :) )
I tried something like this:
$("img").on "touchstart", ->
$(this).animate({opacity:0}, 100)

If you want to hide all images when one recive the touchstart-event you should use:
$("img").on("touchstart", function() {
$("img").animate({opacity:0}, 100);
});
Or even better:
var $images = $("img").on("touchstart", function() {
$images.fadeTo(100, 0);
});
The this keyword refers the the DOM Element receiving the event rater then the whole jQuery collection.
Not good with CoffeeScript.
$(document.body).on "touchmove", (event) ->
if $(event.target).is("img")
$(event.target).animate
opacity: 0
, 100

Related

JQuery/JavaScript hide one clicked element but not others

I'm creating a JavaScript and JQuery "Whack-a-Mole" game, and I'm appending "mole" images at random coordinates into the gamespace every two seconds. When a mole is clicked, I would like it to hide (disappear from the screen). However, the way I have the code written now, clicking on one mole causes all mole images to be hidden. Would love to hear any thoughts on selecting and hiding only the clicked mole image, but not hiding the other mole images.
Here's my "addMole" function:
function addMole() {
xPos = randPosX();
yPos = randPosY();
$('#gamespace').append('<img src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole'); // insert mole into #gamespace
repeatAddMole = setTimeout("addMole()", 2000); // append moles every 2 seconds
};
And here's the game's main function:
$(document).ready(function() {
$('#start_button').click(function() {
start();
$('#timer').show(); // show timer
$('.mole').on("click", function(){
incScore();
$('img', this).hide();
});
});
Thanks!
You are adding the mole class to the #gamespace, not the image. Maybe you want this:
$('#gamespace').append($('<img src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole'));
Here's a demo to help you https://jsfiddle.net/bradlis7/ubar2Lzb/1/. I like to keep the functions doing what they say they are doing (addMole should not really be setting a new timer).
You can do it like this:
$('#gamespace').append('<img onclick="this.style.display=\'none\'" src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole'); // insert mole into #gamespace
Also the problem is cause you attach event only to created images (moles) before you clicked on start.
You can use event delegation. Use this code out of start button click handler.
$( "#gamespace" ).on( "click", "img", function( event ) {
incScore();
$(this).hide();
});
I would do it pretty much in this way:
function addMole() {
xPos = randPosX();
yPos = randPosY();
var el = $('#gamespace').append('<img src="img/mole.png" style="top:'+yPos+'px;left:'+xPos+'px" />').addClass('mole');
el.on("click", function(){
$(this).remove();
incScore();
});
repeatAddMole = setTimeout("addMole()", 2000);
};
append function returns you jQuery object of appended element, so you can attach event directly on it after it is created. If you create events before objects are created, events will not be attached to it. This way, you create element and then attach the event.
You could do it in the way mhodges wrote in his comment, but I simply don't like this way because I believe it's not that efficient.

How to avoid hover/mouseenter being called again when creating child elements dynamically

I'm dynamically creating a box inside an element, say A, whenever the user hovers over A. The box, B, is then moved around with the mouse. B should only appear when the user is hovering over A (i.e. it is removed on mouseleave).
Unfortunately, if I dynamically create elements inside B, when the mouse moves over them, the hover event is called again (creating a new B). This issue seems to happen when I dynamically create B's children on the mouse move. At first I thought it was to do with bubbling, and needing to delegate, but now I feel it has to do with the fact I'm emptying the box and filling it again (thereby causing the hover event to fire again)?
This example illustrates what I'm having a problem with:
https://jsfiddle.net/shzy6gtx/
function positionBox(element, position) {
element.css({
top: position - element.parent().offset().top - 10,
});
element.empty();
jQuery('<span />').appendTo(element).text(position);
}
$(document).bind('mousemove', function(e) {
if ($('#theBox').length <= 0)
return;
positionBox($('#theBox'), e.pageY);
});
$('.hover').hover(function(e) {
var innerBox = jQuery('<div />', {
id: 'theBox',
class: 'inner',
}).appendTo(this);
positionBox(innerBox, e.pageY);
}, function(e) {
$('#theBox').remove();
});
This is how it should work (without the dynamically created span tags):
https://jsfiddle.net/dffyt6gx/
If this is something I can't solve, how else can this be accomplished?
For me the problem in fact looks like both:
an event-bubbling problem.
a problem with the repeated rapid creation of the position-span
My theory is that when the label is destroyed with .empty() while the mouse is hovering the position label, and it is not added back again fast enough, this will be considered as another mouse-enter event.
Now 1. can be solved by simply adding
if (e.delegateTarget != e.target)
return;
to the hover event handler. You can observe notice that the problem occurs way less often.
For 2.
One simple solution would be to not create the label again every time the mouse (and B) are moved.
have a look at https://jsfiddle.net/IARI/w8y1y3vt/
If for some reason you want to or have to create the element(s) inside B every time this wont help. However if it is possible not to recreate them I would advise you to do so, if only for performance reasons.
If simply checking, whether B exists is an option for you, that would solve it as well while allowing you to recreate the position-label - https://jsfiddle.net/IARI/shzy6gtx/6/
Don't know if this can help you but you are assigning a #id to each div and trying to work with those elements an #id must be unique in the DOM.
$(document).bind('mousemove', function(e) {
if ($('.inner').length <= 0)
return;
positionBox($('.inner'), e.pageY);
});
$('.hover').hover(function(e) {
var innerBox = jQuery('<div />', {
id: 'theBox',
class: 'inner',
}).appendTo(this).click(function(e) {
});
positionBox(innerBox, e.pageY);
}, function(e) {
$('.inner').remove();
});
Maybe this can give you a clue
Added a fiddle
You can move the handler out.
**$('body').on('click','#theBox', function(e){
alert('event handler'); });**
$('.hover').hover(function(e) {
var innerBox = jQuery('<div />', {
id: 'theBox',
class: 'inner',
}).appendTo(this);
jQuery('<span />').appendTo(innerBox).text('number');
positionBox(innerBox, e.pageY);
}, function(e) {
$('#theBox').remove();
});

jQuery: mouseover makes image visible that has the same last 4 numbers in their id as the trigger

I am currently working on a website and got stuck with the following problem:
On the website I have small dots (images) with the ids "dot0001", "dot0002", "dot0003", etc. . I also have hidden images (visibility:hidden) with the ids "info0001", "info00002", "info0003", etc.
I am looking for a jQuery solution. What I need is a code that allows the following events:
When users move the mouse over "dot0001" the image "info0001" becomes visible and when they leave "dot0001", "info0001" becomes invisible again. Same applies to "dot0002"-"info0002" , "dot0003"-"info0003" etc. So only the info-images with the corresponding 4 digit number become visible.
I gave it endless tries but got nowhere and there is not even a point in pasting my code.
Any help appreciated!
Something like this should work (though untested):
$('[id^="dot"]').on({
mouseenter: function(e) {
var infoId = this.id.replace('dot', 'info');
$('#' + infoId).show();
},
mouseleave: function(e) {
var infoId = this.id.replace('dot', 'info');
$('#' + infoId).hide();
}
});
That uses an attribute-starts-with selector to select all elements with an id beginning with "dot", then binds the event handlers to them. The event handler functions themselves simply replace the "dot" part of the id with "info" to form the correct new one, then show or hide the element as appropriate.
Don't forget to wrap that code in a DOM ready event handler so that it executes once the elements actually exist, otherwise it won't work.
Get all elements which id starts with "dot" and show/hide related "info" on mouseover/out:
$("[id^=dot]").hover(
function(){
$("#info" + this.id.substring(3)).css({"visibility":"visible"});
},
function(){
$("#info" + this.id.substring(3)).css({"visibility":"hidden"});
}
);
http://jsfiddle.net/EGBnR/

Set time delay between two frames on mouseover

I have to display two images for single mouseover. So when I mouseover to the image, first, the image is displayed then with a time delay of 5000, the image is needed to display for that same hover. Now on mouseout display the original image.
I am not so familiar with JavaScript and jQuery.
Can someone please give me some idea about how to do this.
What i did is,
$('.image1').mouseover(function() {
setInterval($(this).removeClass(.image1).addClass('image-over1'),5000);
$(this).removeClass(.image1).addClass('image-over2');
});
$('.image1').mouseout(function() {
$(this).removeClass('image-over1');
$(this).removeClass('image-over2').addClass(item);
});
$('.image1').click(function(){
document.location='index.php?page='index.php';
})
The .hover() function lets you specify both mouseover/mouseout at the same time, and you need to make a function for the setInterval:
$('.image1').hover(function(evt) {
// mouse over function.
// DOM Element that got the mouseover.
var target = evt.target;
if (target.timer) {
clearTimeout(target.timer);
target.timer = null;
}
target.timer = setInterval(function() {
// $(this) will not work here, since 'this' has changed.
// depending on your css you shouldn't need to remove the '.image1'
// class, just make sure .image-over1 and .image-over2 are
// stronger selectors, or occur after .image1
$('.image1').addClass('image-over2');
// at this point your element will be (just guessing <img>, could be
// anything really:
// <img class="image1 image-over1 image-over2" .../>
// it's absolutely fine for the image to have all those classes as
// long as your css is correct.
}, 5000);
$('.image1').addClass('image-over1');
}, function(evt) {
// mouse out function.
// DOM Element that got the mouseout.
var target = evt.target;
if (target.timer) {
clearTimeout(target.timer);
target.timer = null;
}
$('.image1').removeClass('image-over1');
$('.image1').removeClass('image-over2');
});
$('.image1').click(function(){ document.location='index.php?page='index.php'; })
First of all, I think there's a problem in your approach; if you remove the "image1" class from the element on a mouseover, then that element won't be matched by the $(".image1") selector for the mouseout. Is there a reason you need to remove it? If you do (i.e. if there is something defined on the class in the CSS that you need to disable), is there some other selector you could match on?
As to the time delay, if you're using a jQuery version greater than 1.4, you can use the .delay() function:
$('.image1').mouseover(function() {
$(this).addClass('image-over1').delay(5000).addClass('image-over2');
});
Perhaps you to create an animated GIF of these images??? Then use a code similar to here: http://www.netmechanic.com/news/vol3/design_no10.htm
Even if the images are generated on fly, it is possible to programtically generate animated gif in PHP - see http://php.net/manual/en/function.imagegif.php

js/jQuery Drag'n'Drop, recalculate the drop targets

I have the following issue, I have a large tree which has subnodes which can be folded and unfolded on demand (the data within nodes gets fetched with AJAX). However, I use jquery.event.drop/drag to create my drag/drop targets.
However, when I fold/unfold the drop targets change position and I need to recalculate. This is how I wanted to do that:
function create_drop_targets() {
$('li a')
.bind('dropstart', function(event) {
})
.bind('drop', function(event) {
})
.bind('dropend', function(event) {
});
}
create_drop_targets() is called upon fold/unfold.
However, this doesn't work. I have located the following within jquery.event.drop:
var drop = $.event.special.drop = {
setup: function(){
drop.$elements = drop.$elements.add( this );
drop.data[ drop.data.length ] = drop.locate( this );
},
locate: function( elem ){ // return { L:left, R:right, T:top, B:bottom, H:height, W:width }
var $el = $(elem), pos = $el.offset(), h = $el.outerHeight(), w = $el.outerWidth();
return { elem: elem, L: pos.left, R: pos.left+w, T: pos.top, B: pos.top+h, W: w, H: h };
}
Now I need to know how I can call the setup() method again so it repopulates $elements with the new positions for the droppables.
Just had the same issue. I wandered around within the source-code of jQuery and found this (in ui.droppable.js):
drag: function(draggable, event) {
//If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
if(draggable.options.refreshPositions) $.ui.ddmanager.prepareOffsets(draggable, event);
...
So, you'd just have to use
$(".cocktails").draggable({
refreshPositions: true,
});
Seems not to be documented very much... but it fixed my problem. Makes everything a bit slower of course, I would advise some usage-dependent tweaking (enable it before the changes occur, and disable it once the user has moved his mouse and the changes have occured).
Maybe it will be better to add live events introduced in jQuery 1.3?
$("li a").live("dropstart", function(){...});
I ran into the same issue when I tried to combine scrolling with draggable rows in liteGrid, but I found a work-around. Your mileage may vary, but what I did was add logic to my drag event handler that would check to see if the grid was being scrolled (which is when I needed to force the droppable positions to be refreshed), and if so, I set refreshPositions to true on the draggable. This doesn't immediately refresh the positions, but it will cause them to refresh the next time the drag handle moves. Since refreshPositions slows things down, I then re-disable it the next time my drag event handler fires. The net result is that refreshPositions is enabled only when the grid is scrolling in liteGrid, and its disabled the rest of the time. Here's some code to illustrate:
//This will be called every time the user moves the draggable helper.
function onDrag(event, ui) {
//We need to re-aquire the drag handle; we don't
//hardcode it to a selector, so this event can be
//used by multiple draggables.
var dragHandle = $(event.target);
//If refreshOptions *was* true, jQueryUI has already refreshed the droppables,
//so we can now switch this option back off.
if (dragHandle.draggable('option', 'refreshPositions')) {
dragHandle.draggable('option', 'refreshPositions', false)
}
//Your other drag handling code
if (/* logic to determine if your droppables need to be refreshed */) {
dragHandle.draggable('option', 'refreshPositions', true);
}
}
$("#mydraggable").draggable({
//Your options here, note that refreshPositions is off.
drag: onDrag
});
I hope that saves you from ramming your head into the keyboard as many times as I did...
I realize the original question is quite old now, but one little trick I came up with to refresh the position of draggable elements without much overhead (AFAICT) is to disable and immediately re-enable them wherever appropriate.
For instance, I noticed that resizing my browser window would not refresh the position of my draggable table rows, so I did this:
$(window).resize(function () {
$(".draggable").draggable("option", "disabled", true);
$(".draggable").draggable("option", "disabled", false);
});
I hope this helps someone out there!

Categories

Resources