I've seen other similar questions to this on SO but the answers weren't quite what I'm looking for. My problem with the code below is about the variable hide.
In it's current form hide won't be visible to the first hover function, but I don't want to declare it at a higher scope because it has no use there. Plus declaring it at a higher scope would require making a different variable for every li.
What's the solution for keeping this variable containing a timeout between these two functions?
$('li').hover(function() {
clearTimeout(hide);
$('.menu', this).show();
}, function() {
var menu = $('.menu', this);
var hide = setTimeout(function() {
menu.hide();
}, 500);
});
You can store the value with .data()
$('li').hover(function() {
clearTimeout($(this).data('hide'));
$('.menu', this).show();
}, function() {
var menu = $('.menu', this);
$(this).data('hide', setTimeout(function() {
menu.hide();
}, 500));
});
Related
I am trying to pass through a reference to an item selected by the user (so that the appropriate Javascript effects can be run on it), but it doesn't seem to be working. Initially it was, but when I refactored my code to make it easier to read, it stopped. I reckon it is an issue with the logic I am using, can anyone please show me how to correct it.
New code - not working but easier to read
$('.timeline-item').click(function() {
expandTimelineDetail( $(this));
});
function expandTimelineDetail($obj) {
// UI effect
$obj = $(this).css("background-color", "#F5F5F5");
setTimeout(function () {
$obj.css("background-color", "#FFFFFF");
}, 250);
// Make timeline item active
$obj.addClass("active-item");
$obj.next().addClass("active-item").css('display', 'block');
// Hide the rest of the timeline items that are not active
$('#timeline > :not(.active-item)').hide();
$('#leftspan').css('visibility', 'visible');
$('.search-container').css('display', 'none');
// Hide relative departure time, show actual departure time
$('.actual-time').css('display', 'inline');
$('.leaving-time').css('display', 'none');
}
Old code - working fine but difficult to read
$('.timeline-item').click(function() {
var $this = $(this).css("background-color","#F5F5F5");
setTimeout(function() {
$this.css("background-color","#FFFFFF");
}, 250);
$(this).addClass("active-item");
$(this).next().addClass("active-item").css('display','block');
$('#timeline > :not(.active-item)').hide();
$('#leftspan').css('visibility','visible');
$('.search-container').css('display','none');
$('.actual-time').css('display','inline');
$('.leaving-time').css('display','none');
});
You are passing $(this) to the function where you assign another value to $obj argument.
You can bind this to function:
expandTimelineDetail.bind(this);
Where you will be able to access this as you did before
Or just don't reassign $obj variable.
I have the following function. To make a long story short, I have 4 divs that I want to apply an init class to. The init class essentially shows the 4 divs.
It works as it should, however it shows all 4 divs at the same time, which is not what I want. I want to show 1 div, then the next, then the next, etc.
Where am I going wrong?
$('.campaign-item').waypoint({
handler: function() {
var $this = $(this);
$this.each(function(i) {
setTimeout(function() {
$this.addClass('init');
}, i * 500 );
});
},
offset: '60%'
});
$('.campaign-item').each(function (i) {
var $this = $(this);
$this.waypoint({
handler: function() {
setTimeout(function() {
$this.addClass('init');
}, i * 500 );
},
offset: '60%'
});
});
You need to add the class to each individual element, not to all of them.
var $this = $(this);
$this.each(function(i,v){
setTimeout(function(){
$(v).addClass('init');
}, i * 500 );
});
I think your problem is that a jQuery object contains a collection of the objects that match your selector. "$(this)" is that collection. The "each" function gives you access to the individual elements in that collection with the returned second parameter ("function(index, element)"). In your code you are trying to add your "init" class to every member of the collection because "$this" IS the entire collection. You need to add the class to the second parameter returned in each iteration of your each function.
I'm learning how to use objects to help organize my code and give it some structure but I've run into a problem. I don't understand how to set the $(this) from inside of one function to the $(this) of another function.
I'm researching call and apply but I can't seem to grasp how it works in this scenario.
cloneCard and clickCard is where I'm having the problem. I want to pass the $(this) that is referenced when I click the card to the cloneCard function.
Here is my code so far (updated to reflect the answer):
var Modal = {
init: function(config) {
this.config = config;
this.clickCard();
this.removeModal();
this.clickOutside();
this.createClose();
},
clickCard: function() {
$this = this;
this.config.boardOutput.on('click', '.card', function(event) {
$this.showOverlay();
$this.cloneCard.call($(this));
$this.createClose();
});
},
cloneCard: function() {
this.clone()
.replaceWith($('<div/>').html(this.html()))
.removeClass('card')
.addClass('modal')
.css("margin-top", $(window).scrollTop())
.prependTo('body');
},
showOverlay: function() {
this.config.overlay.show();
},
removeModal: function() {
$('.modal').remove();
$('.overlay').hide();
},
clickOutside: function() {
this.config.overlay.on('click', this.removeModal);
},
createClose: function() {
$('<span class="close">X</span>')
.prependTo('.modal')
.on('click', this.removeModal);
}
};
Modal.init({
boardOutput: $('#board-output'),
overlay: $('.overlay')
});
For what you need, calling self.cloneCard.call($(this)); instead of self.cloneCard($(this));
should work. What you're doing is, calling cloneCard passing it the element in which the the clickCard event occured.
If this doesn't work, i think we'll need more information to sovle your problem.
i was wondering if someone new how to keep a control with chaining in scope of the "this" key word. It breaks out of the chain when using .find(this).click does anyone know how to keep the chain from breaking
(function($) {
$.fn.mycontrol = function() {
$(window).resize(function() {
alert('resize')
}).scroll(function() {
alert('scroll')
}).find(document).bind('init', function() {
alert('scroll')
}).ready(function() {
$(this).trigger('init');
}).find(this).click(function() {
alert('click'); // $(this) loses scope here
});
})(jQuery);
$(document).ready(function() {
$('#mycontrol').mycontrol()
});
If I understand correctly what you're looking for, you should be able to just save the value of this before you start your chaining:
(function($) {
$.fn.mycontrol = function() {
var that = this;
$(window).resize(function() {
alert('resize')
}).scroll(function() {
alert('scroll')
}).find(document).bind('init', function() {
alert('scroll')
}).ready(function() {
$(that).trigger('init');
}).find(that).click(function() {
alert('click'); // $(this) loses scope here
});
})(jQuery);
Chaining creates unmaintainable code. Break it up into separate lines:
var $window = $(window);
$window.resize(function()
{
alert('resize')
});
$window.scroll(function()
{
alert('scroll')
});
// etc.
Then you can read it, you can step though it with the debugger, you can delete and remove logic with out breaking anything.
window is an object Window.
This is window.document which contains HTML objects.
So $(window).find(this) return jquery empty object as $(window).find(document) too.
$(document).find(this) works instead which is equivalent of $(window.document).
I am trying to add a simple delay to a mouseover event of a child and having difficulties. (Still learning!)
This enables me to show the popup after a delay, but shows all of them simultaneously:
onmouseover='setTimeout(function() { $(\".skinnyPopup\").show(); }, 600)'
and this works to show only the popup I want with no delay:
onmouseover='$(this).children(\".skinnyPopup\").show()'
but the combination does not:
onmouseover='setTimeout(function() { $(this).children(\".skinnyPopup\").show(); }, 600)'
Any help would be appreciated. Thanks!
You need to define what this is when it executes, something like this would work:
setTimeout($.proxy(function() { $(this).children(".skinnyPopup").show(); }, this), 600)
Or just use .delay(), like this:
$(this).children(".skinnyPopup").delay(600).show(0);
Both of the above are quick fixes, I suggest you move away from inline handlers and check out an unobtrusive method (see this answer by Russ Cam for some great reasons), for example:
$(function() {
$('selector').mouseover(function() {
$(this).children(".skinnyPopup").delay(600).show(0);
});
});
It's because this is bound to the global context, not the element. Use something like the following instead:
// put this in your document head -- replace element with a selector for the elements you want
$(function () {
$(element).bind("mouseover", function () {
var e = $(this);
setTimeout(function () { e.children(".skinnyPopup").show(); }, 600);
});
});
If you're adamant about inline event handlers, the following should also work:
onmouseover='var self = this; setTimeout(function() { $(self).children(\".skinnyPopup\").show(); }, 600)'