JS loop and maintain index of parameters that meet condition - javascript

I have a bunch of div's that I'm selecting by getElementsByClassName let's call it:
let myDivs = document.getElementsByClassName('small-divs');
I need to set innerText conditionally to myDivs depending on whether each <div> in myDivs is style.visibility != 'hidden'
So I'm looping using a for loop and within the loop I have the condition checking for visibility:
for(let i=0; i < myDivs.length; i++){
if(myDiv[i].style.visibility != 'hidden'){
myDiv[i].innerText = letter + i; // letter is a user defined array of letters to use for 'rows'
}
}
This is working as it should but my problem is that I need the i in letter + i to begin from 1 rather than from the element's index that meets the condition. Here's a pictorial of what I have:
This is before hiding any divs:
And here's what I have after hiding some divs and running the above code. Notice that the inner text starts from the index that meets the conditions. For instance I need "row K" to start from K1
How can I achieve this? Seems like a small step I should do that I'm missing

Do you mean something like this? Use a counter which increments only when a non-hidden div is found
let number = 1;
for(let i=0; i < myDivs.length; i++){
if(myDiv[i].style.visibility != 'hidden'){
myDiv[i].innerText = letter + number; // letter is a user defined array of letters to use for 'rows'
number += 1;
}
}

Related

Apps Script JS adding items to array from range (if not already in array) fails

I am looping through various cells and want to add their string content do an array, if the content is not already in the array. It works perfectly fine when I do it manually like so, trying to add 'eJobs' to the array (see below "var item = 'eJobs') which already containts 'eJobs':
var divisionarray = ['eJobs']
for (var i = 0; i < cells_users.length-1; ++i) {
var row_users = cells_users[i];
if (row_users[0] == user_ldap) {
var podarray = row_users[1].split(', ')
for (j = 0; j < podarray.length; j++) {
for (var k = 0; k < cells_edit.length; ++k) {
var row_edit = cells_edit[k]
if (podarray[j] === row_edit[0]) {
var item = 'eJobs'
if (!(divisionarray.indexOf(item) >= 0)) {
divisionarray.push(item)
}
}
}
}
Logger.log(divisionarray)
As expected, the log file shows [17-10-08 19:11:04:111 BST] [eJobs], illustrating that the code works and 'eJobs' has not been added to the array as it is already in the array.
Now, when I change var item='eJobs' to values of a range
var item = sheet_pods_edit.getRange(startRow+k, startColumn+1).getValue();
the code does not work anylonger, as the log file shows:
[17-10-08 19:14:03:770 BST] [eJobs, eJobs, BestJobs, Vivre Deco, ...
Note I have a range of thousands of cells, so I get alot of duplicates added. What am I missing? Note the cells of the defined range are indeed just strings with a single word (e.g. 'eJobs').
The code is working and the log file is indicating what the problem is..
[eJobs, eJobs, BestJobs, Vivre Deco,
In the second eJobs there is a white space before eJobs, so the first value and the second value don't match.
Without seeing your data and going by the 'just strings with a single word' I would say that using a .replace(" ", "") on the text string should work, this will find the first " " in the string and remove it. I.e. " eJobs" would become "eJobs".
2.
Is this line of code just for testing? You should never use a method like this in a script. It will be extremely inefficient
var item = sheet_pods_edit.getRange(startRow+k, startColumn+1).getValue();
Instead get the full range using .getValues()and iterate over it then.
3.
Is there a reason you are using === in if (podarray[j] === row_edit[0]) unless you need to check for type always use ==

Getting previous element in for loop

EDIT 2 (to make the problem more understandable)
The effect I am trying to achieve is the following: everytime an element enters the viewport an 'is-visible' class is added to it and the same 'is-visible' class is removed from the previous element.
Now I've managed to make it work but I run a for loop to remove all is-visible classes before adding the is-visible class to the element in viewport.
It works but in terms of performance I think it would be better to just remove the class from element[i -1]. And this were I can't get it working.
Here is a simplified fiddle were I try to make the element[i-1] solution work: https://jsfiddle.net/epigeyre/vm36fpuo/11/.
EDIT 1 (to answer some of the questions asked)
I have corrected an issue raised by #Catalin Iancu (thanks a lot for your precious help) by using a modulus operator ((i+len-1)%len).
ORIGINAL QUESTION (not really clear)
I am trying to get the previous element in a for loop (to change its class) with following code :
for (var i = 0; i < array.length; i++) {
if(array[i-1] && my other conditions) {
array[i-1].classList.remove('is-visible');
array[i].classList.add('is-visible');
}
}
But it's not removing the class for [i-1] element.
Here is a more complete piece of code of my module (this is running within a scroll eventlistener):
var services = document.getElementsByClassName('services'),
contRect = servicesContainer.getBoundingClientRect();
for (var i = 0; i < services.length; i++) {
var serviceRect = services[i].getBoundingClientRect();
if ( !services[i].classList.contains('active') && Math.round(serviceRect.left) < contRect.right && services[i-1]) {
services[i-1].classList.remove('is-visible');
services[i].classList.add('is-visible');
}
}
Thanks for your help!
Your if(array[i-1] && my other conditions) is always true, except for the very first case where array[-1] doesn't exist. Therefore, it will remove and then add the active class for each element, which will make it seem as only the first element's class has been removed.
What you need is a better if condition or a break statement, when the loop is not needed anymore
for (var i = 0; i < array.length; i++) {
if(array[i] && i != array.length - 1) {
array[i].classList.remove('active');
}
}
array[array.length - 1].classList.add('active');
The problem probably is that based on your code: services[i-1].classList.remove('active'); and services[i].classList.add('active'); the 'active' class you add in current iteration will be removed in next iteration!
So your code has logical errors, array index does not return all prev items!
What if you create a variable that contain the previous element?
var previous = array[0];
for (var i = 0; i < array.length; i++) {
if(previous && my other conditions) {
previous.classList.remove('active');
array[i].classList.add('active');
break;
}
previous = array[i];
}

How do I reference text boxes using a variable

So I am making a small quiz on JavaScript for the first time. I wanted the user to be able to select between 3 options(a, b and c) by entering the letter in a text box and clicking a button to check the answer. A text will then appear underneath the text box to show whether the user entered the right option or not.
I have managed to make this work but since there are multiple questions, I wanted to use a for loop to loop through each text box (I named each text box "0", "1" ...) but I cannot reference them using i. How can I do it?
Here is my JavaScript:
var answer = ["a", "b", "c"];
var results = "results"
function check() {
for (i = 1; i = 4; i++) {
var input = document.getElementById(i).value;
if (input == answer[parseInt(i-1)]) {
document.getElementById(results.concat(i)).innerHTML = "Correct";
}
else {
document.getElementById(results.concat(i)).innerHTML = "Wrong";
}
}
}
Here is the HTML (I repeated the same code for each question with a different ID):
<input type="text" id="0" value="a, b or c"><br>
<input type=button value="Check" onClick="check()"><br>
Result: <span id="results0"></span><br><br>
This should work:
There are a few things wrong with your original code
Wrong:
for (i = 1; i = 4; i++)
usually we start our iterations on 0 index, also the middle portion of the for loop should return truthy which means it should evaluate to true or false "i = 4" will never be either because = is an assignment operator, you should use evaluation operators >, <, >=, ==, etc.
for (i = 0; i < 3; i++) {
var input = document.getElementById(i).value;
if (input == answer[i]) {
document.getElementById("results" + i).innerHTML = "Correct";
}
else {
document.getElementById("results" + i).innerHTML = "Wrong";
}
}
Additionally you were using "result" like a variable in this:
results.concat(i)
So results would need to be a variable that contains the string "results" which I doubt is the case. so what we are telling the getElementById method by doing it this way
document.getElementById("results" + i)
is to find an element with an ID of "results" plus the index of the loop eg. id="result0", or id="result1" etc.
If you have all of these within a <div> or div tag you can reference them using :nth-child notation. This works by referencing the nth child from the beginning.
$("div:nth-child(i)");
With the html you provided your for loop is incorrect.
Since you started your input at 0 you want to start looping at 0.
for (i = 0; i <= 2; i++) { //with three values 0,1,2
...
}
Your <span> tag also need to be closed with a </span>
Looping through id's feels very dirty to me. From a maintenance and readability standpoint, I recommend you loop through a collection of Nodes instead.
I believe that you are looking for:
document.getElementsByClassName("someClass")[0];
Where [0] Would be the index of the element whos class is shared.
Here is a code sample I wrote for you to reference using textboxes and outputting the values into a div within a for loop.
https://jsfiddle.net/4ocnyy38/1/
You can dynamically create inputbox and result span and alot dynamic ids to them and then check the correct answer on click of button
Javascript:
var answer = ["a", "b", "c"];
var results = "results";
setTimeout(function(){
var injectData='';
for(var i=0;i<3;i++){
injectData+="<input type='text' id='id_"+i+"' placeholder='a, b or c'/> Result: <span id='results_"+i+"'></span><br/>";
}
document.getElementById('inject').innerHTML=injectData;
},500);
function check() {
for (i = 0; i <3; i++) {
var input = document.getElementById('id_'+i).value;
if (input == answer[i]) {
document.getElementById("results_"+i).innerHTML = "Correct";
}
else {
document.getElementById("results_"+i).innerHTML = "Wrong";
}
}
}
HTML:
<div id="inject">
</div>
<input type=button value="Check" onClick="check();"><br>
Demo: https://jsfiddle.net/9ea46of5/

Javascript stuck at "for" loop

i am newbie learner and i am learning basic javaScript from codecademy.I stuck at "Search Text for Your Name" tutorial 5/7.
here is my question:
your loop should stop when it hits the value of the first iterator (say, i)
plus the length of your myName variable.
here is some informations from to tutorial:
Your second "for" loop
Okay! Last loopy step: add another for loop, this time inside the body of your if statement (between the if's {}s).
This loop will make sure each character of your name gets pushed to the final array. The if statement says: "If we find the first letter of the name, start the second for loop!" This loop says: "I'm going to add characters to the array until I hit the length of the user's name." So if your name is 11 letters long, your loop should add 11 characters to hits if it ever sees the first letter of myName in text.
For your second for loop, keep the following in mind:
First, you'll want to set your second loop's iterator to start at the first one, so it picks up where that one left off. If your first loop starts with
> for(var i = 0; // rest of loop setup
your second should be something like
> for(var j = i; // rest of loop setup Second
think hard about when your loop should stop.
Finally, in the body of your loop, have your program use the .push() method of hits. Just like strings and arrays have a .length method, arrays have a .push() method that adds the thing between parentheses to the end of the array. For example,
newArray = [];
newArray.push('hello');
newArray[0]; // equals 'hello'
and here is my code:
multistr:true
var text = "Hey, how are you \
doing? My name is Emily.";
var myName = "Emily";
var hits = [];
for (var i = 0; i > text.length; i++)
{
if (text[i] === 'E')
{
for(var j = i; j > text.length; j++){
};
};
};
ps: i don't want to pass this tutorial without understand it. please help me. teach me.
for (var i = 0; i > text.length; i++) should be
for (var i = 0; i < text.length; i++)
otherwise it won't ever meet the criteria to even start the loop.
Welcome on board! You confused > with <. Your loops won't run because for the first check when i = 0 it certainly does not hold that 0 > text.length, because text.length is at least 0 (there are no strings shorter than the empty string).
You should make a habit of manually going through your loops for the first two steps and then check what happens just before the loop ends.
Here is what I got for my code:
for ( i = 0; i < text.length; i++)
{
if ( text[i] === "E")
{
for( var j = i; j < (myName.length + i ); j++)
{
hits.push(text[j]);
}
}
};
It looks like you were missing the " + i " part in your second for loop. That seems to make sure that the first loop will be included. I tried it without the "+ i" and it does not work.
I tried continuing directly from the second for loop using a "+ j" and that only crashes the browser.

Javascript array + index

Im still needing help with this, and have edited the jsfiddle post to show my problem. http://jsfiddle.net/7ztEf/6/
I want to return number to associated index value [0] =0 [1]=1 as you can see the index string returns all numbers. Thanks again Paul
I have a number generator script that returns values to DIV ID's. I need to hook into this somehow, to enable replacing color based upon the number value i.e. > 1 && <= 20 = red etc.
function myNumbers(numbers, type) {
for (var x in numbers) {
document.getElementById(type + x).innerHTML = numbers[x];
}
}
This script fills each of the DIVs named num0 ... num3 with a random number.
I have managed to query the first value of numbers[x] but need to set an index order to loop through the rest, or something.
Use Array.forEach.
numbers.forEach(function (number, index) {...})
Don't use for..in for arrays. They're meant to be used on objects so using for..in on arrays will return such things as the length element.
Either use forEach as ethagnawl mentioned or use the traditional for loop:
for (var x=0; x < numbers.length; x++) {
document.getElementById(type + x).innerHTML = numbers[x];
}

Categories