Getting 'activeSpreadsheet.getSheetByName()' to change dynamically - javascript

Please see the picture below
I have this GoogleSheets spreadsheet with a BUNCH of tabs (sheets) in it. The following code needs to run for EVERY sheet:
function SearchCols()
{
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"),
searchVal = sheet.getRange("L7").getValue(),
searchCol = sheet.getRange('L11:L30').getValues();
searchCol1 = sheet.getRange ('R11:R30').getValues();
searchCol2 = sheet.getRange('Q11:Q30').getValues();
searchCol3 = sheet.getRange('S11:S30').getValues();
searchCol4 = sheet.getRange('T11:T30').getValues();
for (var i = 0, len = searchCol2.length; i < len; i++)
for (var j = 0, len2 = searchCol1.length; j < len2; j++)
{
if (searchCol2[j][0] == searchVal && searchCol1[j][0] == searchCol[i]
[0])
{
sheet.getRange('N11:N10').setValue;
sheet.getRange(i + 11, 14).setValue(searchCol3[j][0])
sheet.getRange(i + 11, 15).setValue(searchCol4[j][0])
}
}
}
It just some code to loop through a column to see if any values match with another column, and if so, paste some data into adjacent cells.
The code works, BUT...
See the 3rd line of code? Where it says: ".getSheetByName("Sheet1")"???
How do I change that "Sheet1" part so it DYNAMICALLY knows what sheet I'm on in order to run the code FOR THAT SPECIFIC SHEET?
I have a 'Run' button in EVERY sheet of my file, but I ONLY want this code to run for the sheet that I press the button in. (look at the attached screenshot!)
The way it is right now, if I'm in Sheet50 and I press the button to run this code, it will produce the results in Sheet1, but I need it to produce results in Sheet50! The same applies for every sheet of my file. When I press the 'Run' button, I need the code to ONLY run for that specific sheet.
Please help, dear friends!

To loop through all of your sheets:
Get all of the sheets in the spreadsheet using .getSheets() then use a for loop to iterate through all of the sheets in the spreadsheet.
This is your code modified to work as you asked:
function SearchCols() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ss.getSheets();
for (var i = 0; i < sheets.length; i++) {
var sheet = ss.getSheetByName(sheets[i].getName());
var searchVal = sheet.getRange("L7").getValue();
var searchCol = sheet.getRange('L11:L30').getValues();
var searchCol1 = sheet.getRange('R11:R30').getValues();
var searchCol2 = sheet.getRange('Q11:Q30').getValues();
var searchCol3 = sheet.getRange('S11:S30').getValues();
var searchCol4 = sheet.getRange('T11:T30').getValues();
for (var x = 0, len = searchCol2.length; x < len; x++) {
for (var j = 0, len2 = searchCol1.length; j < len2; j++) {
if (searchCol2[j][0] == searchVal && searchCol1[j][0] == searchCol[x][0]) {
sheet.getRange('N11:N10').setValue;
sheet.getRange(x + 11, 14).setValue(searchCol3[j][0])
sheet.getRange(x + 11, 15).setValue(searchCol4[j][0])
}
}
}
}
}

Related

Changing existing script for Finding Duplicates in Google Sheets and entering "yes" in the last column instead of coloring it

I am new here and have no idea what I am doing. I found a script online and thought it would work for what I needed, but I would like to change it some. Any help would be appreciated. I have already changed it a little. If it would help to share the form with someone I can do that since it is only in the testing stages.
What I am wanting to do is instead of coloring the duplicates red in the main sheet I want it to put "Yes" in the last column of the main sheet. I would also like it to ignore the blank rows. Is this possible? (I copied the script I am currently using below)
function findDuplicates() {
// List the columns you want to check by number (A = 1)
var CHECK_COLUMNS = [13];
// Get the active sheet and info about it
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("USE THIS SHEET FOR DATA").activate();
var numRows = sourceSheet.getLastRow();
var numCols = sourceSheet.getLastColumn();
// Create the temporary working sheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var newSheet = ss.insertSheet("FindDupes");
// Copy the desired rows to the FindDupes sheet
for (var i = 0; i < CHECK_COLUMNS.length; i++) {
var sourceRange = sourceSheet.getRange(1,CHECK_COLUMNS[i],numRows);
var nextCol = newSheet.getLastColumn() + 1;
sourceRange.copyTo(newSheet.getRange(1,nextCol,numRows));
}
// Find duplicates in the FindDupes sheet and color them in the main sheet
var dupes = false;
var data = newSheet.getDataRange().getValues();
for (i = 1; i < data.length - 1; i++) {
for (j = i+1; j < data.length; j++) {
if (data[i].join() == data[j].join()) {
dupes = true;
sourceSheet.getRange(i+1,1,1,numCols).setFontColor("red");
sourceSheet.getRange(j+1,1,1,numCols).setFontColor("red");
}
}
}
// Remove the FindDupes temporary sheet
ss.deleteSheet(newSheet);
// Alert the user with the results
if (dupes) {
Browser.msgBox("Possible duplicate(s) found and colored red.");
} else {
Browser.msgBox("No duplicates found.");
}
};

Why does this for loop not work in Google scripts

i wrote the following loop based on the code found here:
How do I iterate through table rows and cells in javascript?
function myRowLooper() {
var inputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('INPUT');
var inputRange = inputSheet.getRange(2,inputSheet.getLastColumn(),inputSheet.getLastRow());
for (var i = 0, row; row = inputRange.rows[i]; i++) {
Logger.log(row);
for (var j = 0, col; col = row.cells[j]; j++) {
Logger.log(col);
}
}
}
but when I apply it to Google scripts it throws an error: "TypeError: Cannot read property "0" from undefined."
What's causing this?
Because you can't get any value from 'inputRange.rows[i]'.
You may do something like this :
function myRowLooper() {
var inputSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
for(var i = 1; i<=inputSheet.getLastRow(); i++){
for(var j = 1; j<=inputSheet.getLastColumn(); j++){
var cell = inputSheet.getRange(i,j).getValue();
Logger.log(cell);
}
}
}
Hope this will help you.
Thanks.
Your code is extremely sloppy. You are trying to combine variables and condense unnecessarily and it's leading to errors in your code. There's no use in added "efficiency" if it leads to errors and mistakes.
Try something like this --
function yourFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Name");
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getMaxColumns();
var conditionToCheckColumn = (lastColumn - 1);
var conditionRange = sheet.getRange(2, checkColumn, (lastRow - 1), 1);
var check = checkRange.getValues();
for (var i = 0; i < check.length; i++) {
if (check[i] == condition) {
continue;
} else {
//your code here
}
}
}
This will pull a range at which you can check it's value/ condition and if matches, it does nothing. If it does not match, it will perform code. It will then loop to the next row until the last row in your check range that has data.
Be warned - functions count as data despite the cell being visibly empty. If your sheet uses functions like =QUERY, you will have an infinitely looping code unless your =QUERY (or other fx()) has a specific upper limit.

How do you use a script to delete a row off of a spreadsheet that is linked to a form?

I have this script that does several things with data once it is entered into a google form, but I need to make sue that when two entrants have the exact same name that it deletes the previous entry entirely.
function formChanger() {
var doc = DocumentApp.openById('THIS WAS MY ID');
var body = doc.getBody();
var date = body.getListItems();
var dates = [];
for(var i = 0; i<date.length;i++)
{
dates.push(date[i].getText());
}
var form = FormApp.openById('THIS WAS MY ID');
var items = form.getItems();
var ss = SpreadsheetApp.openById("THIS WAS MY ID");
Logger.log(ss.getName());
var sheet = ss.getSheets()[0];
var values = sheet.getSheetValues(2, 4, sheet.getLastRow() , 1);
Logger.log(values);
var names = sheet.getSheetValues(2, 2, sheet.getLastRow(), 1);
var item = items[2].asMultipleChoiceItem();
var choices = item.getChoices()
for(var i=names.length; i>-1; i--){
for(var j=names.length; j>-1; j--){
if(names[i]==names[j] && i != j)
sheet.deleteRow(i);
}
}
var h = -1;
var j = -1;
var k = -1;
var l = -1;
for(var o = 0; o<values.length; o++){
if(choices[0].getValue().equals(values[o].toString()))
h++;
if(choices[1].getValue().equals(values[o].toString()))
j++;
if(choices[2].getValue().equals(values[o].toString()))
k++;
if(choices[3].getValue().equals(values[o].toString()))
l++;
}
if(h>3)
dates.splice(0,1);
if(j>3)
dates.splice(1, 1);
if(k>3)
dates.splice(2, 1);
if(l>3)
dates.splice(3, 1);
emptyDocument();
Logger.log(h);
Logger.log(j);
Logger.log(k);
Logger.log(l);
item.setChoices([
item.createChoice(dates[0]),
item.createChoice(dates[1]),
item.createChoice(dates[2]),
item.createChoice(dates[3])
]);
for(var i = 0; i<dates.length; i++)
body.appendListItem(dates[i]);
Logger.log(doc.getName()+" Contains:");
Logger.log(dates);
}
Yes the code is a mess, and I'm sure that it could be done a better way, but the important part is that I could be able to delete the line of information that is repeated. The compiler will not allow me to do this because the Spread Sheet is linked to the form. is there a way around this?
The following attempts at deletion are blocked in sheets receiving form data:
deletion of columns with form data
deletion of the row with form questions - that is, row 1
Other rows can be deleted at will. This behavior is exactly the same for scripts as it is for user actions.
Your script attempts to delete row 1 because it's buggy. I quote the relevant part:
var names = sheet.getSheetValues(2, 2, sheet.getLastRow(), 1);
for(var i=names.length; i>-1; i++){
for(var j=names.length; j>-1; j++){
if(names[i]==names[j] && i != j)
sheet.deleteRow(i);
What row is names[i] in? It's in row i+2, because i=0 corresponds to row 2. Yet, you attempt to delete row numbered i, two rows above the intended one.
Besides, i>-1; i++ is absurd; you want i-- there.
Here is a simple script that deletes row with duplicates; it's tested with my form responses. It traverses the contents of "Form Responses 1" sheet from bottom to top; if two rows have the same value in column C, the older one gets deleted. I do take care not to attempt deletion of row 1.
(The reason to do this in bottom-up order is to avoid dealing with rows that moved up because others were deleted.)
function deleteDupes() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Form Responses 1');
var values = sheet.getDataRange().getValues();
for (var i = values.length - 1; i > 1; i--) {
if (values[i][2] == values[i-1][2]) {
sheet.deleteRow(i);
}
}
}

Google Spreadsheet Script: "Cannot find function getRange in object Sheet" when creating a simple function

Sorry, for the stupid question, but I´ve searched the whole internet and I could not find a good Tutorial to learn how to program in Google SpreadSheet Script.
I want to make a very simple function just for practice.
function simplesum(input) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets();
var range = sheet.getRange(input);
var x = 0;
for (var i = 1; i <= range.getNumRows(); i++) {
for (var j = 1; j <= range.getNumColumns(); j++) {
var cell = range.getCell(i, j);
x += (cell.getValue());
}
}
return x;
}
I know I could use =sum() to do exactly the same thing. The idea here is to learn how to program.
When I try to use my function in a cell: (i.e: =simplesum((A1:A8)) it gives an Error saying: "TypeError: Cannot find function getRange in object Sheet. (line 4)"
What should I do?
And again, sorry for the dumb question....
In this case, you are implementing a Google Apps Script function as a custom function, invoked in a spreadsheet cell.
When you pass a range to a custom function invoked in a spreadsheet cell, you are not passing a range object or a range reference, but rather a 2-D Javascript array of values. So your custom function should just process that array.
function simplesum(input)
{
var x = 0;
for (var i = 0; i < input.length; i++)
{
for (var j = 0; j < input[0].length; j++)
{
x += input[i][j];
}
}
return x;
}
This is working :
function sum(input) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet(); // your mistake : getSheets()
var range = sheet.getRange(input);
var x = 0;
for (var i = 1; i <= range.getNumRows(); i++) {
for (var j = 1; j <= range.getNumColumns(); j++) {
var cell = range.getCell(i, j);
x += cell.getValue();
}
}
return x;
}
function main () // Yes, I am a former C-programmer ...
{
var s = sum ("A1:B3"); // Notice the quotes. A string must me entered here.
Logger.log('s = ' + s);
}
var sheet = ss.getSheets();
returns an Array of sheets, meaning sheets.getRange(input) will throw that error. Try this instead:
var sheet = ss.getSheets()[0];
which selects the first sheet of the array of sheets. Google has some decent documentation for this. For example, here's its documentation on getRange(). Note that it uses ss.getSheets()[0] as well. Hope this helped!

Unable to filter data from other spreadhseet paste in master sheet based on dates in google spreadsheet

First of all thank you for the efforts made in this site. As an individual and a beginner i have learnt from my errors made. Thanks for all who have contributed & extended their support.
Thanks for this.
Here is a small program written which is not working (no output)seen , i have tried it in many ways but in vain. please help me to find a solution for this.
the aim of this program was to filter the data from 4 sheets and paste into current sheet (master). this filter is based on date values.
Conditions of dates are taken from the master sheet in columns in (b2 & d2)dates. this are to be filtered out based in column no.18 which has dates in client sheets.
function myFunction3() {
var source = ['0AjkkHlm3kCphdGhSWnlxWmFsakZ2aFhMSHl6SlF3M1E',
'0AjkkHlm3kCphdHY2aXpjTVJEMlFRYVBST0ZPYzNwRFE',
'0AjkkHlm3kCphdEc5ZHFpeHVlc241SlFKWGJDeXFKLXc',
'0AjkkHlm3kCphdG9WVjVRRnQ3RlFlcllhd1JGallXVmc'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get start date from sheet
var sDate = ss.getSheetByName('123').getRange("B2").getValue();
// get end date from sheet
var eDate = ss.getSheetByName('123').getRange("D2").getValue();
// days between
var Dura = ss.getSheetByName('123').getRange("E1").getValue();
var codes = new Array();
for (var k = 0; k < Dura; k++){
var d = new Date(sDate);
d.setDate(d.getDate()+ k);
codes[k] = d;
}
var numCodes = codes.length;
var copied = [];
for (var k = 0; k < numCodes; k++) {
copied[k] = [];
}
//get data from external sheets for comparision
for (var i = 0; i < source.length; i++) {
var tempCopy = SpreadsheetApp.openById(source[i]).getSheetByName('Footfall-Format').getDataRange().getValues();
// comparision starts
for (var j = 0; j < tempCopy.length; j++) {
var codeIndex = codes.indexOf(tempCopy[j][5]);
if (codeIndex > -1) copied[codeIndex].push(tempCopy[j]);
}
}
var sheets = SpreadsheetApp.getActive().getSheets();
for (var m = 0; m < numCodes; m++) {
if (copied[m][0] != undefined) {
var gensheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('123');
gensheet.getRange(5, 1, 1500, 18).clear({contentsOnly:true});
gensheet.getRange(5, 1, copied[m].length, copied[m][0].length).setValues(copied[m]);
}
}
}
The fundamental problem is that you are comparing objects for equality - in this case, you're comparing Date objects. Even when the date represented by two of these objects is the same, the object comparison comes up false unless you're actually referencing the same object. You can read more about this in Compare two dates with JavaScript.
Here's a simple change to your script, using toDateString(), that will ensure your codes[] array contains string values that can be compared with values in tempCopy[j][5].
function myFunction3() {
var source = ['0AjkkHlm3kCphdGhSWnlxWmFsakZ2aFhMSHl6SlF3M1E',
'0AjkkHlm3kCphdHY2aXpjTVJEMlFRYVBST0ZPYzNwRFE',
'0AjkkHlm3kCphdEc5ZHFpeHVlc241SlFKWGJDeXFKLXc',
'0AjkkHlm3kCphdG9WVjVRRnQ3RlFlcllhd1JGallXVmc'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get start date from sheet
var sDate = ss.getSheetByName('123').getRange("B2").getValue();
// get end date from sheet
var eDate = ss.getSheetByName('123').getRange("D2").getValue();
// days between
var Dura = ss.getSheetByName('123').getRange("E1").getValue();
var codes = new Array();
for (var k = 0; k < Dura; k++){
var d = new Date(sDate);
d.setDate(d.getDate()+ k);
codes[k] = d.toDateString(); //***** Make array of Strings, not Dates
}
var numCodes = codes.length;
var copied = [];
for (var k = 0; k < numCodes; k++) {
copied[k] = [];
}
//get data from external sheets for comparision
for (var i = 0; i < source.length; i++) {
var tempCopy = SpreadsheetApp.openById(source[i]).getSheetByName('Footfall-Format').getDataRange().getValues();
// comparision starts
for (var j = 4; j < tempCopy.length; j++) { // start at 4 to skip headers
if (typeof tempCopy[j][5] != "object") break; // skips strings, but could improve
// Search for String match of date from input record
var codeIndex = codes.indexOf(tempCopy[j][5].toDateString());
if (codeIndex > -1) copied[codeIndex].push(tempCopy[j]);
}
}
// This part has bugs... each day overwrites the previous
var sheets = SpreadsheetApp.getActive().getSheets();
for (var m = 0; m < numCodes; m++) {
if (copied[m][0] != undefined) {
var gensheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('123');
gensheet.getRange(5, 1, 1500, 18).clear({contentsOnly:true});
gensheet.getRange(5, 1, copied[m].length, copied[m][0].length).setValues(copied[m]);
}
}
}
As #Serge points out, there are other problems in this code.
d.getDate()+ k does not handle month-end, so you need to do that yourself.
The last part of your script that handles the output via setValues() needs to be debugged. As it is, each day overwrites the previous day's values from the copied[] array. I'm not sure what requirement you were trying to meet with this, so I left it alone, but it needs attention.

Categories

Resources