Lookup cell reference of given value - google-apps-script

I have a spreadsheet with hundreds of rows and Column A is a unique record number.
I would like to learn to be able to find cell reference based on the inputted unique record number.
For example if in Call A1, I enter value 11, ho can I retrieve cell row (eg: 17) using google script.
Thank you for help
Taizoon

You can build a simple and small Ui that does a "search" in your first column and activates the found cell (and the whole row). An example is shown below, You have an option to use it repeatedly (like it is now) or just once by changing one line of code, see comment at the end of the handler function. :
function showInSheet() {
var app = UiApp.createApplication().setTitle('Search and Select').setWidth(250).setHeight(60);
var panel = app.createVerticalPanel();
var searchHandler = app.createServerHandler('searchRow').addCallbackElement(panel);
var Hpanel = app.createHorizontalPanel();
var search = app.createTextBox().setName('search').setId('search').setWidth('70').addKeyUpHandler(searchHandler);
var warning = app.createHTML('incomplete or invalid entry').setId('warning').setStyleAttributes({'padding-left':'10px','background':'yellow','fontSize':'8pt'}).setVisible(false);
app.add(panel.add(Hpanel.add(search).add(warning)));
SpreadsheetApp.getActive().show(app);
}
function searchRow(e){
var app = UiApp.getActiveApplication();
var item = e.parameter.search;
var sh = SpreadsheetApp.getActiveSheet();
var data = sh.getRange(1,1,sh.getLastRow(),1).getValues().join().split(',');// the 2D array is "flattened" and splitted to get a 1D array
Logger.log(data.length);
var idx = data.indexOf(item);// in a "simple" array we can use this array function more easily to seach in it ;-)
Logger.log(idx);
if(idx>data.length || idx==-1){app.getElementById('warning').setVisible(true) ; return app};
idx++;// increment because rows count from 1 instead of 0 in arrays
var itemRange = sh.getRange(idx,1,1,sh.getMaxColumns());
sh.setActiveSelection(itemRange);
// return app.close();// can be replace by next line (uncommented)
app.getElementById('search').setText('');app.getElementById('warning').setVisible(false);return app;
}

Related

How to separate column into two separate columns by condition App Script

I am trying to take the Data in the scan it columns and conditionally filter it into the commercial or manufacturing sheet.
I tried writing a formula as an if function basically saying if it equals "Company" put it in manufacturing column, if not(if the rest) then put into commercial column.
I tried coding it backend in app script, but had an issue grabbing the last row from scan it and correctly adding the item #, vendor, and quantity into the last row of either Commercial or Manufactured.
The scan it section is an importrange function so more data will be entered into it once the code is working correctly.
I ran into dead ends with both. This is obviously an advanced code and I only did a little bit of coding in college. Below is a script that I had been messing with trying to get it to filter the data properly, but I couldn't get it to run. Any help would be appreciated!
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1')
//Get last rows for MFG
var mfgvalues = sheet.getRange(3, 5, sheet.getLastRow()).getValues();
//var mfglast = mfgvalues.filter(String).length;
//Get last rows for Comm
var commvalues = sheet.getRange(3, 1, sheet.getLastRow()).getValues();
//var commlast = commvalues.filter(String).length;
//Get last rows for Scann
var scanvalues = sheet.getRange(2, 12, sheet.getLastRow()).getValues();
//var scanlast = scanvalues.filter(String).length;
//Filter Accordingly
if (scanvalues == "IMMCO") {
var scanrange = sheet.getRange("L2:N").getLastRow().getValues();
//var scanlastrow = scanrange.getLastRow().getValues();
var mfgrow = sheet.getRange("E3:G").getLastRow();
scanlastrow.copyTo(mfgrow)
} else {
var scanrange = sheet.getRange("L:N").getLastRow.getValues();
//var scanlastrow = scanrange.getLastRow().getValues();
var commrow = sheets.getRange("A3:C").getLastrow()
scanlastrow.copyTo(commrow)
}
}
https://docs.google.com/spreadsheets/d/1D0FvVoTADi3t3ENPceB14QYYI4lNI6C3xj2OF-St7Is/edit?usp=sharing
GOOGLE SHEET OUTPUT WANTED
Option1:
Using FILTER() to filter your data set if vendor name is equal to "COMPANY" as mentioned in your description
Formula in Cell A3:
=filter(L3:N,LEN(L3:L)>0,UPPER(M3:M)<>"COMPANY")
Formula in Cell E3:
=filter(L3:N,LEN(L3:L)>0,UPPER(M3:M)="COMPANY")
Output:
Option2:
Using apps script to filter your data set.
Sample Code:
function filter(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
//Get item count for Scann
var scanCnt = sheet.getRange('L3:L').getValues().flat().filter(String).length;
Logger.log(scanCnt);
//Get last rows for Comm
var commLastRow = sheet.getRange('A1:A').getValues().flat().filter(String).length;
Logger.log(commLastRow);
//Get last rows for MFG
var mfgLastRow = sheet.getRange('E1:E').getValues().flat().filter(String).length;
Logger.log(mfgLastRow);
//Get Scann data if item count is not zero
if(scanCnt){
var commItem = [];
var mfgItem = [];
var dataRange = sheet.getRange(3,12,scanCnt,3);
var data = dataRange.getDisplayValues();
//Loop all scann data and separate mfg with comm
Logger.log(data.length)
data.forEach(item => {
Logger.log(item);
if(item[1].toUpperCase() == "COMPANY"){
mfgItem.push(item);
}else{
commItem.push(item);
}
});
Logger.log(mfgItem);
Logger.log(commItem);
//Append comm items
sheet.getRange(commLastRow+1,1,commItem.length,commItem[0].length).setValues(commItem);
//Append mfg items
sheet.getRange(mfgLastRow+1,5,mfgItem.length,mfgItem[0].length).setValues(mfgItem);
//Optional: Clear content of scann column
dataRange.clearContent();
}
}
What it does?
Get the item count to filter in Scan it column by selecting the range L3:L. Get its value. Change 2-d array to 1-d array using array.flat(). Use array.filter() to remove empty values. Then get its length
Get the last row of Commercial(ColumnA) and Manufactured(ColumnE) column.
If item count obtained in step1 is not zero. Then get the data range and its value
Loop all data value (by row) one-by-one. Check if vendor index is equal to "COMPANY" then add it to mfgItem array. Else, add it to commItem array
Append mfgItem and commItem under Manufactured Column and Commercial Column
(Optional) Clear the data under Scan-it Column
Note:
You can check the execution log to further understand the procedure done. I included some debug logs in the sample code.
Output:

Automatically add variables to array?

In a google script I have written something to check my monthly expenses, which are listed in a google sheet.
Based on words the script finds, every line gets a category tag. It works fine, but the number of words to search for is getting big. And the array is getting big too.
I have listed 6 pairs (words to find, tag to add) - but in real version I have as many as 35. How can I create the pairs, and load everything automatically in the array?
This is my script:
function myFunction() {
// check usual suspects
var A1 = ["CAFE", "HORECA"]
var A2 = ["ALBERT", "AH"]
var A3 = ["VOMAR","Vomar"]
var A4 = ["HEMA","HEMA"]
var A5 = ["KRUID","Drogist"]
var A6 = ["RESTA", "Horeca"]
// in Array
var expenses = [A1,A2,A3,A4,A5,A6]
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues(); // read all data in the sheet
for (i in expenses)
{for(n=0;n<data.length;++n){ // iterate row by row and examine data in column A
if(data[n][3].toString().toUpperCase().match(expenses[i][0])==expenses[i][0]){ data[n][4] = expenses[i][1]};
// if column D contains 'xyz' then set value in index [5] (is column E)
}
Logger.log(data)
ss.getRange(1,1,data.length,data[0].length).setValues(data); // write back to the sheet
}
}
I can propose you that:
function multiPass(){
var searchCriterions = [
["CAFE","HORECA" ],
["ALBERT", "AH"],
["VOMAR","Vomar"],
["HEMA","HEMA"]
];
var dico = {};
var patt = "";
for (var i in searchCriterions) {
dico[searchCriterions[i][0]] = searchCriterions[i][1];
patt += "("+searchCriterions[i][0]+")";
if((Number(i)+1)<searchCriterions.length){
patt += "|";
}
}
var re = new RegExp(patt,"");
var ss = SpreadsheetApp.getActiveSheet();
var data = ss.getDataRange().getValues(); // read all data in the sheet
Logger.log(re);
for(n=0;n<data.length;++n){ // iterate row by row and examine data in column A
// THAT'S NOT COLUMN "A", 3 --> "D"
var test = data[n][3].toString().toUpperCase().match(re);
Logger.log(test);
if(test!==null){
data[n][4] = dico[test[0]]
};
}
ss.getRange(1,1,data.length,data[0].length).setValues(data); // write back to the sheet
}
instead of using variable for your "pairs" prefer to use a big table (it's less painfull to write)
then transform your pairs in object to quickly access the second argument of the pair and create a big regexp that check at once all the keywords instead of parsing them one by one.
Now as we are using a big array as search criterions we can totally imagine that this big array is loaded instead of hard coding it. If you have a sheet where the data is you can change the code this way:
var searchCriterions = SpreadsheetApp.getActive().getRange("namedRange").getValues();

Converting Sheet data to a new Sheet

I'm trying to use Google Apps Script to communicate with Google Sheets to do the following:
We're trying to convert data from one Point of Sale system to a new one. In order to do this, I need to take certain columns of a sheet, manipulate them in various ways, and repopulate another sheet with the resulting data. I need to find products without a SKU number, and assign them a new one, starting at 10110 and incrementing from there.
function sku() {
// "From" Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("New POS Data");
// "To" Spreadsheet
// Spreadsheet key: the string at the end of the URL
var ssraw = SpreadsheetApp.openById("1BH-j4cOW9Ntg6FlPNXmNCUId_pm9BgyAh0cwrwB4z_A");
var sheetraw = ssraw.getSheetByName("Old POS Data");
var max = sheet.getLastRow();
// SKU / UPC
var range = sheetraw.getRange(2,18,max);
var data = range.getValues();
// Assign new sku if no old one
var skunum=[10110];
var newData = new Array();
for (var y = 0; y <= max; y++) {
if (data[y]==""){
newData.push(skunum);
skunum++;
var skunum=[skunum];
}
else {newData.push(data[y]);}
}
sheet.getRange(2,3,max).setValues(newData);
}
This gives me the error "Incorrect range height, was 1 but should be 30 (line 26, file "SKU")"
If I remove the brackets around newData in the last line, I get "Cannot convert Array to Object[][]. (line 27, file "")"
This has been driving me mental, if anyone can offer help, I would be very grateful.
Even if you get a one row or one column vector with getData() you will get an Object[][].
when you do:
if (data[y]==""){
newData.push(skunum);
skunum++;
var skunum=[skunum];
}
You check if [cellFromColumn] == "" which will evaluate to false as it's an array.
You then push the new/old sku number to a simple array which, for spreadsheets, is one row of columns.
Instead you want to push into the array a one element array containin the sku number like this:
newData.push(skunum);
...
newData.push([data[y]]);
This will create an array of rows, each row is an array with one element (one column)

Find string and get its column

Let's say I have a lot of columns and one of them contains "impressions" string (on row 3). What I need to do is to:
1) Find the cell with "impressions" string
2) Get column number or i.e. "D"
3) Based on what I got paste a formula into i.e. D2 cell which gets AVERAGE from a range D4:D*last*
I couldn't find it anywhere so I have to ask here without any "sample" code, since I have no idea on how to achieve what I want. (3rd one is easy but I need to get that "D" first)
There's no way to search in Google Apps Script. Below is a function that will accomplish the first 2 parts for you (by iterating over every cell in row 3 and looking for "impressions"):
function findColumnNumber() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1'); // insert name of sheet here
var range = sheet.getDataRange(); // get the range representing the whole sheet
var width = range.getWidth();
// search every cell in row 3 from A3 to the last column
for (var i = 1; i <= width; i++) {
var data = range.getCell(3,i)
if (data == "impressions") {
return(i); // return the column number if we find it
}
}
return(-1); // return -1 if it doesn't exist
}
Hopefully this will allow you to accomplish what you need to do!
The indexOf method allows one to search for strings:
function findColumnNumber() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet() //whatever tab the code is run on
var data = sheet.getDataRange().getValues();
var header_row_num = 1; // TODO: change this to whichever row has the headers.
var header = data[header_row_num -1] //Remember JavaScript, like most programming languages starts counting (is indexed) at 0. For the value of header_row_num to work with a zero-index counting language like JavaScript, you need to subtract 1
//define the string you want to search for
var searchString = "impressions";
//find that string in the header and add 1 (since indexes start at zero)
var colNum = header.indexOf(searchString) + 1;
return(colNum);

Multiple results from a single column search in a spreadsheet

I just wanted to know if there was a way to pull multiple (only 2 at the most) results with the code provided below. All the code is doing is searching for a user's name in a spread sheet and then displaying the value in the cell next to that user's name. The slight issue I'm running into now is that their name might appear twice in a given column and I would like for both results to be displayed. Any help would be appreciated. The full explanation of what this code is used for can be found here if needed: VLOOKUP style app script using UiApp and textBox form to reference a spreadsheet
// function called when submit button is clicked
function submit(e) {
var app = UiApp.getActiveApplication();
Logger.log(Utilities.jsonStringify(e)); // Log the input parameter (temporary)
// Write the data in the text boxes back to the Spreadsheet
var cell = e.parameter.userName;
var doc = SpreadsheetApp.openById('SPREADSHEET-ID');
var ss = doc.getSheets()[0];
var lastRow = doc.getLastRow();
var data = ss.getRange(2, 1, 2, 4).getValues();
var result = "User not found";
for (nn = 0; nn < data.length; ++nn) {
if (data[nn][1] == cell) {
result = data[nn][1];
break
}; // if a match in column B is found, break the loop
}
// Make the status line visible and tell the user the possible actions
app.getElementById('status').setVisible(true).setText(result);
return app;
}
All you need to do is modify the behavior of the search loop. Perform the search, adding finds to an array, and get rid of the break that was terminating a search after finding one item. At the end of the search, join the array of finds into a string, and you're done.
// function called when submit button is clicked
function submit(e) {
var app = UiApp.getActiveApplication();
Logger.log(Utilities.jsonStringify(e)); // Log the input parameter (temporary)
// Write the data in the text boxes back to the Spreadsheet
var cell = e.parameter.userName;
var doc = SpreadsheetApp.openById('SPREADSHEET-ID');
var ss = doc.getSheets()[0];
var lastRow = doc.getLastRow();
var data = ss.getRange(2, 1, 2, 4).getValues();
var result = "User not found";
var result_array = [];
for (nn = 0; nn < data.length; ++nn) {
if (data[nn][1] == cell) {
result_array.push( data[nn][1] );
}; // if a match in column B is found, keep going, there may be more!
}
if (result_array.length > 0)
result = result_array.join(", "); // concatenate multiple results
// Make the status line visible and tell the user the possible actions
app.getElementById('status').setVisible(true).setText(result);
return app;
}