How to use variable inside for loop - javascript

I have 50 rows in google spreadsheet. User use these rows as input. But not all 50 rows are shown. When user input number in A2 cell then only that number of the rows are visible. I was able to do the task. But there is one problem inside for loop.
I think problem is in this line
for(var i = 2; i < fillingRows; i++){
//This is my full code.
function onEdit(e) {
//Logger.log("Previous value was - " + e.oldValue);
//Logger.log("New value is - " + e.value);
var range = e.range;
var rowNumber = range.getRow();
var columnNumber = range.getColumn();
//Logger.log("Row - " + rowNumber);
//Logger.log("Column - " + columnNumber);
if (rowNumber == 2 && columnNumber == 1){
//Logger.log(e.value);
var fillingRows = e.value + 2;
//Hide rows from 3 to 51
var spreadsheet = SpreadsheetApp.getActive();
spreadsheet.getRange('3:51').activate();
spreadsheet.getActiveSheet().hideRows(spreadsheet.getActiveRange().getRow(), spreadsheet.getActiveRange().getNumRows());
Logger.log(fillingRows);
for(var i = 2; i < fillingRows; i++){
spreadsheet.getActiveSheet().showRows(i, 1);
}
}
}
When I change that line to something like this
for(var i = 2; i < 10; i++){
Then it works correctly. But I can't use constant number here.
Isn't it possible to use variable inside a for loop.

Try this:
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()!="Your sheet name")return;//Edit this. Add your sheet name
if(e.range.rowStart==2 && e.range.columnStart==1 && e.value>=1 && e.value<=50){
//e.source.toast('Value: ' + e.value);
sh.hideRows(3,50);
sh.showRows(3,e.value);
//sh.getRange(1,1).setValue(e.value);
}
}

It's probably because fillingRows is no greater than 2, and therefore,
I suggest printing & checking fillingRows.

Related

Search for matching cells then copy one cell to a different location in Google Sheets

I have two different sheets in a spreadsheet that both contain emails. I am trying to move 3 cells from the row that an email is on in sheet "y" to the row that that same email is on in sheet "x".
Example:
An email is on sheet "y" at D3, that same email is on sheet "x" at F7; I then want to copy the cells from H3:K3 on sheet "y" (because the email was in row 3 on sheet "y") to L7:P7 on sheet "x" (because the same email was in row 7 on sheet "x").
Also on I have this formula in R2 on sheet "x" and N2 on sheet "y" to tell what is the last row that has data in it so the script only scans for matching emails up until that row. I have variables "finalRowV" and "maxEmail" referring to those cells respectively:
=COUNTIF(A1:A, "<>")
I'm not the best at JavaScript but I feel like I compiled a coherent script (to me...) but when I ran it nothing happened: there was no error but the data was not moved.
function onOpen(e){
function runIt(){
var mainSheet = SpreadsheetApp.getActiveSpreadsheet();
var workoutSheet = mainSheet.getSheetByName("x");
var customerSheet = mainSheet.getSheetByName("y");
var searchRow = 2;
var searchLoc = "C" + searchRow;
var copyLoc = "D" + searchRow + ":F" + searchRow;
var maxEmail = customerSheet.getRange("N2").getValue();
var found = 0;
if (searchRow > maxEmail){
if(found = 0){
Logger.log("No match found");
}
else{
endSearch();
}
}
var finalRowV = workoutSheet.getRange("R2").getValue();
var targetColumnV = "C2:C" + finalRowV;
var targetColumn = workoutSheet.getRange(targetColumnV).getValues();
var email = customerSheet.getRange(searchLoc).getValue();
for (var i = 2; i < targetColumn[2].length; i++){
if (targetColumn["C"][i].toString() == email.toString()){
Logger.log("found the email " + targetColumn["C"][i] + " at cell" + searchRow + i);
found++;
searchRow++;
var pasteLoc = "M" + i + ":O" + i;
customerSheet.getRange(copyLoc).copyTo(workoutSheet.getRange(pasteLoc));
runIt();
}
else {
customerSheet.getRange(searchLoc).setBackground("red");
i++;
searchRow++;
runIt();
}
}
}
function endSearch(){
}
}
I found it hard to reproduce your code, therefore I just made a similar scenario based on your question which you can use for your case as well:
function moveEmails() {
ss = SpreadsheetApp.getActive();
sx = ss.getSheetByName("x");
sy = ss.getSheetByName("y");
sx_size = sx.getLastRow();
sy_size = sy.getLastRow();
x_email = sx.getRange("F2:F"+sx_size).getValues().flat([1]);
y_email = sy.getRange("D2:D"+sy_size).getValues().flat([1]);
for (var i = 0 ; i < y_email.length ; i++ ) {
pos_found = x_email.indexOf(y_email[i]);
if (pos_found > -1) {
y_data = sy.getRange("H"+(i+2)+":K"+(i+2)).getValues();
sx.getRange("L"+(pos_found+2)+":O"+(pos_found+2)).setValues(y_data);
}
}
}
Explanation:
I have two sheets: x,y ,
emails in x are in column F and emails in y are in column D,
columns in both sheets have a header, this is why the ranges start from the second row,
check if an email from y list matches email from x list,
if there is a match copy the relevant data from y(H:K) to x(L:0) since you copy data from 4 columns.
Concepts you can use:
Instead of having the count formula =COUNTIF(A1:A, "<>") to calculate the last row with content, you can use the google script method: sheet.getLastRow().
Finally, pos_found = x_email.indexOf(y_email[i]) gives the position of the element in list x_email where the element y_email[i] was matched. If there is no match, it returns -1.

Google sheets script - Strip extra data from a second line and add it to the first line

I'm trying to build a script in google sheets script that will iterate down a sheet, row by row, and if it encounters an ID number in the first cell of that row that is identical to the one above it, it strips out the data from every cell EXCEPT Column A and B, and appends it to the line above. Ideally, this would work with an indeterminate number of duplicate row IDs, might be 2, might be 3, might be 4.
After stripping out the data I want to keep (eg colums C and onward), I then want to delete the entire contents of the processed duplicate ID row, but I just haven't put that in my script until after it copies the data correctly.
In this example, sheet rows 6, 7 and 8 have identical ID numbers (Column A)
Here is the result I'm trying to get:
And here is the result I'm getting:
I've tried a number of different ways, and torn down and rebuilt my script a couple of times without getting the result I want:
function stripMiner() {
var ss = SpreadsheetApp.openById("1WDPoTICQvdruxfhAwHLtA51fz05DqyZ-NhNfpAyPO6Y");
var mainSheet = ss.getSheetByName("Main");
var startRow = 5;
var numRows = mainSheet.getLastRow();//obtains the last row in the sheet
var setrgh = mainSheet
var dataRange = mainSheet.getRange(startRow, 1,4,120); //rowStart, columnStart, row count, column count, the columncount needs to be large enough to encompass all your ancillary data
var data = dataRange.getValues();
var iter = 0;
var maxItRow = 4;
var prevIdNum = 0;
var dupCount = 1;
var cc1 = "P5"; //Cells to dump check values into
var cc2 = "P6";
var dumpRow = startRow;
//if (numRows >= maxItRow){var maxIter = maxItRow;}
for (i in data){
if (iter != maxItRow){ //making sure we haven't gone over the iteration limit
var row = data[i];
var idNum = (row[0]);
var jCount = 0; //resets icount if the id number is different icount is used to skip some cells in a row
if (idNum == prevIdNum){//only proceed if we've hit another line with the same ID number
dupCount = +1; //increment the dupcount value
mainSheet.getRange(cc2).setValue("dupCount"+dupCount); //dupcount check value
var rowIterStart = 5; //RowIterStart is used to add to rowiter, EG if your data is 20 columns wide, and you start transposing from column 4, then this will want to be about 17
var rowIter = 1;
for (j in row){
if (jCount >= 2){ //the integer here is the column where it will begin to transpose data
mainSheet.getRange(dumpRow-1,(rowIterStart*dupCount)+(rowIter)).setValue(row[j]); //startRow+(iter-dupCount)
mainSheet.getRange(cc1).setValue("dumprow"+dumpRow);
}
rowIter+=1;
jCount +=1;
}
}
else{
var dupCount = 1;
dumpRow +=1;
}
prevIdNum = (row[0]); //sets the most recently processed rows ID number
}
iter +=1;
}
}
I'm not quite sure where I'm going wrong. Does anyone have any suggestions? Thanks!
(Also I'm still just a beginner with this so if I've overlooked anything obvious or taken the wrong approach to do this, I apologize!)
The results for the questioner's code in the case of copied data arise from a convoluted loop. In essence, though duplicates were identified, there was a mis-counting to assign the copied data to the correct rowID. So far as clearing data, no provision was included.
The following code works to meet the questioner's goals, though it is far from perfect.
At present, the recalculation of the "last column" after copy each duplicate is an absolute rather than than a row-based figure. So, if a duplicate was detected for, say, ID=3, the data would be copied to column 12 rather than column 6. This requires the addition of a simple dupID row counter.
The second factor is the calculation of the last column in the spreadsheet.
var dataRange = mainSheet.getRange(startRow, 1,Rowlast+1,120);
The questioner used 120 columns; and I have retained that number simply for the sake of consistency. The questioner should re-assess whether this is excessive.
function ejb_so_5284922701() {
var ss = SpreadsheetApp.openById("<< insert questioners spreadsheet ID>>");
var mainSheet = ss.getSheetByName("<< insert questioner's sheet name >>");
var startRow = 5;
// calculate the last row containing data
var Rowvals = ss.getRange("A5:A").getValues();
var Rowlast = Rowvals.filter(String).length; //6
Logger.log("last row = " + Rowlast); // DEBUG
// calculate the last column containing data
var cell = mainSheet.getRange("A5"); //or however you determine "cell"
var drCol = mainSheet.getDataRange().getLastColumn();
Logger.log('getLastColumn = ' + drCol); //DEBUG
for (var i = drCol; i >= 1; i--) {
if (mainSheet.getRange(cell.getRow(), i).getValue() != "") {
break;
}
}
var lastColumn = i;
Logger.log("Last column with data = " + lastColumn); //DEBUG
var setrgh = mainSheet
// numColumns neds to be reviewed
var dataRange = mainSheet.getRange(startRow, 1, Rowlast + 1, 120); //rowStart, columnStart, row count, column count, the column count needs to be large enough to encompass all your ancillary data
// start row = 5, 1= column A, 4, rows, 120, columns
Logger.log("startRow = " + startRow + ", and the datarange = " + dataRange.getA1Notation()); //DEBUG
var data = dataRange.getValues();
Logger.log("length of data =" + data.length); //DEBUG
var lastid = 0;
for (i = 0; i < data.length; i++) {
if (i == 0) {
// if this is the first row, then assign anything but zero to last id
lastid = 100;
Logger.log(" this is the first row; set last id to 100");
}
var thisid = data[i][0];
// evaluate whether this is a duplicate ID
if (thisid == lastid) {
// this is a dup
Logger.log("i=" + i + ". This is a dup" + ", name is " + data[i][2]); //DEBUG
var stufftocopyrange = mainSheet.getRange(startRow + i, 3, 1, 3);
var stufftocopy = stufftocopyrange.getValues();
Logger.log("the range to copy is " + stufftocopyrange.getA1Notation()); //DEBUG
var targetrange = mainSheet.getRange(startRow + lastid - 1, lastColumn + 1, 1, 3);
targetrange.setValues(stufftocopy);
lastColumn = lastColumn + 3;
var duprange = mainSheet.getRange(startRow + i, 1, 1, 5);
Logger.log("the range to clear is " + duprange.getA1Notation()); //DEBUG
duprange.clearContent();
} else {
// no dup
//assign lastid value
var lastid = thisid;
Logger.log("i=" + i + ". No dup. Last id set to " + lastid); // DEBUG
} // if
} // end for loop
}
BEFORE
AFTER
The solutions previously posted didn't quite get the result I needed, however I managed to cobble together something that works for my purposes. It expects to see data in the format like:
And turn it into something like this:
Where it uses duplicate ID numbers (with an indeterminite number of duplicates) to pull only certain columns of data from the duplicate lines and append it to the first line.
function stripMiner() {
var ss = SpreadsheetApp.openById("1WDPoTICQvdruxfhAwHLtA51fz05DqyZ-NhNfpAyPO6Y");
var mainSheet = ss.getSheetByName("Main");
var startRow = 5;
var numRows = mainSheet.getLastRow();//obtains the last row in the sheet
var setrgh = mainSheet
var dataRange = mainSheet.getRange(startRow, 1,3,120); //rowStart, columnStart, row count, column count, the columncount needs to be large enough to encompass all your ancillary data
var data = dataRange.getValues();
var iter = 0;
var maxItRow = 4;
var prevIdNum = 0;
var dupCount = 1;
var cc1 = "P5"; //Cells to dump check values into
var cc2 = "P6";
var dumpRow = startRow;
//if (numRows >= maxItRow){var maxIter = maxItRow;}
for (i in data){
if (iter != maxItRow){ //making sure we haven't gone over the iteration limit
var row = data[i];
var idNum = (row[0]);
var jCount = 0; //resets icount if the id number is different icount is used to skip some cells in a row
if (idNum == prevIdNum){//only proceed if we've hit another line with the same ID number
dupCount = +1; //increment the dupcount value
mainSheet.getRange(cc2).setValue("dupCount"+dupCount); //dupcount check value
var rowIterStart = 5; //RowIterStart is used to add to rowiter, EG if your data is 20 columns wide, and you start transposing from column 4, then this will want to be about 17
var rowIter = 1;
for (j in row){
if (jCount >= 2){ //the integer here is the column where it will begin to transpose data
mainSheet.getRange(dumpRow-2,(rowIterStart*dupCount)+(rowIter)).setValue(row[j]); //startRow+(iter-dupCount)
mainSheet.getRange(cc1).setValue("dumprow"+dumpRow);
}
rowIter+=1;
jCount +=1;
}
}
else{
var dupCount = 1;
dumpRow +=1;
}
prevIdNum = (row[0]); //sets the most recently processed rows ID number
}
iter +=1;
}
}
Hopefully someone else who wants to do a similar thing can make use of this too.

google script, match column with other and grab next value

I'm trying to make a google script to automate some calculations in a google spreadsheet.
I have several things in this sheet and what i need is, for all the date values i have on A column (between rows 3 and 20) i need to search on the column T (between rows 17 and 50) and when a date match i need to grab the value in the cell next to the data in column T.
Then with this sum i need to go to the B move one row down and substract that sum from the above cell.
example:
A
17/8/2017
18/8/2017
19/8/2017
B
100
empty
empty
T
empty
empty
18/8/2017
18/8/2017
18/8/2017
19/8/2017
U
empty
empty
5
5
2
1
After running the script B should be:
100
88
87
My code:
function burnDown(){
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sheet.getDataRange().getValues();
var completed = sheet.getRange(20, 20, 40);
for(var i = 3; i<20;i++){
for(var j = 1; i<50; j++){
var sum = 0;
if(data[i][0] == completed[j][0])
{
sum = sum + completed[j][20];
Logger.log(completed[j][21] + "" + sum);
}
j++;
}
i++;
}
}
I'm stuck at this point where I have to make the match but i'm getting the error: TypeError: Cannot read property "0" from undefined. (line 9, file "BurnDown"
Thanks,
No values in completed. Perhaps you need a getValues() somewhere
function burnDown()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = sheet.getDataRange().getValues();
//var completed = sheet.getRange(20, 20, 40);//this is a range
var completed = sheet.getRange(20,20,40).getValues();//this creates a 2d array of values
for(var i = 3;i<20;i++)
{
for(var j = 1; j<50; j++)
{
var sum = 0;
if(data[i][0]==completed[j][0])
{
sum=sum + completed[j][20];
Logger.log(completed[j][21] + "" + sum);
}
//j++;//not sure why these are here the loop increments
}
//i++;//same question as above
}
}

Looping through Spreadsheet to collect data starting with xxx_bb

I am confused about the following task.
Eventually, I want to find certain data in a spreadsheet.
This is not a problem, I can find a defined value and grab whatever information I need around it through:
function findCell() {
var ss = SpreadsheetApp.openById('ID');
var sheet = ss.getSheetByName('NAME');
var dataRange = sheet.getDataRange();
var values = dataRange.getValues();
for (var i = 0; i < values.length; i++) {
var row = "";
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] == "Hallo") {
row = values[i][j+11];
Logger.log(row);
Logger.log(i);
}
}
}
}
But I am not trying to find the exact value "Hallo" but anything starting with "Hallo_xxx". I tried to use i.e. indexOf but I am not sure what I am doing wrong - this task doesn't sound too difficult to solve. Does anybody got a good idea here...?
Thanks for your advice,
Sa
Here's some code I just wrote and tested. findCell() should do what you want. As you surmised, indexOf() will quickly find specific text within a string, but I don't see where you tried to use it in your code.
var ROW = 0;
var COLUMN = 1;
function test(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var results = findCell("Hallo_xxx", sheet);
for(var i=0 ; i<results.length ; i++){
Logger.log("Match found at: " + colToA1(results[i][COLUMN]) + (results[i][ROW] + 1));
}
}
function findCell(string, sheet) {
var range = sheet.getDataRange();
var values = range.getValues();
var results = [];
for(var i=0 ; i<values.length ; i++){
for(var j=0 ; j<values[0].length ; j++){
if(values[i][j].indexOf(string) != -1){
results.push([i, j]);
}
}
}
return results;
}
function colToA1(col){
return col < 26 ?
String.fromCharCode(col + 65) :
String.fromCharCode(parseInt(col / 26) + 64) + String.fromCharCode((col % 26) + 65);
}
Working on this a bit, the answer I was looking for is:
function findCell2() {
var ss = SpreadsheetApp.openById('ID');
var sheet = ss.getSheetByName('Name');
var values = sheet.getDataRange().getValues();
for(var i=1;i<values.length;i++){
if((values[i][1].indexOf('Hallo') > -1){
Logger.log('xxx: ' + values[i][2]);
}
}
}

Match a range of rows in an array? jQuery, Javascript

I'm unsure how else to write the title but it's about as close as I can get to what I'm after.
I have a calculator I'm trying to create that compares values in a number of arrays.
Each data object in my array has 34 rows, some of which have the same number/value in them.
At the minute if you select france, I only want 1 of each grade to show in the dropdown, so the number 1 would appear once.
If you select France and grade 1, I want the outputted value to say the lowest value in that range to the highest, in this case USA would output 3 to 5 does this make sense?
If so I'm wondering how I'd possibly do this?
JSFiddle
http://jsfiddle.net/R85Qj/
Does this help?
http://jsfiddle.net/R85Qj/2/
$("#convert").on("click", function () {
var gradeIndex = $("#grade").val();
var gradeConversion = "";
/* gradeConversion += "<span>" + countryGrades[countryGradesIndex].country + ": " + countryGrades[countryGradesIndex].grades[gradeIndex][1] + "</span>";*/
var indexes = [];
var countryIndex = $("#country").val();
var gradeValue = countryGrades[countryIndex].grades[gradeIndex][0];
// find all indexes of gradeValue
for(var i = 0; i < countryGrades[countryIndex].grades.length; i++) {
if (countryGrades[countryIndex].grades[i][1] == gradeValue) {
indexes.push(i);
}
}
allValues = [];
for(var c = 0; c < countryGrades.length; c++) {
gradeConversion += countryGrades[c].country + ":";
for(i = 0; i < indexes.length; i++) {
if (i == 0 || countryGrades[c].grades[indexes[i]][1] != countryGrades[c].grades[indexes[i-1]][1]) {
gradeConversion += countryGrades[c].grades[indexes[i]][1] + " ";
}
}
}
$("#conversions").html(gradeConversion);
});

Categories

Resources