In this demo, i got different outputs, if i use (no wrap) or (onLoad).
My question is, in html file, to get a correct alert: 1,2,3,4 what alteration is needed in code ? With a simple load of dojo i got always 4 in all alerts:
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js"></script>
<script type="text/javascript">
var slider = [];
for (i = 0; i < 4; i++) {
slider[i] = function () {
alert([i]);
};
dojo.addOnLoad(slider[i]);
}
</script>
You could use a closure:
var slider = [];
for (i = 1; i < 5; i++) {
slider[i] = (function (i) {
return function () { alert([i]); }
})(i);
dojo.addOnLoad(slider[i]);
}
This will save i into another functions scope saving the state. Without the closure, i is scoped to the original function.
The value of i is 4 at the end of the loop, which is what your functions will see when they are called. Something like this should work:
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js"></script>
<script type="text/javascript">
var slider = [];
for (i = 0; i < 4; i++) {
eval("slider[i] = function () { alert([" + i + "]);};");
dojo.addOnLoad(slider[i]);
}
</script>
Edit: well you could also try doing the counting when the functions are called rather than when they're defined. e.g.
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js"></script>
<script type="text/javascript">
var slider = [];
var onLoadCounter = 0;
var onLoadCallback = function() {
alert(onLoadCounter);
onLoadCounter++;
};
for (i = 0; i < 4; i++) {
slider[i] = onLoadCallback;
dojo.addOnLoad(slider[i]);
}
</script>
Related
I am adding event listener to every image in document.
for (var i = 0; i < document.images.length; i++) {
let img = document.images[i];
img.addEventListener('click', function (event) {
var data = {uri: img.src};
});
}
But I can't use es6 so let is making me issue. If I put var instead of let only last image has event.
How to use es5 to add event to each image?
You could do it this way using var and this:
for (var i = 0; i < document.images.length; i++) {
document.images[i].addEventListener('click', function(event) {
var data = {
uri: this.src
};
});
}
for (var i = 0; i < document.images.length; i++) {
document.images[i].addEventListener('click', function(event) {
var data = {
uri: this.src
};
console.log(data)
});
}
<img src="http://www.placehold.it/100x100">
<img src="http://www.placehold.it/100x200">
<img src="http://www.placehold.it/100x300">
Here's an example of creating elements and adding an event listener to each using regular old ES5.
function createClickableElements() {
var arr = [];
for (var i = 0; i < 5; i++) {
var div = document.createElement('div');
div.innerHTML = 'Click Here!';
arr.push(div);
}
return arr;
}
var elems = createClickableElements();
var createClickHandler = function(arg) {
return function() {
console.log(arg);
};
}
for (var i = 0; i < elems.length; i++) {
elems[i].onclick = createClickHandler(i);
document.getElementById('container').appendChild(elems[i]);
}
<div id='container'></div>
Unlike other examples suggest, there is no need of creating a closure for each image, or assigning a new anonymous function to each image. And ES5 already offers Array.from and Array.prototype.forEach. Making use of it supports writing better readable code that just uses two functions - one for assigning the click handler and another one that will handle the data creation of any image, thus offering a less memory consuming approach too ...
function createImageData(evt) {
var data = { uri: evt.target.src };
console.log('createImageData - data : ', data);
}
function assignClickHandler(elmImage) {
elmImage.addEventListener('click', createImageData, false);
console.log('assignClickHandler - elmImage : ', elmImage);
}
Array.from(document.images).forEach(assignClickHandler);
.as-console-wrapper { top: 0; }
<img src="https://placehold.it/100x100">
<img src="https://placehold.it/100x200">
<img src="https://placehold.it/100x300">
... one might even think about making use of event delegation
I got the following script, which is not working propperly. I know about getJSON's async nature, so I tried to build a callback function (jsonConsoleLog), which is supposed to be executed before getJSON get asigned to var (myJson = json;). After running debug in Chrome, I got two things out: A) debug is highlighting jsonConsoleLogcalls inside getJSON function as undefined.
B) Console is throwing TypeError: Cannot read property '0' of null for var friends = myJSON[0].friends;, which means the whole function doesn't work.
I'm in battle with it since saturday and I really don't know what to do. There's clearly something up with my callback function, but shoot me if I know what. Help?
var myJSON = null;
var main = document.getElementsByClassName('main');
var sec = document.getElementsByClassName('sec');
function getJSON(jsonConsoleLog){
$.getJSON('http://www.json-generator.com/api/json/get/cpldILZRfm? indent=2', function(json){
if (json != null){
console.log('Load Successfull!');
};
if (jsonConsoleLog){
jsonConsoleLog(json[0].friends);
}
myJSON = json;
});
};
function jsonConsoleLog(json) {
for (var i = 0; i < json.length; i++) {
console.log('friend: ' + friends[i]);
};
};
getJSON();
var friends = myJSON[0].friends;
function myFn1(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
function myFn2(){
for(var i = 0; i < friends.length; i++) {
main_div[i].innerHTML = friends[i].name;
};
};
main.innerHTML = myFn1();
sec.innerHTML = myFn2();
The first problem is because your function getJSON is expecting one formal argument, which you've called jsonConsoleLog. But you are not passing any arguments to getJSON. This means that inside getJSON the formal parameter, jsonConsoleLog, will indeed be undefined. Note that because you've named the formal parameter jsonConsoleLog, which is the same name as the function you're hoping to call, inside getJSON you won't have access to the function. What you need to do is pass the function as the parameter:
getJSON(jsonConsoleLog);
The second problem is I think to do with the json variable - it doesn't have a property 0 (i.e. the error is occurring when you try to treat it as an array and access element 0), which suggets that json is coming back empty, or is not an array.
you're calling getJSON without the callback parameter - therefore, the local variable jsonConsoleLog is undefined in getJSON
snip ...
function blah(json) { // changed name to avoid confusion in the answer - you can keep the name you had
for (var i = 0; i < json.length; i++) {
console.log('friend: ' + friends[i]);
};
};
getJSON(blah); // change made here (used the function name blah as changed above
var friends = myJSON[0].friends;
function myFn1(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
snip...
The issue with
var friends = myJSON[0].friends;
is duplicated here many many times ... $.getJSON is asynchronous and you are trying to use it synchronously
i.e. when you assign var friends = myJSON[0].friends; myJson hasn't been assigned in $.getjson ... in fact, $.getjson hasn't even BEGUN to run
here's all your code reorganised and rewritten to hopefully work
var main = document.getElementsByClassName('main');
var sec = document.getElementsByClassName('sec');
function getJSON(callback) {
$.getJSON('http://www.json-generator.com/api/json/get/cpldILZRfm? indent=2', function(json) {
if (json != null) {
console.log('Load Successfull!');
};
if (callback) {
callback(json);
}
});
};
function doThings(json) {
var friends = json[0].friends;
for (var i = 0; i < friends.length; i++) {
console.log('friend: ' + friends[i]);
};
function myFn1() {
for (var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
function myFn2() {
for (var i = 0; i < friends.length; i++) {
main_div[i].innerHTML = friends[i].name;
};
};
main.innerHTML = myFn1();
sec.innerHTML = myFn2();
}
getJSON(doThings);
Correct, fully working code (basically the same as accepted, correct answer but stylistycally bit different)
var main = document.getElementsByClassName('main');
var sec = document.getElementsByClassName('sec');
var friends = null;
function getJSON(jsonConsoleLog){
$.getJSON('http://www.json-generator.com/api/json/get/cpldILZRfm?indent=2', function(json){
if (json != null){
console.log('Load Successfull!');
};
if (jsonConsoleLog){
jsonConsoleLog(json[0].friends);
}
});
};
function jsonConsoleLog(json) {
for (var i = 0; i < json.length; i++) {
console.log('friend: ' + json[i]);
};
friends = json;
myFn1();
myFn2();
};
function myFn1(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML = friends[i].id;
};
};
function myFn2(){
for(var i = 0; i < friends.length; i++) {
main[i].innerHTML += friends[i].name;
};
};
getJSON(jsonConsoleLog);
I'm having some confusion with closures
<script type="text/javascript">
$(function () {
for (var i = 0; i < 7; i++) {
var cname = '#closingTimePicker' + i;
$(cname).datetimepicker({
format: 'LT'
});
var oname = '#openingTimePicker' + i;
$(oname).datetimepicker({
format: 'LT'
});
$(oname).on("dp.change", function (e) {
$(cname).data("DateTimePicker").minDate(e.date);
});
$(cname).on("dp.change", function (e) {
$(oname).data("DateTimePicker").maxDate(e.date);
//Loop issue here
});
}
});
</script>
>
In the above script i'm confused how to apply closure so that i cloud get the correct date picker based on the loop. any suggestions and importantly explanation would be a great help.
Thanks,
every loop cname and oname gets a new value. so when dp.change on a oname object is triggered, cname has always the last value it gets in the loop.
try something like this:
<script type="text/javascript">
function initPicker(cname, oname)
{
// paste here the rest of the loop
}
for (var i = 0; i < 7; i++) {
var cname = '#closingTimePicker' + i;
var oname = '#openingTimePicker' + i;
initPicker(cname, oname);
}
</script>
[EDIT]
short explanation:
scopes live as long as their variables. so "scope" initPicker is 7 times initialized with different filled variables.
[/EDIT]
enjoy (-:
so this might be a repost, but I don't really know how to explain my second problem.
I have this code:
var paragraphsArray = new Array();
function setParagraphs(offSet)
{
offSet = offSet * 12;
for (var i = 1; i < 13; i++)
{
var parX = i + offSet;
var testASd = $.get('php/entryParagraphs.php', {idd: parX}).done(function(paragraph)
{
//clear paragraph1 div
document.getElementById("paragraph1").innerHTML = "";
//create p elements
var pElem = document.createElement("p");
pElem.setAttribute("id", "pEntry"+i);
document.getElementById("paragraph1").appendChild(pElem);
$("pEntry"+i).text(paragraph);
});
}
}
edited: I removed the second loop because it was unnecessary, for some reason the p element creation starts on i==13, which is the extra one that shouldn't even do.
for some reason the second loop executes first, so the paragraphArray is printed out as undefined. I managed to "fix" the order with the setTimeout() function, BUT I still get the undefined message, instead of the value. In the first loop the value is printed out fine, but if I try and put it in a $("p").text(paragraph); I also get undefined. So although I was right about the execution order, the problem is still there!
Because first is in ajax call, declare paragraphsArray in global space and use a callback function, try this:
*Updated
var paragraphsArray = [];
function setParagraphs(offSet) {
offSet = offSet * 12;
var request = 0;
for (var i = 1; i < 13; i++) {
var parX = i + offSet;
var testASd = $.get('php/entryParagraphs.php', {idd: parX}).done(function(paragraph) {
request++;
paragraphsArray[request] = paragraph;
console.log(paragraphsArray[request]);
if (request === 12) {
alert('first');
callback();
}
});
}
}
function callback() {
for (var i = 1; i < 13; i++) {
console.log(paragraphsArray[i]);
}
alert('second');
}
Run the second loop inside of the first loop.
function setParagraphs (offSet) {
//paragraphs
var testing = 0;
var paragraphsArray = new Array();
offSet = offSet * 12;
for (var i=1;i<13;i++) {
var parX = i + offSet;
var testASd = $.get('php/entryParagraphs.php', { idd: parX }).done(function(paragraph) {
paragraphsArray[i] = paragraph;
console.log(paragraphsArray[i]);
alert('first');
for (var i=1;i<13;i++) {
console.log(paragraphsArray[i]);
alert('second');
}
});
}
}
$.get is async function. 1st cycle will just send requests and wouldn't wait for response, so 2nd cycle will start right after first, without getting response of $.get function. Thats why console.log(paragraphsArray[i]); in 2nd cycle shows undefined.
You only can handle response in first cylce.
You can use $("p").text(paragraph); only like in this example:
var testASd = $.get('php/entryParagraphs.php', { idd: parX }).done(function(paragraph) {
paragraphsArray[i] = paragraph;
console.log(paragraphsArray[i]);
alert('first');
$("p").text(paragraph);
});
You can't use variables, which are assigned in function
function(paragraph) {
paragraphsArray[i] = paragraph;
console.log(paragraphsArray[i]);
alert('first');
$("p").text(paragraph);
}
outside of this function.
To achieve what you want you have to use another approach.
HTML will be:
<div id='paragraphs'>
</div>
JS code:
var testASd = $.get('php/entryParagraphs.php', { idd: parX }).done(function(paragraph) {
$("#results").append("<p>"+paragraph+"</p>")
});
You should use ~ this code. I just show you approach.
Everyone is suggesting some framework, but I'd like to know how it can be done in native JavaScript. I've tried this code and some other things, no effect. Seems that I'm unaware of some basic underlying concept. Any help would be appreciated.
window.onload = function() {
var trCurrent
var main = document.getElementById('main');
var tr = main.getElementsByTagName('tr');
function hl() {
trCurrent.setAttribute('class', 'highlight');
};
for (var x = 0; x < tr.lenght; x++) {
trCurrent = tr[x];
trCurrent.addEventListener ('mousedown', hl, false);
}
};
You have to change trCurrent to this at your function h1, becayse trCurrent points to the last defined TR element (trCurrent = tr[x] for a high x).
Use .length instead of .lenght.
Final code:
window.onload = function() {
var main = document.getElementById('main');
var tr = main.getElementsByTagName('tr');
function hl() {
this.setAttribute('class', 'highlight');
};
for (var x = 0; x < tr.length; x++) {
tr[x].addEventListener ('mousedown', hl, false);
}
};
If you want to use an variable which is subject to change during a loop, it's required to wrap the body in an (anonymous) function:
window.onload = function() {
var main = document.getElementById('main');
var tr = main.getElementsByTagName('tr');
for (var x = 0; x < tr.length; x++) {
(function(trCurrent){ //Anonymous wrapper, first argument: `trCurrent`
function hl() {
trCurrent.setAttribute('class', 'highlight');
};
trCurrent.addEventListener ('mousedown', hl, false);
})(tr[x]); //Passing a reference to `tr[x]`
}
};