Using 'this' in nested functions - javascript

Wow.. to get real information about 'this' is not easy as google basically ignores the word.
The code opens an image from a database using the information from thumbnail.. the onlick works, and the hover code works, but I can't figure out how to get 'this' from the mouseenter to be used in the showModal function.
function showModal() {
$("body").css("overflow-y", "hidden");
$(".small").removeClass("smallHover");
$(".modal").fadeIn(200);
var altLong = $(this).attr("alt");
var altSplit = altLong.split("#");
$(".picTitle").text(altSplit[0]);
var srclong = $(this).attr("src");
var srcshort = srclong.split("_");
var srcextension = srclong.split(".");
$(".big").attr("src", srcshort[0]+'.'+srcextension[1]);
}
$(".small").click(showModal);
var timer;
$(".small").mouseenter(function() {
timer = setTimeout(function(){
$(this).showModal(); // **<--this is the line that doesnt work**
}, 2000);
}).mouseleave(function() {
clearTimeout(timer);
});
also if you could explain why you would use $(this) as a jquery object instead of just 'this' and how they differ, that would be great. Thanks in advance~!

There are two separate aspects to this.
Getting the right this in the setTimeout callback
Calling showModal with that this
#1 is addressed by this question's answers. You have several options, the simplest in this case (for now) probably being to use a variable:
$(".small").mouseenter(function() {
var _this = this; // ***
timer = setTimeout(function(){
$(_this).showModal(); // ***
}, 2000);
}).mouseleave(function() {
clearTimeout(timer);
});
...but that code still won't work, because showModal isn't a property of jQuery objects, it's a standalone function. To call it with a specific this, you'd use Function.prototype.call:
$(".small").mouseenter(function() {
var _this = this;
timer = setTimeout(function(){
showModal.call(_this); // ***
}, 2000);
}).mouseleave(function() {
clearTimeout(timer);
});
(Alternately, change showModal to accept the element as a parameter and then just pass it as an argument.)
More on this in this question's answers as well, as well as this (old) post on my anemic little blog.

this will also work if you could change your showModel function like this :
$.fn.showModal = function() {
$("body").css("overflow-y", "hidden");
$(".small").removeClass("smallHover");
$(".modal").fadeIn(200);
...
}
and inside timer method
$(this).showModal();

Related

Adding a jQuery delay on autocomplete

I'm trying to create a jQuery autocomplete for an application:
$("#search-input").on('keyup', function() {
search = $(this).val();
autocomplete_div = $(".autocomplete")
$.get('/ajax/search/', {'search': search,}, function(response){
autocomplete_div.html(response)
});
});
What would I need to add to the above code to add a 400ms delay?
Use
setTimeout(function() {
// your code here
}, 400);
setTimeout is a method provided by the browser's window object.
A more complete example that cancels a timer if already set using clearTimeout would be:
var myTimer = 0;
$("#search-input").on('keydown', function() {
search = $(this).val();
// cancel any previously-set timer
if (myTimer) {
clearTimeout(myTimer);
}
myTimer = setTimeout(function() {
autocomplete_div = $(".autocomplete")
$.get('/ajax/search/', {'search': search,}, function(response){
autocomplete_div.html(response)
});
}, 400);
});
Also note use of on instead of the deprecated live.
Your code should look like this: (for jQuery 1.7+)
$(document).on('keyup', "#search-input", function () {
clearTimeout($(this).data('timeout'));
var _self = this;
$(this).data('timeout', setTimeout(function () {
$.get('/ajax/search/', {
search: _self.value
}, function (response) {
$(".autocomplete").html(response);
});
}, 400));
});
If using older jQuery version, use live() or better delegate(). BTW, you should bind it to closest static container, not document.
You can use the setTimeout() function to delay the start of the expression, in this case, your function. Beware that this does not delay processing beyond this code. It will only delay the start of this function, while continuing to process code after the function.
$("#search-input").live('keydown', setTimeout(function() {
search = $(this).val();
autocomplete_div = $(".autocomplete")
$.get('/ajax/search/', {'search': search,}, function(response){
autocomplete_div.html(response)
})
},400));
EDITED: to correct misplaced parentheses.

Move element with jQuery plugin - setInterval

Why this code doesn't work?
I wrote This code but:
(function($){
$.fn.newsSlider = function() {
setTimeout(function() {
this.each( function() {
$(this).each(function(){
$(this).append($(this).children(":first-child").clone());
$(this).children(":first-child").remove();
});
});
}, 3000);
}
}(jQuery));
With setInterval:
http://jsfiddle.net/OmidJackson/46UNg/
Without setInterval:
http://jsfiddle.net/OmidJackson/6bKWU/
Your problem is that this has different meaning (the window object) inside the setTimeout function literal. Check this answer for further info about this in different contexts.
The solution is to save a reference to this so you can use it inside the setTimeout.
See this example.
You need to store the this as it currently has a value of window
var $this = this;
setTimeout(function() {
$this.each( function() {
$(this).each(function(){
$(this).append($(this).children(":first-child").clone());
$(this).children(":first-child").remove();
});
});
}, 3000);

SetInterval using linkObj

With this code I expect to see a 'yo' added to the console every second while I'm hovering over .cell-top. But I get one 'yo' and that's it.
function cellUp(linkObj) {
console.log('yo');
}
$(".cell-top").hover(function() {
setInterval(cellUp($(this)), 1000);
});
Any idea what I can do to get my expected results?
PS. I'm using linkObj to get $(this) in a function within cellDown, I didn't include the function because that's unrelated to the issue I'm having. I did include the linkObj because I figured it may be part of the issue.
Since you're using jQuery, you can use $.proxy.
$(".cell-top").hover(function() {
setInterval($.proxy(cellUp, null, $(this)), 1000);
});
var interval;
function cellUp(linkObj) {
console.log(linkObj);
}
$(".cell-top").hover(function() {
var self = this;
interval = setInterval(function(){cellUp($(self))}, 1000);
},function() {
clearInterval(interval);
});

Using jquery $(this) in a function

Quick Description:
I'm aware that using $(this) in a function won't work because it's not within the right scope. I've also seen other similar questions. I just still can't figure out how to fix my scenerio.
Goal: I'm trying to build a panoramic photo viewer with jQuery. I have it working, but I need multiple instances. So I need to target only the one I'm hovering on.
Code:
jsFiddle: http://jsfiddle.net/kthornbloom/5J3rh/
Simplified Code:
var hoverInterval;
function doStuff() {
/* The next line is the one in question */
$(this).animate({
/* stuff happening */
});
}
$(function() {
$('.pan-wrap').hover(
function() {
/* stuff happening */
hoverInterval = setInterval(doStuff, 250);
},
function() {
clearInterval(hoverInterval);
});
});
You have scope issues, this in the doStuff is window context.
Use proxy()
hoverInterval = setInterval($.proxy(doStuff,this), 250);
You can explicitly pass this into doStuff:
setInterval(function() {
doStuff(this);
}, 250);
And in doStuff you can do:
function doStuff(element) {
...
}
Or you can explicitly set the value of this for doStuff like so:
setInterval(function() {
doStuff.call(this);
}, 250);
Then you can still use $(this) inside doStuff without changing any of its arguments. For more information on call, see Function.prototype.call and its friend Function.prototype.apply.

Clearing timeouts with javascript

i'm having some sort of variable out of scope issue or something. in the function below, i'm creating or clearing a timeout based on whether the mouse is entering or exiting. it seems though, that even once the timeout has been created it's returning undefined on re-entry. not sure what i'm doing wrong here, thanks for your help!
jsFiddle example
JavaScript: (particular issue is within else conditional on line 35
var navLinks = $('nav li.sub');
navLinks.mouseenter(function(){
console.log('hovering on link');
var thiis = $(this),
subList = thiis.find('ul'),
autoClose;
if (!thiis.hasClass('out')){
console.log('isnt out');
/* Link */
thiis
/* Show submenu when entering link */
.addClass('out')
/* Hide submenu when exiting link */
.mouseleave(function(){
autoClose = setTimeout(function(){
thiis.removeClass('out');
}, 1000);
console.log('exiting link: timeout active', autoClose);
});
} else {
console.log ('is out', autoClose);
if (autoClose){
console.log('is out: clear timeout');
clearTimeout(autoClose);
}
}
});
Techno,
The simple answer is just to move var autoClose to an outer scope, but I think you can (and should) do more.
More specifically,
I don't think you want to attach the mouseleave handler inside the mouseenter handler. It can be permanently attached from the outset.
In the mouseenter handler, clearTimeout(autoClose) and thiis.addClass('out') can be executed unconditionally. There's no real economy in testing .hasclass('out').
Try this :
var navLinks = $('nav li.sub');
var autoClose;
navLinks.hover(function(){
var thiis = $(this);
clearTimeout(autoClose);
thiis.addClass('out');
}, function(){
var thiis = $(this);
autoClose = setTimeout(function(){
thiis.removeClass('out');
}, 1000);
});
As pointed in comments to question you have new timeout each time mouse hovers an item. Lets make new timeout variable for every item:
$('nav li:has(ul)').each(function(){
var par = $(this),
sub = $("> ul", this),
closeTO;
par.hover(
function(){
clearTimeout(closeTO);
par.addClass("out");
},
function(){
closeTO = setTimeout(function(){
par.removeClass("out");
}, 1000);
}
);
});
http://jsfiddle.net/ByuG3/1/
You should use a global object to store some vars like reference of timeout and interval.
In example you could declare such an object:
// Declare the context object in the global scope
var myContext = {
"myTimeout" : false
}
And then use the context object in your mouseenter and mouseleave handler functions.

Categories

Resources