Using $(this) in setTimeout(); - javascript

I want to set timeouts dynamically in jQuery. The dynamically set timeout functions need to use $("this"), but I can't seem to get it working.
An exmple:
$("div").each(function(){
var content = $(this).attr('data-content')
setTimeout("$(this).html('"+content+"')",$(this).attr('data-delay'));
});​
http://jsfiddle.net/qmhmQ/
What is the best way to do this?

$("div").each(function(){
var content = $(this).attr('data-content'),
$this = $(this); // here $this keeps the reference of $(this)
setTimeout(function() {
// within this funciton you can't get the $(this) because
// $(this) resides within in the scope of .each() function i.e $(this)
// is an asset of .each() not setTimeout()
// so to get $(this) here, we store it within a variable (here: $this)
// and then using it
$this.html(content);
}, $this.attr('data-delay'));
});​
DEMO

Your code should look like this:
pass a function instead of a string.
Explanation:
When passing a string to setTimeout you get problems, because it runs in a different scope than you original one, and thus you get errors.
use the jQuery data()method
$("div").each(function(){
var content = $(this).attr('data-content'),
$el = $(this),
setContent = function(){
$el.html(content);
}
setTimeout(setContent,$el.data('delay'));
});​
You can assign a function to a variable and pass that variable as parameter to setTimeout, this is the cleanest way.

Use closures (some tutorials).
Using strings with setTimeout is not a good idea. Also beware this, since it can change its context (ie. call-site) if used inside a closure.
If using data attributes you can use the jQuery data function.
$("div").each(function() {
var instance = $(this);
var content = instance.data('content');
var method = function() {
instance.html(content);
};
setTimeout(method, instance.data('delay'));
});
div {
border: 1px solid black;
margin: 5px;
height: 1.5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div data-content="fus" data-delay="1000"></div>
<div data-content="ro" data-delay="2000"></div>
<div data-content="dah" data-delay="5000"></div>

I am just expanding answer one above,
Use class or id to refer div in JavaScript. This will avoid further tag name conflicts in the page.
So your updated HTML is,
<div data-content="fus" data-delay="1000" class="dv"></div>
<div data-content="ro" data-delay="2000" class="dv"></div>
<div data-content="dah" data-delay="5000" class="dv"></div>​
Now your updated JavaScript code is,
$(".dv").each(function(){
var content = $(this).attr('data-content'),
$this = $(this);
setTimeout(function() {
$this.html(content);
}, $this.attr('data-delay'));
});​
Where main line is
$this = $(this);
Where we are assigning the current element to our variable used in the setTimeout function.
Please refer this link

Take $(this) out of settimeout and save that in local variable say 'self' just after $("div").each(function(){ this line
var self=$(this);
and use that self further.

The following seems like a good compromise of whitespace, readability and revealing intention.
$('div').each(function(){
var element = $(this)
var content = element.attr('data-content')
var delayms = element.attr('data-delay')
var action = function() { element.html(content) }
setTimeout(action, delayms)
})
​
SEE: http://jsfiddle.net/wilmoore/LSs6g/

Related

JQuery event delegation: how to get the index of a JQuery Object in a Array?

I have created an array full of jQuery Object - dom elements:
var tabComponet = new Class({
var $tab = $("<div class='tab'></div>");
var $container = $("<div id='container'></div>");
var tabsArr = [];
[a, b, c].each(function(){
tabsArr.push($tab);
$container.append($tab);
});
$container.on('click', '.tab', function (e) {
e.preventDefault();
var index = $(tabsArr).indexOf($(this));
}
});
I created tabsArr to avoid when there are multiple components created by this Class above by then there will be multiple components contains .tab class thus using $('.tab') would not be working right, but it seems I could not simply put a $ sign on tabsArr to make this working. Also in the delegation, I should avoid using '.tab' as parameter too, right?
I googled about it, it may be because that everytime I use $ to make a JQuery object they would be not the same but just contain the same value, so $(this) is not in tabsArr, because tabsArr doesn't contain it but just the same value.
so how should I do this? how should I create a object that contains the exact tab elements that belong to its own component?
When you create element, you obtain reference to this element. Reference is not value. Your code serves as nice example: when your for loop finishes, you will see only one element inside container no matter what..
Wrapping javascript element into jQuery always create new reference. When you compare two elements(and any non-primitive type) in javascript, you don't compare values(content), but their references. Fortunately you can use get() method to obtain javascript direct reference to element!
var $container = $("<div id='container'></div>");
var tabsArr = [];
for (var i=0;i<2;i++) {
let $tab = $("<div class='tab'></div>");
tabsArr.push($tab.get(0));
$container.append($tab);
};
$container.on('click', '.tab', function (e) {
e.preventDefault();
console.log(tabsArr.indexOf(this));
});
$container.appendTo('body');
.tab {
height: 100px;
width: 200px;
background-color: red;
margin-bottom: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Can this JQuery code be written using plain Javascript?

Is there a way to represent this code as plain vanilla Javascript so I can better understand how it works for now?
$("#id").click(function(){
var $x = $("#id");
$x.removeProp("-webkit-animation");
});
Essentially I'm using this to tell the code not to play a css animation given that a certain set of parameters are met.
removeProp removes properties of objects. If that’s definitely what you want, the equivalent is the delete operator:
var element = document.getElementById("id");
element.addEventListener("click", function () {
delete element["-webkit-animation"];
});
If what you really want to do is change a CSS property, though, it needs to be an operation on the element’s style:
element.style.WebkitAnimation = "none";
But what you should probably do is change a class instead:
element.classList.add("no-animation");
and use CSS:
.no-animation {
-webkit-animation: none;
}
The delete element is the somewhat equivalent on vanilla javascript of removeProp()
element = document.getElementById('id');
element.onclick() = function(){
delete element['-webkit-animation'];
}
Yes, you can use the .removeAttribute() function to remove an attribute, like style, title, etc.
Or you can use .removeProperty() to remove a style property (supported in IE9 and above)
Fiddle
(function() {
var myDiv = document.getElementById('myDiv');
myDiv.removeAttribute('style');
var aDiv = document.getElementById('aDiv');
aDiv.style.removeProperty('height');
})();
<div id="aDiv" style="background-color: green;">Hi</div>
<div id="myDiv" style="background-color: green;">Hi</div>
Hope it will help OP
JS
var element = document.getElementById("id");
element.onClick = function(){
this.style.removeProperty("-webkit-animation");
};

Get DIV ID where Class is selected?

I currently have the following:
$(window).load(function(){
$(".boxdiv").click(function () {
$(this).toggleClass("selected");
});
});
Which perfectly does the first part of what I need. I have a fair amount of div's with the class "boxdiv" and they each have a unique ID that will identify it. What I need to happen is to have some kind of button that when pressed sends all of these div ID's with the class selected, to the next page.
Anyone got any idea of how I can do this?
Map the ID's in an array, and use $.param to create a querystring
$('button').on('click', function() {
var id_arr = $.map($(".selected"), function(el) {return el.id;});
window.location.href = '/next_page?' + $.param({ids : id_arr});
});
EDIT:
$('button').on('click', function() {
var id_arr = $.map($(".selected"), function(el) {return el.id;}),
qs = encodeURIComponent(id_arr.join(','));
window.location.href = '/next_page?ids=' + qs;
});
Perhaps this is what you're looking for:
$(".button").click(function(){
var id_arr = [];
$(".boxdiv").each(function(){ // Loop through each element with that class
id_arr.push($(this).attr('id'));
}); // Loop through each element with that class
});
window.location = 'next.html/ID=' + id_arr.join(',');
The ID's should be stored in id_arr
You can loop over each div that has the class selected. You can then use attr() to access the ID names.
Javascript
var ids = [];
$.each($(".selected"), function() {
ids.push($(this).attr('id'));
});
ids = ids.join(',');
HTML
<div id="boxA"></div>
<div id="boxB" class="selected"></div>
<div id="boxC" class="selected"></div>
<div id="boxD"></div>
This should return ["boxB", "boxC"]
See: http://jsfiddle.net/B4V28/1/
All of the answers submitted are in fact correct - but I think the real issue is your expectation of what jQuery is doing for you.
jQuery will gather all of the ID's in any manner, but you will need to have a way to collect them on the next page and actually do something with them. This will all need to happen server side.
Most likely, the ideal method, based on your comment of "potentially there could be many" you would want to do a mapping (see other answers), and pass the json object to your server, where it can pass it to the next page.
With the same code -
$('button').on('click', function() {
var id_arr = $.map($(".selected"), function(el) {return el.id;}),
qs = encodeURIComponent(id_arr.join(','));
alert('/next_page?ids=' + qs);
});
Here is a fiddle for you - http://jsfiddle.net/kellyjandrews/4dYfh/

Find div ID and use to call associated Javascript variable with jQuery

I have several fish images, within links, which are listed like so...
<img src="img/fish1.png" id="fish1"/>
<img src="img/fish2.png" id="fish2"/>
I want to take id 'fish1', 'fish2', ect. (based on which is clicked), and use a variable to replace some text.
The name of the variables are...
var fish1Hunger
var fish2Hunger
And the function I want to call with a variable is...
$(function() {
$('a.trigger').click(function() {
$('#popUp h3').html(REPLACE WITH VARIABLE ASSOCIATED WITH THE FISH);
});
});
How can I call the variable associated with the IMG id?
window[e.srcElement.id+"Hunger"];
Put that inside your click event with e being the event (function (e){...) and it should access the variable as long as it is in the global scope.
jsBin demo
var fish1Hunger = "Fish 1 is hunger!! Feed him!"
var fish2Hunger = "Fish 2 is hunger!! Feed him!"
$('a.trigger').click(function (e) {
e.preventDefault();
var ImLookingFor = $(this).find('img').attr('id')+'Hunger';
$('#popUp h3').html(eval(ImLookingFor));
});

Access javascript object directly through DOM traversing with jQuery

I'm working on a simple client side interface where I have a jQuery object that I want to access directly when clicking on a hyperlink. Simplified code:
<div class="controls">
<div class="score">
<a class="button" href="/add">Add points!</a>
</div>
</div>
$(".controls").myControls();
$.fn.myControls = function() {
return $.extend(this, $.myControls).initialize();
}
$.myControls = {
initialize: function() {
this.scoreElement = $("div.score", this);
this.linkElement = $("a", this.scoreElement);
this.scoreElement.score = 0;
var _this = this;
this.linkElement.click(function() {
_this.clickHandler(this);
});
},
clickHandler: function(element) {
var scoreElement = $(element).parent();
scoreElement.score = 1;
}
}
Explanation: .controls element has .score element which doubles as a container for score information (this.scoreElement.score). When I click on a link within the .score element, I find the parent element, which is the same element in the DOM as this.scoreElement and try to set its score property to 1. Obviously, this won't work, as the local scoreElement.score property in the clickHandler method is "undefined".
So here's my question: is there a simple way to access my this.scoreElement object directly through traversing the DOM with jQuery?
Surely I can check if this.scoreElement == $(element).parent() in some way and then access the right property in my this.scoreElement object, but direct access would be more elegant and robust. Is this possible? Am I going at it the wrong way? Thanks!
PS: Ignore the fact I use parent() to find the scoreElement, I only use it to illustrate my problem. Unless it is part of the problem, in that case don't ignore :)
While it's certainly possible to use your own 'control-object' to store the related data, I usually prefer to rely on jQuery doing it - with .data() method, like this:
$(this.scoreElement).data('score', 0); // in initialize()
$(this).parent().data('score', 1); // in clickHandler()
This approach allows me to scale more easily, as I never have to fear 'overlapping' issues, using a single 'control' object rather than object-for-element.
I would think that if you used jQuery's proxy function for your click handler, you then could just go this.scoreElement inside of clickHandler and you wouldn't even need to traverse the DOM. Like this:
$.myControls = {
initialize: function() {
this.scoreElement = $("div.score", this);
this.linkElement = $("a", this.scoreElement);
this.scoreElement.score = 0;
this.linkElement.click($.proxy(this.clickHandler, this));
},
clickHandler: function(event) {
var element = event.target;
this.scoreElement.score = 1;
}
}
After progressive simplification (and storing the score slightly differently) I get the code below, in which scoreElement is discovered once per .controls div, then held in a closure to make it available to its corresponding click handler. You could alternatively use .closest() - see commented out line.
$.fn.myControls = function() {
return this.each(function() {
var scoreElement = $("div.score", $(this));
scoreElement.data('score', 0);
$("a", scoreElement).on('click', function() {
scoreElement.data('score', 1);//get scoreElement from closure formed by the outer "each" function.
//$(this).closest(".score").data('score', 1);//alternative to the line above, not requiring closure.
});
});
};
Call as in the question with:
$(".controls").myControls();
This is so trivial and unidimensional it doesn't really warrant, in its own right, a jQuery plugin. Unless there was some compelling reason for a plugin (eg. reuse or the need for closely related methods), then I would phrase it as follows :
$(".controls").each(function() {
var scoreElement = $("div.score", $(this));
scoreElement.data('score', 0);
$("a", scoreElement).on('click', function() {
scoreElement.data('score', 1);//get scoreElement from closure formed by the outer "each" function.
//$(this).closest(".score").data('score', 1);//alternative to line above, not requiring closure.
});
});
That's the same code with the plugin wrapper removed and attached directly to the same base jQuery object.
And if you really wanted, you could write the whole thing in three lines as follows:
$(".controls").find("div.score").data('score', 0).find("a.button").on('click', function() {
$(this).closest(".score").data('score', 1);
});

Categories