How to effect the hovered div with jQuery via it's class? - javascript

I have a jQuery function which, on the events mouseover and mouseout of the <div>s with the class .myshp_list_product_image, changes their src attribute.
The issue is that when I hover one of them, it also changes the others.How can I make it only change the one being hovered?
Here's the code of the function:
$(function() {
$('.myshp_list_product_image').mouseover(function() {
$('.myshp_list_product_image').each(function() {
var $this = $(this);
$this.attr('src', $this.attr('src').replace('1s', '2s'));
});
});
$('.myshp_list_product_image').mouseout(function() {
$('.myshp_list_product_image').each(function() {
var $this = $(this);
$this.attr('src', $this.attr('src').replace('2s', '1s'));
});
});
});

You don't need .each() here, get rid of it. You just need to target the current element i.e. this.
$(function() {
$('.myshp_list_product_image').mouseover(function() {
var $this = $(this);
$this.attr('src', $this.attr('src').replace('1s', '2s'));
});
$('.myshp_list_product_image').mouseout(function() {
var $this = $(this);
$this.attr('src', $this.attr('src').replace('2s', '1s'));
});
});
I would recommend you to use mouseenter and mouseleave event, A small demo for the difference between mouseover and mouseenter

I would use .hover() from jQuery
$(function () {
$('.myshp_list_product_image').hover(function () { // mouse in
var $this = $(this);
$this.attr('src', $this.attr('src').replace('1s', '2s'));
}, function () { // mouse out
var $this = $(this);
$this.attr('src', $this.attr('src').replace('2s', '1s'));
});
});

Just target the currently hovered/hovered out element instead of iterating over all elements with same class.
Also you can use .hover instead of mouseover and mouseout and callback function of .attr() to minimize your code:
$('.myshp_list_product_image').hover(
function() {
$(this).attr('src',function(i,oldattr){return oldattr.replace('1s', '2s')});
}, function() {
$(this).attr('src',function(i,oldattr){return oldattr.replace('2s', '1s')});
});

Related

jQuery: prevent multiple firing fadeOut or any animation

I want to click on Item1, replace the label "Item1" with "Saved", then fade out the button after 500ms and place back the label "Item1" (saved in var currentText)
If I click the button multiple times it fires too many times. How can I prevent that?
$('body').on('click', ".item", function() {
var currentText = $(this).text();
$(this).text('Saved!').delay(500).fadeOut("fast", function() {
$(this).text(currentText).css('display', '');
});
});
This could be solved with a simple flag indicating that you are in the process of fading it out.
var isFadingOut = false;
$('body').on('click', ".item", function() {
if (isFadingOut) {
return;
}
isFadingOut = true;
var currentText = $(this).text();
$(this).text('Saved!').delay(500).fadeOut("fast", function() {
$(this).text(currentText).css('display', '');
isFadingOut = false;
});
});
Note: this solution works globally. So if you have multiple different buttons on screen that you want to be able to fade out simultaneously, this will not work. If that's the case, something more like what #Phiter wrote would be better.
I'd do something like this:
$('body').on('click', ".item", function() {
if ($(this).data('off')) return;
$(this).data('off', true);
var currentText = $(this).text();
$(this).text('Saved!').delay(500).fadeOut("fast", function() {
$(this).text(currentText).css('display', '');
$(this).data('off', false);
});
});
The function will not execute while the button has the off data. Kinda like Mike's answer but without the global variable.
Can use not(':animated'). The :animated pseudo selector is used internally by jQuery and is only active when an animation is in progress
$('body').on('click', ".item", function() {
var currentText = $(this).text();
$(this).not(':animated').text('Saved!').delay(500).fadeOut("fast", function() {
$(this).text(currentText).css('display', '');
});
});

Expand on click, collapse on click outside

I have an element which I want to expand on click and then collapse on click outside and thus came up with the following code. However when I run this it will start to expand and then immediately collapse since both functions are called sequentially. I don't understand why and how to solve this.
jQuery(document).ready(function() {
var element = jQuery("#search-main");
var defaultWidth = jQuery("#search-main").css('width');
var expandWidth = "200px";
var fnSearch = {
expand : function() {
jQuery(element).animate({
width : expandWidth
});
jQuery(document).bind('click', fnSearch.collapse);
},
collapse : function() {
jQuery(element).animate({
width : defaultWidth
});
event.stopPropagation();
jQuery(document).unbind("click", fnSearch.collapse);
}
}
jQuery("#search-main").bind("click", fnSearch.expand);
});
You are having the problem because the #search-main click event is propagating to the document; i.e. first the #search-main click event triggers, then the document click event triggers. Click events do this by default. To stop this event propagation, you want to use http://api.jquery.com/event.stoppropagation/ in your expand function:
jQuery(document).ready(function() {
var element = jQuery("#search-main");
var defaultWidth = jQuery("#search-main").css('width');
var expandWidth = "200px";
var fnSearch = {
expand : function(event) { // add event parameter to function
// add this call:
event.stopPropagation();
jQuery(element).animate({
width : expandWidth
});
jQuery(document).bind('click', fnSearch.collapse);
},
collapse : function() {
jQuery(element).animate({
width : defaultWidth
});
jQuery(document).unbind("click", fnSearch.collapse);
}
}
jQuery("#search-main").bind("click", fnSearch.expand);
});
That said, Jason P's solution is better for what you want. It's more reliable and less messy, since you don't have to bind stuff to the document, which can easily become hard to track and cause conflicts with other code if you use that strategy habitually.
You could unbind the click event from the #search-main element after clicking, or stop the propagation of the event, but I would recommend binding to the blur and focus events instead:
http://jsfiddle.net/6Mxt9/
(function ($) {
$(document).ready(function () {
var element = jQuery("#search-main");
var defaultWidth = jQuery("#search-main").css('width');
var expandWidth = "200px";
$('#search-main').on('focus', function () {
$(element).animate({
width: expandWidth
});
}).on('blur', function () {
$(element).animate({
width: defaultWidth
});
});
});
})(jQuery);
That way, it will work even if the user tabs in or out of the field.

Set Variable inside (document).ready for all functions?

Really new to jQuery and this had been baffling me for a while.
I'll use this as an example:
$(document).ready(function(){
$("#link1 a").hover(function(){
var $this = $(this);
$this.css("color", "#fff");
});
});
Obviously enough, this will change the color of the a inside #link1 to white on hover.
THIS is what I was trying to do:
$(document).ready(function(){
var $this = $(this);
$("#link1 a").hover(function(){
$this.css("color", "#fff");
});
$("#link2 a").hover(function(){
$this.css("color", "#f00");
});
});
This doesn't work.
Am I able to set var $this = $(this); inside (document).ready so it works with all functions inside it?
Sorry if this is a silly question, couldn't find an answer anywhere else. Wasn't 100% sure to search for if I'm honest!
your statement var $this = $(this); while valid, doesn't achieve what you need. If you think about it... THIS is referring to $(document)
So, if you change your code to this :
$(document).ready(function(){
$("#link1 a").hover(function(){
var $this = $(this);
$this.css("color", "#fff");
}); //In this case $this refers to $("#link1 a")
$("#link2 a").hover(function(){
var $this = $(this);
$this.css("color", "#f00");
}); //In this case $this refers to $("#link2 a")
});
however, that is not really necessary, as you can just do this :
$(document).ready(function(){
$("#link1 a").hover(function(){
$(this).css("color", "#fff");
});
$("#link2 a").hover(function(){
$(this).css("color", "#f00");
});
});
Now if you wanted to increase the scope of $this you can do something like so :
$(a).hover(function() {
var $this = $(this);
//now if you wanted to check for which link is currently hovered you can say this :
var link = $this.attr("id");
//this will set link equal to the current id
//NOW you can have if statements checking which link it is...
if(link == "link1") { ... do stuff }
if(link == "link2") { ... do other stuff }
}
also, if you are using JQuery version POST 1.7 you should be calling events like so :
$(a).on("hover", function () {
...some function
});
Lastly, don't be afraid to look at the JQuery API for some help with things... it is very well written and provides examples
https://api.jquery.com/
No, but you could select everything -
$(document).ready(function() {
$this = $('*'); // all elements in the DOM for this page
});
I don't recommend it though, why are you doing this?

How can I trigger a 'focusout' after I click on an element?

I have the following markup:
<select style="display:none">
<option value='1'>1</option>
<option vlaue='2'>2</option>
</select>
<input type="text" id="comboBox" />
<ul id="comboBoxData" style="display:none">
<li id='1'>1</li>
<li id='2'>2</li>
</ul>
and the following JQuery code:
$(document).ready(function() {
$('select').each(function() {
var parent = this;
$('#comboBoxData').on('click', 'li', function() {
var value = $(this).prop('id');
$(parent).val(value);
$('#comboBox').val(value);
});
});
$('#comboBox').bind('focusin', function () {
$('#comboBoxData').show();
});
$('#comboBox').bind('focusout', function () {
$('#comboBoxData').hide();
});
});
When I click on one of the LI's the 'comboBoxData' element disappears before the click trigger happens. Is there a way around this or an alternate event that I can use instead to have the same effect as a focusout?
Put mouseenter and mouseleave events and change the value of a global variable say isOver.
$('select').each(function() {
var parent = this;
$('#comboBoxData').on('click', 'li', function() {
var value = $(this).prop('id');
$(parent).val(value);
$('#comboBox').val(value);
$('#comboBoxData').hide();
});
});
$('#comboBoxData').mouseover(function(){
isOver = true;
}).mouseleave(function(){
isOver = false;
});
$('#comboBox').bind('focusin', function () {
$('#comboBoxData').show();
});
$('#comboBox').bind('focusout', function () {
if(!isOver){
$('#comboBoxData').hide();
}
});
You do not require this:
$('#comboBox').bind('focusout', function () {
$('#comboBoxData').hide();
});
instead use this inside $('#comboBoxData').on('click', 'li', function() {
if you are fine with plugin , you could just use this way:
$('#menu').bind('clickoutside', function (event) {
$(this).hide();
});
You can get that plugin here
Also, I have changed the code without using the plugin:
Please check the updated answer:
DEMO
try with blur() function
$('#comboBox').blur(function () {
$('#comboBoxData').hide();
});
The blur event is sent to an element when it loses focus.
from http://api.jquery.com/blur/
Not exactly elegant but it works.
$("body").click(function(event){
if(!$(event.target).is("#comboBoxData") && !$(event.target).is("#comboBox") ){
$("#comboBoxData").hide(); }
});
$(document).ready(function() {
$('select').each(function() {
$('#comboBoxData').on('click', 'li', function() {
var value = $(this).prop('id');
$('#comboBox').val(value);
$('#comboBoxData').hide();
});
});
$('#comboBox').bind('focusin', function () {
$('#comboBoxData').show();
});
});

How to tell what type of element an event was triggered on

I am using the following module to reveal a sub menu:
icisSite.fatNav = function(trigger){
function init() {
width = 0,
$mainMenuListEl = $('.nav-SiteNav .nav-list > li'),
$subNav = $('.subNav > li > ul');
appendSubNav();
getWidth();
};
function appendSubNav(){
$subNav.each(function(index){
index = ++index;
$(this).appendTo($mainMenuListEl[index]);
});
};
function subNavShow(trigger){
setWidth(trigger);
trigger.toggleClass('hover');
};
function subNavHide(trigger){
trigger.toggleClass('hover');
trigger
.find('ul')
.removeAttr('style');
};
function getWidth(){
$mainMenuListEl.each(function(index){
width += parseInt($(this).outerWidth());
});
width = width - 11;
};
function setWidth(trigger){
trigger
.find('ul')
.css({'width': width});
};
return {
setup: init,
show: subNavShow,
hide: subNavHide
};
}();
icisSite.fatNav.setup();
$('.nav-SiteNav .nav-list > li:gt(0)').hover(function() {
$this = $(this);
icisSite.fatNav.show($this);
},function(e) {
icisSite.fatNav.hide($this);
});
$('.nav-SiteNav .nav-list > li:gt(0) a').focusin(function() {
var $this = $(this);
$this
.parent()
.toggleClass('hover');
$this
.parent()
.find('ul')
.css({'width': icisSite.width});
});
$('.nav-SiteNav .nav-list > li:gt(0) a').focusout(function() {
var $this = $(this);
$this
.parent()
.toggleClass('hover');
$this
.parent()
.find('ul')
.removeAttr('style');
});
I want to refactor to accomodate the focusin and focusout events. As the code is very similar to the hover event but not the same.
I am unsure how to do this other than checking the type of element that 'trigger' is and wondered if there is a better way?
I am not even sure how to retrieve the type of element either? So if it was a hover it would return an li element and a focus an anchor element.
If you want to test if a jQuery object is something you can simply use .is()
if($(this).is('li')){
}
if($(this).is('a')){
}
Also, you might be able to refactor you focusin, focusout some as well by checking the event.type
not tested, but might look something like this...
$('.nav-SiteNav .nav-list > li:gt(0) a').bind("focusin, focusout", function(event) {
var $this = $(this);
$this
.parent()
.toggleClass('hover');
$this
.parent()
.find('ul');
if(event.type =="focusout"){
$this.removeAttr('style');
}
else
{
$this.css({'width': icisSite.width});
}
});
Wouldn't
$(this).get(0).tagName
be a better way of getting the type of tag, instead of going
if($(this).is('li')){
}
?

Categories

Resources