So i am learning how to perform loops with javascript, and was researching how to do it with an array. I understand how to create arrays, but what i am not clear on is using implementing that in the loop. So i cam across examples that kind of "manufacture an array within the loop" as i think i have done in this case.
What i want to do is use javascript to change the classes of different dom elements on a page. What i don't want to do is repeat the same code over and over again with a different numerical value. I thought i had everything right but apparently i don't. Here is my code:
<script>
for (var i = 0; i < 11; i++) {
var storyImageSubmit + [i] = document.getElementById('story_image_' + [i]);
var realImageUpload + [i] = document.getElementById('realImageUpload' + [i]);
realImageUpload + [i].addEventListener('mouseover', over_profile_image_submit_ + [i], false);
realImageUpload + [i].addEventListener('mouseout', out_profile_image_submit_ + [i], false);
realImageUpload + [i].addEventListener('mousedown', down_profile_image_submit_ + [i], false);
realImageUpload + [i].addEventListener('mouseup', up_profile_image_submit_ + [i], false);
function over_profile_image_submit_ + [i] + () {
storyImageSubmit + [i].className = "accountSettingsBrowseSubmitHover";
}
function out_profile_image_submit_ + [i] + () {
storyImageSubmit + [i].className = "accountSettingsBrowseSubmit";
}
function down_profile_image_submit_ + [i] + () {
storyImageSubmit + [i].className = "accountSettingsBrowseSubmitDown";
}
function up_profile_image_submit_ + [i] + () {
storyImageSubmit + [i].className = "accountSettingsBrowseSubmit";
}
}
</script>
What i want the code to look like, but iterated with the different numerical values of 1-10, is this:
<script>
for (var i = 0; i < 11; i++) {
var storyImageSubmit1 = document.getElementById('story_image_1');
var realImageUpload1 = document.getElementById('realImageUpload1']);
realImageUpload1.addEventListener('mouseover', over_profile_image_submit_1, false);
realImageUpload1.addEventListener('mouseout', out_profile_image_submit_1, false);
realImageUpload1.addEventListener('mousedown', down_profile_image_submit_1, false);
realImageUpload1.addEventListener('mouseup', up_profile_image_submit_1, false);
function over_profile_image_submit_1() {
storyImageSubmit1.className = "accountSettingsBrowseSubmitHover";
}
function out_profile_image_submit_1() {
storyImageSubmit1.className = "accountSettingsBrowseSubmit";
}
function down_profile_image_submit_1() {
storyImageSubmit1.className = "accountSettingsBrowseSubmitDown";
}
function up_profile_image_submit_1() {
storyImageSubmit1.className = "accountSettingsBrowseSubmit";
}
}
</script
what am i doing wrong here?
<----------------------UPDATE:----------------------->
this is my code presently, after determining that i need an array to accomplish what i want to do. I tested my loop of my array variable, and everything in that department seems to be working fine.
The next issue i have run into now is getting javascript not to rewrite over my listening variables defined by each iteration. I decided the best way to do that would be to eliminate any variables in the loop so that each listening and function execution is unique. I am doing that with the assumption that rewriting my variables is why it wont work. but even after doing that, it won't work.
<script>
var storyImageValue = ["1","2","3","4","5","6","7","8","9","10"];
for (var i = 0; i < storyImageValue.length; i++) {
document.getElementById('realImageUpload' + storyImageValue[i]).addEventListener('mouseover', function () { document.getElementById('storyImageSubmit' + storyImageValue[i]).className = "accountSettingsBrowseSubmitHover"; }, false);
}
Thoughts?
Try something like this:
for (var i = 1; i <= 10; i++) {
var storyImage = document.getElementById('story_image_' + i);
var realImage = document.getElementById('realImageUpload' + i);
realImage.addEventListener('mouseover', function () { storyImage.className = "..."; }, false);
...
}
In JQuery you can use below syntax for parsing javascript array :
$.each(curVal, function(i, array){
alert (curVal);
});
If you have an array in JavaScript, this is how you can iterate it with a for-loop construct:
var arr = [1, 2, 3], i, element;
for (i = 0; i < arr.length; ++i) {
element = arr[i];
// Now do whatever you want with element within this loop.
}
Update as per your comment:
What's happening in the code you have in the comment is that the variable i is not being scoped properly for your purposes. Thing is, in JavaScript, there's no block scope, only function scope...
This means that whenever your event listener function is being invoked, it's getting the value of i but that value is always going to be the last value that was used in the loop..in this case, 10.
Try it like this:
var storyImageValue = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"];
for (var i = 0; i < storyImageValue.length; i++) {
(function (index) {
document.getElementById('realImageUpload' + storyImageValue[index]).addEventListener('mouseover', function () {
document.getElementById('storyImageSubmit' + storyImageValue[index]).className = "accountSettingsBrowseSubmitHover";
}, false);
}(i));
}
What I'm doing is I'm creating a function that takes a single argument (representing the loop index in our case) which invokes itself immediately after being declared, passing in the current value of the loop counter i.
This is because of what I mentioned before as regards scoping. Since JavaScript does not support block scoping, but only function scoping, creating a function which immediately invokes itself will create the scope you need to store the loop counter so that once your event listener function is executed, it will access the correct value.
Related
I have a JavaScript function called resetIndex. It works fine but I want to reset all child IDs. How can I do this? Is there any method like firstChild and lastChild?
I'm new with JavaScript. Can anyone help?
I have following function:
function resetIndex(delId) {
for (var i = delId + 1; i < count; i++) {
var currentElement = document.getElementById(i);
currentElement.id = i - 1;
var update = currentElement.childNodes;
update.setAttribute('id', 'deleteLink(' + currentElement.id + ')');
}
count--;
}
You can use
node.children[0]
to get the first one, and
node.children[node.children.length - 1]
to get the last one.
Make sure to check if they exist, first.
To do something to all child-nodes, you can use a for-loop, like
for(let a = 0; a < node.children.length; a++) {
node.children[a].id = "my-new-id";
}
This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 6 years ago.
I have a piece of code that I'm trying to have alert 1,2,3. I'm having issues using closures properly, so I can't figure this out.
The original code:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {alert(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
I am trying to do something like this to buildList() to get it to work properly:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result[i] = function(x) {
result.push( function() {alert(item + ' ' + list[x])} );
}(i);
}
return result;
}
I know I'm making mistakes on working with the closures, I'm just not sure what the problem is.
Your second try was closer to the solution but still doesn't work because your inner-most function is capturing variable item from your top-level function: item is just always referencing the same instance, which was created when calling buildList().
var scope in JavaScript is always bound to current function call, not to code block, so it's not bound to control statements like for.
For that reason, the alerts likely show the value 'item' + (list.length-1) had at the time of calling buildList().
Since you are passing i to your closure, you should declare var item within that function, e.g:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
result[i] = function(x) {
// x and item are both local variables of anonymous function declared just above
var item = 'item' + list[x]; // or maybe you meant 'item' + x?
return function() {alert(item + ' ' + list[x])};
}(i);
}
return result;
}
Note that the closure would still capture a reference to list so will display the value it contains at the time of calling functions in the array returned by buildList(). Also local variable item is completely optional, you could call alert('item' + x /*or is it list[x]?*/ + ' ' + list[x]).
From How do JavaScript closures work?
Note that when you run the example, "item2 undefined" is alerted three
times! This is because just like previous examples, there is only one
closure for the local variables for buildList. When the anonymous
functions are called on the line fnlistj; they all use the same
single closure, and they use the current value for i and item within
that one closure (where i has a value of 3 because the loop had
completed, and item has a value of 'item2'). Note we are indexing from
0 hence item has a value of item2. And the i++ will increment i to the
value 3.
You need to make a closure in each loop iteration if you are to store the matching value of i:
function buildList(list) {
var result = [], item, closure;
for (var i = 0; i < list.length; i++) {
item = 'item' + list[i];
// call this function with the string you wish to store
// the inner function will keep a reference to the 'msg' parameter even after the parent function returns
closure = (function(msg) {
return function() {
alert(msg);
};
}(item + ' ' + list[i]));
result.push( closure );
}
return result;
}
function testList() {
var fnlist = buildList([1, 2, 3]);
// using j only to help prevent confusion - could use i
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList();
Same question asked here and here. Same answers here, here, here, here and probably in dozen more places.
Here is my code. I do not quite understand why the for loop runs only once, both inner and outer. nodeList.length and innerNodeList.length show appropriate values when I generate alert messages. I see that both i and j do not increment beyond 0. Kindly point out anything wrong with the code.
function getCategoryElements() {
var newCategoryDiv = document.getElementById("category");
var nodeList = newCategoryDiv.childNodes;
for (var i = 0; i < nodeList.length; ++i) {
var innerNodeList = nodeList[i].childNodes;
alert("innerNodeList Length" + innerNodeList.length.toString());
for (var j = 0; j < innerNodeList.length; ++j) {
if (innerNodeList[j].nodeName == "SELECT") {
alert("inside select Node value " + innerNodeList[j].nodeValue.toString());
document.getElementById("newCategories").value =
document.getElementById("newCategories").value + '<%=delimiter%>' + innerNodeList[j].nodeValue;
} else if (innerNodeList[j].nodeName == "TEXTAREA") {
document.getElementById("newCategoriesData").value =
document.getElementById("newCategoriesData").value + '<%=delimiter%>' + innerNodeList[j].nodeValue;
}
}
}
}
var newCategoryDiv, nodeList, innerNodeList, innerNode, i, j;
newCategoryDiv = document.getElementById("category");
nodeList = newCategoryDiv.childNodes;
for (i = 0; i < nodeList.length; ++i) {
innerNodeList = nodeList[i].childNodes;
alert("innerNodeList Length" + innerNodeList.length.toString());
for (j = 0; j < innerNodeList.length; ++j) {
innerNode = innerNodeList[j];
if (innerNode.nodeName === "SELECT") {
alert("inside select Node value " + innerNode.nodeValue.toString());
document.getElementById("newCategories").value += '<%=delimiter%>' + innerNode.nodeValue;
} else if (innerNode.nodeName === "TEXTAREA") {
document.getElementById("newCategoriesData").value += '<%=delimiter%>' + innerNode.nodeValue;
}
// Will this work?
alert('Does this alert appear');
}
}
I took the liberty to refactor your code and clean it up a little bit. In case you're not aware, all variables have function scope in Javascript, so no matter where you declare them within a single function, Javascript treats them as if the variable declaration is the first statement.
It appears that your code is syntactically correct, and so I think that the most logical place to look for a problem is that there could be an error occurring after the last alert function call.
In order to check this, try adding another alert function call to the end of the inner loop. If it doesn't run, you'll know this is the case.
Can someone please tell me why when I click on the [s] href created next to the list of names (myhand) generated it always says selection and i are 5?
var printDD = function(myhand, mydiv){
var dtext = "";
for(var i = 0; i < myhand.length; i++){
dtext += '[s]' + myhand[i] + ', ';
}
mydiv.html(dtext);
for(var i = 0; i < myhand.length; i++){
$('#dd'+i).click(function(){
selection = i;
console.log("sel: " + selection + " i: " + i);
});
}
}
You want to take a look at JavaScript closure inside loops – simple practical example. As the answer to that question says, you can create a function to return one, or you can use inline function invocation in the for loop like so:
for(var i = 0; i < myhand.length; i++) {
$('#dd'+i).click((function(x) {
return function () {
selection = x;
console.log("sel: " + selection + " x: " + x);
}
}(i)));
}
Because the value of i is determined at the time the click handler is run. So it will always have the value of myhand.length - 1, which is the state you left i in after the for-loop.
I am really struggling with concept of scope in my code.
I am simply trying to create a 'callback' function which will add a className to a variable. As it's inside a function, I am passing the global variable as parameters to the callback function using the concept of closure (still dont understand how closure works).
var ePressCuttingsArray = $(".cPressCuttings");
var eSelectedPressCuttingsArray = [];
var iIndexArray = [];
for (var i = 0; i < 7; i++) {
var iIndexArrayValue;
// two conditions being checked in while loop, if random no. is not in global array (iIndexArray) & i var is equal to eSelectedPress... array
while (jQuery.inArray(((iIndexArrayValue = Math.floor(Math.random() * 14) + 1), iIndexArray) === -1)
&& (i === eSelectedPressCuttingsArray.length))
{
// to push a value at a position from array ePressCut... into eSelectedPress... array
eSelectedPressCuttingsArray.push(ePressCuttingsArray[iIndexArrayValue]);
// run a function to addClass to the recently pushed value in eSelectedPress... array
(function (i) {
$(eSelectedPressCuttingsArray[i]).addClass("cPressCuttingsDisplay0" + i)
} (i) );
iIndexArray.push(iIndexArrayValue);
}
}
Could someone explain why the closure func. is not performing correctly, i.e. it always successfully add the className "cPressCuttingsDisplay00", but doesnt follow that up with a className of "cPressCuttingsDisplay01" for the next loop iteration.
You should be able to accomplish your goal by using a for loop:
var ePressCuttingsArray = $(".cPressCuttings").makeArray();
var eSelectedPressCuttingsArray = [];
for (var i = 0; i < 7; i++) {
var idx = Math.floor(Math.random() * ePressCuttingsArray.length);
var selectedItem = ePressCuttingsArray[idx];
selectedItem.addClass('cPressCuttingsDisplay0' + i);
eSelectedPressCuttingsArray.push(selectedItem);
ePressCuttingsArray.splice(idx, 1);
}