Jquery change values mouseover - javascript

I wrote this code but it doesn't work:
JavaScript:
$(function() {
var menu_h_number=5
for (i=1; i<=menu_h_number; i++)
{
$(".web_header_mb_"+i).show(1000);
$(".web_header_mb_"+i).css("background", "#FF0000");
$(".web_header_mb_"+i).hover(function ()
{
$(".web_header_mb_"+i).css("width", "200");
});
$(".web_header_mb_"+i).mouseout(function ()
{
$(".web_header_mb_"+i).css("width", "300");
});
}
});
HTML:
<div id="menu" class="web_header_mb_1"></div>
<div id="menu" class="web_header_mb_2"></div>
<div id="menu" class="web_header_mb_3"></div>
<div id="menu" class="web_header_mb_4"></div>
<div id="menu" class="web_header_mb_5"></div>
When start show different ids in the bucle but when I do a mouseover, there's no change to the size.

Why it doesn't work
The reason your code doesn't work is this:
i will have the correct value for code that is executed immediately (e.g. the show and hover calls). But, because of the way JavaScript works, this doesn't work for callback (such as the one you give to hover). JavaScript will remember the variable, not the value of the variable at the time the callback was provided. The callback won't be called until after the loop is completed. That's why in the callbacks i will always be 5, because that was i's last value.
You can read more about that here: Closures (MDN)
Also, be aware that id's must be unique. You can't give the id "menu" to five different elements; that's what classes are for. In other words: you've got id and class backwards in your code.
How to make it work
The easiest way to circumvent the closure "problem" is to use $(this) inside the callback functions. In jQuery, the this keyword inside a callback function always points to the object which triggered the event. By using $(this) you have exactly the right jQuery object, without any fuss:
for (i=1; i<=menu_h_number; i++)
{
var currentItem = $(".web_header_mb_" + i);
currentItem
.show(1000)
.css("background", "#FF0000");
.hover(
function() { // mouseenter
$(this).css("width", 200); // <--
},
function() { // mouseleave
$(this).css("width", 300); // <--
});
}
Another thing I did in the code above is buffer the jQuery object in a local variable (currentItem). This makes your code faster, because you only have to look up the element once (instead of 6 times, in this case). You should do this as much as possible.
Also, as you can see, the hover function isn't just for the mouseover event. You can give it callbacks to handle both mouseover and mouseout.
One other thing you could do, as others have already suggested, is use a single class instead of 5 different classes. The jQuery function ($()) will actually return a collection if the query matches more than one object.
So, given the following HTML:
<div class="menu web_header_mb"></div>
<div class="menu web_header_mb"></div>
<div class="menu web_header_mb"></div>
<div class="menu web_header_mb"></div>
<div class="menu web_header_mb"></div>
You could use each(), like this:
$(".menu.web_header_mb").each(function() {
$(this)
.show(1000)
.css("background", "#FF0000");
.hover(
function() { // mouseenter
$(this).css("width", 200);
},
function() { // mouseleave
$(this).css("width", 300);
});
});
Or even this:
$(".menu.web_header_mb").
.show(1000)
.css("background", "#FF0000");
.hover(
function() { // mouseenter
$(this).css("width", 200);
},
function() { // mouseleave
$(this).css("width", 300);
});
That last one works because show(), css() and hover() all work on jQuery collections (as well as single jQuery objects). Neat, huh?

Its because the i variable is not in scope or has the latest value when the hover code is executed. Instead use this variable.
Fyi:
1. your div tag are having same ID but different classname. Instead, make them same class and different ID. Than you can make use of jQuery.each function very nicely.
hover function can have 2 arguments, first for mousein and second for mouseout. That way you can concise your code

try to use this
$(function(){
var menu_h_number=5;
for (var i=1; i <= menu_h_number;i++) {
$(".web_header_mb_"+i).show(1000)
.css("background","#FF0000")
.mouseover(function () {
$(this).css("width","200");
})
.mouseout(function () {
$(this).css("width","300");
});
}
});
Also available on jsfiddle

jQuery.hover() actually takes two arguements, mouse in and mouse out.
$(".web_header_mb_"+i).hover(
function () { $(this).css("width","200px") },
function () { $(this).css("width","300px") }
);
Actually, looking at the code, that's not really a good way of doing it. Here try it this way: Gave all the divs the same class instead iterating with a for loop, and use the $.each to give the desired events.
<div id="menu" class="web_header_mb"></div>
<div id="menu" class="web_header_mb"></div>
<div id="menu" class="web_header_mb"></div>
<div id="menu" class="web_header_mb"></div>
<div id="menu" class="web_header_mb"></div>
$.each(".web_header_mb", function (){
$(this).hover(
function () { $(this).css("width","200px") },
function () { $(this).css("width","300px") }
);
});

There's no need to loop over elements, jQuery does that for you if you just figure out the selector.
Try matching every element that has a class that starts with web_header_mb_ and then just remove elements that you don't want. If they have the right index you can :lt(5) or slice(0,5), otherwise you'll have to filter them based on the last character of the class. You can also chain methods, no need to call the selector every time :
$("[class^='web_header_mb_']").filter(function() {
var C = $(this).prop('class');
C = C.charAt(C.length-1);
return (C==1||C==2||C==3||C==4||C==5);
}).show(1000)
.css("background","#FF0000")
.on('mouseenter mouseleave', function() {
$(this).css('width', e.type==='mouseenter'?'200':300);
});
or
$("[class^='web_header_mb_']:lt(5)").show(1000)
.css("background","#FF0000")
.on('mouseenter mouseleave', function() {
$(this).css('width', e.type==='mouseenter'?'200':300);
});

Related

Prototype event handler

I've defined the following HTML elements
<span class="toggle-arrow">▼</span>
<span class="toggle-arrow" style="display:none;">▶</span>
When I click on one of the elements the visibility of both should be toggled. I tried the following Prototype code:
$$('.toggle-arrow').each(function(element) {
element.observe('click', function() {
$(element).toggle();
});
});
but it doesn't work. I know everything would be much simpler if I used jQuery, but unfortunately this is not an option:
Instead of iterating through all arrows in the collection, you can use the invoke method, to bind the event handlers, as well as toggling them. Here's an example:
var arrows = $$('.toggle-arrow');
arrows.invoke("observe", "click", function () {
arrows.invoke("toggle");
});
DEMO: http://jsfiddle.net/ddMn4/
I realize this is not quite what you're asking for, but consider something like this:
<div class="toggle-arrow-container">
<span class="toggle-arrow" style="color: pink;">▶</span>
<span class="toggle-arrow" style="display:none; color: orange;">▶</span>
</div>
document.on('click', '.toggle-arrow-container .toggle-arrow', function(event, el) {
var buddies = el.up('.toggle-arrow-container').select('.toggle-arrow');
buddies.invoke('toggle');
});
This will allow you to have multiple "toggle sets" on the page. Check out the fiddle: http://jsfiddle.net/nDppd/
Hope this helps on your Prototype adventure.
Off the cuff:
function toggleArrows(e) {
e.stop();
// first discover clicked arow
var clickedArrow = e.findElement();
// second hide all arrows
$$('.toggle-arrow').invoke('hide');
// third find arrow that wasn't clicked
var arw = $$('.toggle-arrow').find(function(a) {
return a.identify() != clickedArrow.identify();
});
// fourth complete the toggle
if(arw)
arw.show();
}
Wire the toggle arrow function in document loaded event like this
document.on('click','.toggle-arrow', toggleArrows.bindAsEventListener());
That's it, however you would have more success if you took advantage of two css classes of: arrow and arrow-selected. Then you could easily write your selector using these class names to invoke your hide/show "toggle" with something like:
function toggleArrows(e) {
e.stop();
$$('.toggle-arrow').invoke('hide');
var arw = $$('.toggle-arrow').reject(function(r) {
r.hasClassName('arrow-selected'); });
$$('.arrow-selected').invoke('removeClassName', 'arrow-selected');
arw.show();
arw.addClassName('arrow-selected');
}

Removing elements and then adding them again

I've got this document tree sub-tree:
<div id="content">
<div class="tile"></div>
<div class="tile"></div>
<div class="tile"></div>
</div>
What I'm trying to achieve is to empty the childNodes of #content, and then populate it again with <div>s having the class="tile".
Here is what I've done.
$(".tile").fadeOut( showTileSpeed, function() {
$(this).remove();
});
tiles[tileIndex]();// function adding .tiles to my #content
$(".tile").first().fadeIn(showTileSpeed, function showNext() {
$(this).next(".tile").fadeIn(showTileSpeed, showNext);
});
It seems that the .tiles are added before the remove() is called so that nothing happens on screen...
Does anyone have an explanation for this behavior? It appears that adding a timer is not a good solution.
Thanks!
$(this).remove(); is called showTileSpeed milliseconds after fadeOut was called. But tiles[tileIndex]() is called immediately after fadeOut was called.
You should add the tiles again once all the tiles have been removed. You can achieve this by passing the selected elements to $.when [docs] and register a callback (with .done() [docs]) on the returned promised object. The callback gets called once all animations have been completed:
var $tiles = $(".tile").fadeOut(showTileSpeed, function() {
$(this).remove();
});
$.when($tiles).done(function() { // <-- after all animations do this
tiles[tileIndex]();
$(".tile").first().fadeIn(showTileSpeed, function showNext() {
$(this).next(".tile").fadeIn(showTileSpeed, showNext);
});
});
See also Execute complete function only once in jQuery animation? (especially this answer).
Update: Since it seems that calling .remove() interferes with the tests for the animation state, moving the call to .remove() might be a better solution:
var $tiles = $(".tile").fadeOut(showTileSpeed);
$.when($tiles).done(function() {
$tiles.remove();
tiles[tileIndex]();
$(".tile").first().fadeIn(showTileSpeed, function showNext() {
$(this).next(".tile").fadeIn(showTileSpeed, showNext);
});
});
But if you only want to update the content of the elements, you don't have to remove them from the DOM.
I'm not sure what exactly you mean? Anyway, take look at this, is this what you need?
$(document).ready(function() {
$(".tile").fadeOut( showTileSpeed, function() {
$(this).remove();
tiles[tileIndex]();// function adding .tiles to my #content
$(".tile").first().fadeIn(showTileSpeed, function showNext() {
$(this).next(".tile").fadeIn(showTileSpeed, showNext);
});
});
});

clearTimeout not working in nested function

I think it's got something to do with the nested functions, but they need to be this way. Why isn't it working? Am I doing something stupid? This is an isolated example and I must be using $(this), so it seems I have to nest the functions?
HTML:
<div class="box"></div>
<ul>
<li>Hover box, it turns blue. Leave box, it turns red after 2 secs.</li>
<li>If you hover back onto box before 2 secs is up, it's supposed to clear timer and keep box blue.</li>
<li>It doesn't clear timer and after 2 secs the box still turns red. Why?</li>
</ul>
JavaScript:
var t;
$('.box').on('mouseenter', function() {
$thisBox = $(this);
clearTimeout(t);
$thisBox.addClass('blue');
$thisBox.on('mouseleave', function() {
t = setTimeout(function() { $thisBox.removeClass('blue'); }, 2000);
})
});
​JSFiddle: http://jsfiddle.net/ddbtZ/7/
Thanks for looking :)
http://jsfiddle.net/ddbtZ/3/
Your .on() shouldn't be nested. Effectively, that's attaching a new handler for every time you hover over the element.
EDIT: As per question clarification.
Use .one() instead of .on()
http://jsfiddle.net/ddbtZ/8/
Move your mouseleave from mouseenter event and it will work.
var t;
$('.box').on('mouseenter', function() {
clearTimeout(t);
$('.box').addClass('blue');
});
$('.box').on('mouseleave', function() {
t = setTimeout(function() {
$('.box').removeClass('blue');
}, 2000);
})​;
DEMO: http://jsfiddle.net/ddbtZ/4/

initialize jquery after append

I have a list of blocks, for each block their is a css change by jquery on mouseover/out.
I have a button that is job is to add one more block to the list.
It do it great! But the new block not respond to the mouseover/out jquery set.
This is my blocks and the add:
<div class='blocks'>
<div class='block'>
<div class='block-top'></div>
Default Text Here
</div>
<div class='block'>
<div class='block-top'></div>
Default Text Here
</div>
<div class='block'>
<div class='block-top'></div>
Default Text Here
</div>
</div>
<a href='#' id='addBlock'>Add Block</a>
And this is the javascipt:
$(document).ready(function() {
var inEdit=0;
$(".block").hoverIntent(function() {
if(inEdit==0) {
$(this).children('.block-top').delay(300).animate({opacity:1},600);
$(this).delay(300).animate({borderColor: '#8f8f8f'},600);
}
},function() {
if(inEdit==0) {
$(this).children('.block-top').animate({opacity:0},200);
$(this).animate({borderColor: '#ffffff'},200);
}
});
$('#addBlock').click(function() {
$('.blocks').append("<div class='block'><div class='block-top'></div>Default Text Here</div>");
});
});
I'm using this two scripts:
http://www.bitstorm.org/jquery/color-animation/
http://cherne.net/brian/resources/jquery.hoverIntent.html
What can I do?
Thanks
If you wish that future elements benefits from the event, you have to use on : http://api.jquery.com/on/
For instance :
$('#addBlock').on('click', function() {
$('.blocks').append("<div class='block'><div class='block-top'></div>Default Text Here</div>");
});
You are binding the hoverintent to the element which doesnt exist on load. Therefore the new element wont get the event handler. You have to use .Delegate() or .on()/.off() depending on your version of jQuery Information on how to use each can be found below
http://api.jquery.com/delegate/
http://api.jquery.com/on/
However as hoverIntent uses jquerys mouseover i dont know if it has a specific eventType you can use for delegate/on
This question is about using hoverIntent on new elements. There is exactly this other thread about the same thing, check out the answer :
help with understanding the logic behind how javascript executes on new dom elements being created on the fly
make use of jquery live() method, i.e) use below codes
$(".block").live('hoverIntent', function() { //this line is modified
if(inEdit==0) {
$(this).children('.block-top').delay(300).animate({opacity:1},600);
$(this).delay(300).animate({borderColor: '#8f8f8f'},600);
}
},function() {
if(inEdit==0) {
$(this).children('.block-top').animate({opacity:0},200);
$(this).animate({borderColor: '#ffffff'},200);
}
});
make some adjustments to add 2 functions for the event 'hoverIntent'. I mean this will work
$(".block").live('hoverIntent', function() { //this line is modified
if(inEdit==0) {
$(this).children('.block-top').delay(300).animate({opacity:1},600);
$(this).delay(300).animate({borderColor: '#8f8f8f'},600);
}
});
but to have 2 functions you can try like
$(".block").live('hoverIntent', function() { //this line is modified
if(inEdit==0) {
$(this).children('.block-top').delay(400).animate({opacity:1},600);
$(this).delay(400).animate({borderColor: '#8f8f8f'},600);
}
if(inEdit==0) {
$(this).children('.block-top').animate({opacity:0},200);
$(this).animate({borderColor: '#ffffff'},200);
}
});

jquery simple swap p element?

Given a p element like so:
<p>Something</p> I want to, when the user mouses over it, we have, instead <p>go here</p>
After hovering if the mouse leaves the p area, return to the previous:
<p>Something</p> state.
Can I have a simple example of something like this?
Thanks a lot,
MEM
Or a simple modification of Ken Redler's original that uses .data() to keep track of things:
$('p#someID').hover(
function() {
var $this = $(this);
$this.data('orig', $this.html()).html('go here');
},
function() {
var $this = $(this);
$this.html($this.data('orig')).removeData('orig');
}
);
http://www.jsfiddle.net/ambiguous/FhET2/1/
Updated: As #Phrogz points out, I missed part of the sense of the question. The suggestions of capturing state with a closure or using data() are good ones, but here's another way (with an amusing number of moving parts):
$(document).ready( function(){
$('p#someID').hover(
function() { // on mouseEnter
$(this)
.contents()
.wrap('<span class="hide"/>') // wrap 'n' hide
.end() // back to 'this'
.append('Fascinating Link!'); // add link
}, function() { // on mouseLeave
$(this)
.find('a')
.remove() // kill the anchor
.end() // back to 'this'
.find('span.hide') // the wrapper
.contents() // the wrapped
.unwrap(); // kill the wrapper, leaving its contents
});
});
This assumes a style like so:
span.hide {
display: none;
}
Updated example: http://www.jsfiddle.net/redler/HAGzH/1/
$('p#IDHERE').hover(
function(){ // on mouseEnter
$(this).contents().replaceWith('go here');
},
function(){ // on mouseLeave
$(this).contents().replaceWith("something");
}
);
This will replace all text

Categories