We want to make a Google Form where there are dropdown options pulled from column F of the sheet (Sheet1), beginning in row 3 on down. However, column F has formulas in it, specifically: =IF(D$="","", CONCATENATE(C$," - ",D$)), so that some of the cells appear blank while others have visible text.
The code we attempted to use below does not work. Any help on how to make this work by pulling choices from column F, but of course ignoring blank cells?
var form = FormApp.openById('1Hg4TvEZUnzIMZI_andbwHQ3jtaIBLOZsrTkgjSwVcAY')
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
const current = sheet.getRange(3,6,sheet.getLastRow()-1,6).getValues()
var range = sheet.getDataRange();
var rangeList = current.map(function (row, i) {
for (var i=rangeList; i<range.length; i++) {
if (row[5] == "") return;
var matched = row[5];
const Question = form.getItemById ("620176576")
Question.asListItem().setChoiceValues(matched)
}
})
}
You've to use filter to only get the values which are not null.
Try below sample script:-
const form = FormApp.openById('1Hg4TvEZUnzIMZI_andbwHQ3jtaIBLOZsrTkgjSwVcAY')
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1')
const current = sheet.getRange(3,6,sheet.getLastRow()-3).getValues().flat().filter(r=> r) //filtering out blank values
const Question = form.getItemById("620176576")
Question.asListItem().setChoiceValues(current)
Reference:
filter()
Related
I am trying to compare values on 2 different columns values to ensure that they exist(on Sheet 1)
Once the script is aware that they exist I need to access sheet1's column for quantity and add that value to sheet 2's quantity column. The problem is I am unsure of how to just get the location/index of the foreach loop and offset a setValue to another column without setting the value to the entire column(I dont want to do that if the product name of column A does not exist in Sheet1)
Here is the code example of how i am trying to do it
I have included it in a pastebin because I could not figure out how to format the code to paste ( sorry i'm super new at this!)
<https://pastebin.com/EKB2n9kA>
Sheet1 incoming data https://drive.google.com/file/d/1eLNeOZZbdeCDfMMImksVRnBXwKxpHIO_/view?usp=sharing
Sheet2 'base' data to add quantity values to https://drive.google.com/file/d/1h26H9eQgZapd2Y0LVamhRPYme-8LmVF0/view?usp=sharing
example of expected/wanted results https://drive.google.com/file/d/1-0ozD5PrbIq-otG4j7kAyLufQFjDR5Hi/view?usp=sharing
I have also attached 3 different reference photos
Sheet 1 is 'incoming' data to read
Sheet 2 is our 'base' data and where Sheet1's quantity column needs to be added to
the third screenshot is the expected result(having the script skip over rows that do not contain matching data but still being able to get the quantity value based on the index/location the value was found)
Any insight on how to achieve this would be sincerely appreciated
I have tried pushing the results into an empty array but it does not seem to give much useful info the way I am doing it.
I have also tried just getting an offset range (getRange("G2:G").offset(0,3).setValues() to set the results but it sets the value of the entire column instead of only where the values match for each column being compared.
From your <https://pastebin.com/EKB2n9kA>, it seems that your current script is as follows.
function compareCol() {
var ss = SpreadsheetApp.getActiveSpreadSheet();
var s1 = ss.getSheetByName("Sheet1");
var s2 = ss.getSheetByName("Sheet2");
var datA = s1.getRange("A2:A").getValues();
var datB = s2.getRange("A2:A").getValues();
var quantityA = s1.getRange("C2:C").getValues();
var quantityB = s2.getRange("D2:D");
let matchingCol = [];
for (var i in datA) {
for (var x in datB[i]) {
if (datA[i][0] === datB[x][0]) {
}
}
}
}
Modification points:
In your script, the if statement in the loop has no script. And, quantityA, quantityB, and matchingCol are not used.
When your script is modified for achieving your goal, how about the following modification?
Modified script:
function compareCol() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s1 = ss.getSheetByName("Sheet1");
var s2 = ss.getSheetByName("Sheet2");
var datA = s1.getRange("A2:C" + s1.getLastRow()).getValues().reduce((o, [a, , c]) => (o[a] = c, o), {});
var datB = s2.getRange("A2:D" + s2.getLastRow()).getValues();
var matchingCol = datB.map(([a, , , d]) => [datA[a] || d]);
s2.getRange(2, 4, matchingCol.length).setValues(matchingCol);
}
In this modification, when the value of column "A" in "Sheet2" is not found from column "A" of "Sheet1", the value of column "D" of "Sheet2" is used. If you want to remove this, please modify it as follows.
From
var matchingCol = datB.map(([a, , , d]) => [datA[a] || d]);
To
var matchingCol = datB.map(([a]) => [datA[a] || null]);
References:
reduce()
map()
Hopefully this will help
function comparingColumns() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const osh = ss.getSheetByName("Sheet1");
const [h,...vs] = sh.getDataRange().getValues();
vs.forEach((r, i) => {
//comparing column A to Column D
if (r[0] == r[3]) {
//getting column G of same row in sheet1
osh.getRange(i + 2, 7).setValue(r[6]);
}
})
}
Im currently trying to move in bulk all the rows from a sheet where the checkbox is selected, I was trying to use "newFilterCriteria" but the one I use (found online) check on specific words while I want to use checkboxes.
The code so far does:
Get the source page, declare the filter criteria
function create_filter(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Fridge"); // DECLARE THE SOURCE PAGE
var range = sheet1.getRange("A5:J"); // DECLARE THE RANGE TO BE FILTERED LATER
var filter = range.createFilter();
var Filter_Criteria1 = SpreadsheetApp.newFilterCriteria().withCriteria(true); // HERE IS THE PROBLEM, THE ORIGINAL CODE SAYS "newFilterCriteria().whenNumberGreaterThan(1000);" BUT INSTEAD OF A NUMBER, I NEED A FILTER BASED ON CHECKBOXES BEING EITHER TRUE OR FALSE
var add_filter1 = filter.setColumnFilterCriteria(1,Filter_Criteria1);
Logger.log("Filter has been added.");
var range = sheet1.getDataRange();
var new_sheet = ss.insertSheet(); // CREATE THE DESTINATION TAB
new_sheet.setName("TEST"); // NAME THE DESTINATION TAB AS "TEST"
range.copyTo(new_sheet.getRange(1,1));
filter.remove();
}
Any suggestions or help? Thank you! I tried looking around but havent get to find the right way to filter with the checkboxes.
Something else: Not sure if I can avoid an iteration since there are many rows to copy and it would be a slow process I think, is there a way to say something like a query such as "select all rows where column 1 is true"?
The image is just an example of the table.
Thanks!
Move Checked
function myfunk() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
const vs = sh.getRange(2, 1, sh.getLastRow() - 1, sh.getLastColumn()).getValues();
let a = [];
let d = 0;
vs.forEach((r, i) => {
if (r[0] == true) {
a.push(r)
sh.deleteRow(i + 2 - d++);
}
});
if (a) {
ss.insertSheet('Test').getRange(1, 1, a.length, a[0].length).setValues(a);
}
}
Use whenTextEqualTo true, for filtering in checkboxes:
const Filter_Criteria1 = SpreadsheetApp.newFilterCriteria().whenTextEqualTo('TRUE').build()
I am trying to build a custom array with Google sheet data by getting certain columns in a certain order. The columns/order is set on a google sheet. The below works but I would like to make the return on row 11 more dynamic.
function buildArray() {
const s = SpreadsheetApp;
const ss = s.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Test Sheet');
const pasteSheet = ss.getSheetByName('Paste');
const data = sheet.getRange(1,1,10,10).getValues(); //update range
// const headers = pasteSheet.getRange(1,1,pasteSheet.getLastRow(),1).getValues().map(function(r){return r}).flat(Infinity); //list of headers needed in 1d array
const colNeed = [0,9,5,6,4,7]; //array index for column numbers
var customArray = data.map(function(r){
return [r[0], r[9], r[5], r[6], r[4], r[7]]; //Would like to make this more dynamic
})
debugger;
pasteSheet.getRange(1, 2, pasteSheet.getLastRow(), pasteSheet.getLastColumn()).clear();
pasteSheet.getRange(1, 2, customArray.length, customArray[0].length).setValues(customArray);
debugger;
}
I have tried replacing the r[0] with r[colNeed.map(...)] and also a for loop with no success.
Any ideas on how to make this work.
Here is a screenshot of the final sheet.
I just copied/pasted the header names in the first column(A) to make sure the right columns were pulled/pasted.
Try this one using a loop to combine the data first then return. Also added the headers on top of customArray.
Code:
function buildArray() {
const s = SpreadsheetApp;
const ss = s.getActiveSpreadsheet();
const sheet = ss.getSheetByName('Test Sheet');
const pasteSheet = ss.getSheetByName('Paste');
const data = sheet.getRange(1,1,10,10).getValues(); // update range
// get headers as single array (excluding blank cells)
// since last column of data can go beyond last row of column A
// headers can include blank cells if there is already data present
const headers = pasteSheet.getRange(1,1,pasteSheet.getLastRow(),1).getValues().flat().filter(Boolean);
// array index for column numbers
const colNeed = [0,9,5,6,4,7];
var customArray = data.map(function(r){
var output = [];
colNeed.forEach(function (col){
output.push(r[col]);
});
return output;
});
// Add headers at the first element of customArray
customArray.unshift(headers)
debugger;
pasteSheet.getRange(1, 2, pasteSheet.getLastRow(), pasteSheet.getLastColumn()).clear();
pasteSheet.getRange(1, 2, customArray.length, customArray[0].length).setValues(customArray);
debugger;
}
Paste:
Test Sheet:
Paste Sheet after executing buildArray:
Have the above data in single cell of google sheet sheet1. Need to bring it to individual col's in sheet2.
categories: ScreenGuard item_meta: {'Brand': 'Lenovo', 'Series': 'Z', 'Model': '7r883', 'Length (mm)': '134', 'Width (mm)': '132', 'Total Area (sq mm)': '17688', '_measurement_data': '{"length":"{\\"value\\":\\"134\\",\\"unit\\":\\"mm\\"}","width":"{\\"value\\":\\"132\\",\\"unit\\":\\"mm\\"}","_measurement_needed":"17688","_measurement_needed_unit":"sq mm"}'} line_subtotal: 176.88 line_subtotal_tax: 0.00 line_tax: 0.00 line_total: 176.88 name: Screen Guard product_id: 10 quantity: 1 sku: tags: tax_class: type: simple unit_price: 176.88 variation_id: 0
this can repeat in the same cell ref the sheet for more examples
https://docs.google.com/spreadsheets/d/1NTqAi361vmaVQhgjWhs0y7oEZcb7K09W9unEE12nOkI/edit?usp=sharing
need Brand,Series,Model,Length, Width values in next sheet. Can this be achieved using formulas?
Building on the answer given by Timmer, I've built a function to split the values and post them into different columns in the second sheet.
Here you go:
function split_values(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName("Original_Data"); //Your original Sheet Name
var sheet2 = ss.getSheetByName("Product_Measurement"); //Your modified Sheet Name
var cellRange = sheet.getDataRange();
var cellValues = sheet.getDataRange().getValues(); //All values from original sheet.
var arrayItems = [];
var array_to_print = [];
cellValues.forEach(function(row, index) {
//Uncomment the below line if in sheet 1 we have header row that needs to be ignored.
//if (index !== 0) {
var cell = sheet.getRange(index+1, 2)
if(cell.getValue() != "Success"){ //Check if we have already parsed this row
cell.setValue("Success") //If not, parse it and set status as Success.
var split_item = row[0].split(/item_meta: /g);
for(var i=1;i<split_item.length;i++){
var item = split_item[i].split(/, 'Total Area/)[0].split(/, 'Total Area/)[0].replace(/'/g,'"')+ '}';
item = JSON.parse(item);
arrayItems.push(item); //Add all the split prdoducts to an Array.
//} Uncomment for header.
}}
});
//Add only required details to the array that needs to be put in different columns.
for (var i = 0; i < arrayItems.length ; i++) {
array_to_print.push([arrayItems[i].Brand,arrayItems[i].Series,arrayItems[i].Model,arrayItems[i]['Length (mm)'],arrayItems[i]['Width (mm)'],"Success"])
}
//Print the array in the Modified sheet.
if(array_to_print.length>0){
sheet2.getRange(sheet2.getLastRow()+1, 1,array_to_print.length,6).setValues(array_to_print);
}
}
In the sheet, I've also added some menu options and created a third sheet to shift the success items. You can run the functions from the menu item "Google Script Functions".
Hope this helps you!
Something like this as a first step?
function vanDikHoutZaagtMenPlanken(){
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getSheetByName("sheet1");
var cellValue = sheet.getRange("A3").getValue();
var arrayItems = [];
var hlpItems = cellValue.split(/item_meta: /g);
for(var i=1;i<hlpItems.length;i++){
var item = hlpItems[i].split(/, 'Total Area/)[0].split(/, 'Total Area/)[0].replace(/'/g,'"')+ '}';
item = JSON.parse(item);
arrayItems.push(item);
}
//Edit -> Looping through the result to get every value needed
for (var i = 0; i < arrayItems.length ; i++) {
Logger.log(arrayItems[i])
Logger.log(arrayItems[i].Brand)
Logger.log(arrayItems[i].Series)
Logger.log(arrayItems[i].Model)
Logger.log(arrayItems[i]['Length (mm)'])
Logger.log(arrayItems[i]['Width (mm)'])
Logger.log("================================")
// This is an example on how to set a value to the sheet2
ss.getSheetByName("sheet2").getRange('B5').setValue(arrayItems[i].Brand);
}
}
Check the following links to see how to use:
getRange(a1Notation): To get the cells you need to work with.
getLastRow(): Returns the position of the last row that has content.
setValue(value): To set a value to a cell.
I have poked around and found the following code that will advance to the last line on data in our Google Spreadsheet- at least until we add more lines beyond row 297.
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getSheets()[0].getRange("B297");
SpreadsheetApp.setActiveRange(range);
}
I am trying to figure out how to write this script so that it will go to the last line of data, regardless of the line number.
Is there a change that I can make to this code to accomplish this?
The method getLastRow() tells you the last row of a sheet that has data. This can be used to move the selection to that row. Another thing I changed in the sheet selection: your script always operates on the first sheet; it makes more sense to operate on whichever sheet is active currently.
function myFunction() {
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(sheet.getLastRow(), 1);
SpreadsheetApp.setActiveRange(range);
}
This can be placed into the spreadsheet menu using onOpen.
By the way, pressing Ctrl + ArrowDown does the same thing, if you do it in a column that has some data in every row (like the date or Id column).
The script below allows you to go to the last cell with the content of column A. It works even if some cells in the column A contain formulas.
Modifying the number in parentheses in lastRowOfCol(1) allows you to reach the last cell with content from another column.
Additionally, you can also change the focus to the first empty cell after the last one with content.
function onOpen(){
lastRowOfCol(1); //Enter the column number you want to use as the base of the search
}
function lastRowOfCol(column){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var total = sheet.getMaxRows();
var values = SpreadsheetApp.getActiveSheet().getRange(1,column,total).getValues();
for(var i=total-1;values[i]=="" && i>0; i--){}
var last = sheet.getRange(i+1,column);
//var last = sheet.getRange(i+1,1); //Option to fetch the last row of a given column, but to position in column 1
//var last = sheet.getRange(i+2,column); //Option to go to the cell below the last one with content
sheet.setActiveSelection(last);
}
Script from Marcelo Camargo in this forum
The currently relevant option that works on all non-hidden sheets, and not just on the active one:
function onOpen() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheets = ss.getSheets()
const properties = PropertiesService.getDocumentProperties()
const lastActiveSheetName = properties.getProperty("lastActiveSheetName")
let lastActiveSheet
for (let sheet of sheets) {
if (!sheet.isSheetHidden()) {
const sheetName = sheet.getName()
const lastEdit = properties.getProperty(sheetName)
if (lastEdit) {
if (sheetName !== lastActiveSheetName){
sheet.getLastRow() // Without this magic does not work - I could not figure out the reasons
sheet.getLastColumn() // Without this magic does not work - I could not figure out the reasons
const [lastRow, lastCol] = lastEdit.split(',')
sheet.getRange(Number(lastRow), Number(lastCol)).activate() // With focus set to this cell
//sheet.setActiveSelection(sheet.getRange(Number(lastRow), Number(lastCol))) // Without setting focus to this cell
}
else {
lastActiveSheet = sheet
}
}
}
}
if(lastActiveSheet){
lastActiveSheet.getLastRow()
lastActiveSheet.getLastColumn()
const [lastRow, lastCol] = properties.getProperty(lastActiveSheetName).split(',')
lastActiveSheet.getRange(Number(lastRow), Number(lastCol)).activate()
}
}
function onEdit() {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const sheet = ss.getActiveSheet()
if (!sheet.isSheetHidden()) {
const cell = ss.getActiveCell()
const row = cell.getRow()
const column = cell.getColumn()
if (row !== 1 || column !== 1) { // Protection from the evil magic of "self-editing" the first cell
const sheetName = sheet.getName()
PropertiesService.getDocumentProperties().setProperty(sheetName, `${row},${column}`)
PropertiesService.getDocumentProperties().setProperty("lastActiveSheetName", sheetName)
}
}
}
PS: Please note that in the code I do not use a semicolon separator - it's more convenient for me.