Values from Ranges by named ranges to variables - google-apps-script

I have many named ranges in Spreadsheet.
I need get values from areas by current row (e) and current column by namedranges and write it to variables. I write a lot of the same script
function sendEmailClerck(e){
var sheet = SpreadsheetApp.getActive().getSheetByName('Ответы на форму (1)');
var idRow = e.range.getRow();
var name = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqUser').getColumn()).getValue();
var cli = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqCLI').getColumn()).getValue();
var priority = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqPriority').getColumn()).getValue();
var date = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqDateStart').getColumn()).getValue();
var date2 = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqDateCloseU').getColumn()).getValue();
var tip = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqType').getColumn()).getValue();
var users = sheet.getRange(idRow, SpreadsheetApp.getActiveSpreadsheet().getRangeByName('ReqAddress').getColumn()).getValue();
I found one script in this site but I can't understand how can I use it here
function getRangeName(A1Notation) {
var rangeName = "";
//get all the name ranges of the sheet
var namedRanges = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getNamedRanges();
// loop on all the names range of the sheet
for(i=0;i<namedRanges.length;i++){
//if it's the same A1 Notation
if(namedRanges[i].getRange().getA1Notation() == A1Notation)
rangeName = namedRanges[i].getName();
}
//will return the name of the range or "" if there is no range
return rangeName;
}
I think that's it I need. I think I can write to variables the values by put the value in parameter and send it to one function and return it back. Can you help me this this?
Thank you for your help!

Try Array.map() to make this a bit more manageable, like this:
function sendEmailClerck(e) {
const sheet = SpreadsheetApp.getActive().getSheetByName('Ответы на форму (1)');
const rangeNames = [
'ReqUser',
'ReqCLI',
'ReqPriority',
'ReqDateStart',
'ReqDateCloseU',
'ReqType',
'ReqAddress',
];
const [name, cli, priority, date, date2, tip, users] = rangeNames.map(rangeName => {
const column = sheet.getRange(rangeName).getColumn();
return sheet.getRange(e.range.rowStart, column).getValue();
});
}
You may want to rethink the whole approach though. The code is very inefficient because it reads every cell one by one. You should probably use just one sheet.getDataRange().getValues() call and parse the data from the the 2d array it returns.
Some of the best resources for learning Google Apps Script include the Beginner's Guide, the New Apps Script Editor guide, the Fundamentals of Apps Script with Google Sheets codelab, the Extending Google Sheets page, javascript.info, Mozilla Developer Network and Apps Script at Stack Overflow.

Related

Copy Paste into formula as apps script

I'm trying to run a google apps script which takes a series of importrange functions and puts them into an arrayformula query. I've successfully created a cell which actively accumulates the correct links for use in the importrange and puts it into a cell as a string. All I need the script to do is to copy that string and paste it as a formula in another cell. I can do this manually pretty easily, but I'd like to be able to set it up on a timer so it does it automatically on a certain time period.
As far as I've gotten is below and it doesn't work at all:
function Update Import Ranges() {
var spreadsheet = SpreadsheetApp.getActive();
var source = spreadsheet.getRange('B2').activate();
spreadsheet.getCurrentCell('B3').setFormula(???);
spreadsheet.getRange('B3').activate();
};
accumulates the correct links for use in the importrange and puts it into a cell as a string
The importrange() function only accepts two parameters: one for the spreadsheet to read from, and another to specify which range in the spreadsheet to return. To read from several spreadsheets and/or ranges with importrange(), you will have to create several formulas.
Alternatively, use an Apps Script function that mimics importrange() but supports multiple spreadsheets and ranges, such as the ImportMultipleRanges() function. You could call it like this:
function updateDataFromOtherSpreadsheets() {
var rangeToUpdate = "All Data!A2";
var sourceSpreadsheetKeysRange = "Config!B2:B5";
var sourceSpreadsheetDataRange = "Config!C2:C5";
var add_spreadsheet_name_prefix = false;
var add_sheet_name_prefix = false;
var ignore_blank_rows = true;
var ss = SpreadsheetApp.getActive();
var spreadsheet_keys = ss.getRange(sourceSpreadsheetKeysRange).getValues();
var range_strings = ss.getRange(sourceSpreadsheetDataRange).getValues();
var data = ImportMultipleRanges(spreadsheet_keys, range_strings, add_spreadsheet_name_prefix, add_sheet_name_prefix, ignore_blank_rows);
ss.getRange(rangeToUpdate).offset(0, 0, data.length, data[0].length).setValues(data);
}
To answer your question, you can fix the syntax errors and semantics in your function like this:
function updateImportrangeFormula() {
const sheet = SpreadsheetApp.getActiveSheet();
const ssId = sheet.getRange('B2').getValue();
const rangeA1 = sheet.getRange('C2').getValue();
const formula = '=importrange("' + ssId + '", "' + rangeA1 + '")';
sheet.getRange('B3').setFormula(formula);
}

How to Put Formula Count another sheet in App Script

my First ASK and last at 2020.
Im Newbie with google App Script, need some help
I had 2 Spreadsheet
Spreadsheet ssGETDATA with SHEET1 column(id,name,address,ts,visit)
Spreadsheet ssVERIFY with SHEET1 column (id,ts)
I send data from Android use this code :
function doGet(e) {
return message("Error: Please Try Again");
}
function doPost(e) {
var id= e.parameters.id[0];
var name= e.parameters.name[0];
var address= e.parameters.address[0];
var visit= e.parameters.visit[0];
var ts = Utilities.formatDate(new Date(), "GMT+8", "dd/MM/yyyy HH:mm:ss");
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheets()[0];
sh.appendRow([id,name,address,ts,visit]);
return message("Data Saved");
} else {
return message("Error: Please Try Again");
}}}
function message(msg) {
return ContentService.createTextOutput(msg);
}
I want to Verify data from ssGETDATA but data (id) appeared several times.
so my idea every time append row executed it put formula in column (visit) with =count(id,ssVERIFYSheet1!id) to check it Verified or Not
how it applies in the google app script?
i hope when ssVERIFY changed then ssGETDATA column (visit) counting too.
thanks for your explanation. Happy new Year
The simplest way to check if a column has a value probably is using getValues(), and search for the row in the array:
const range = sheet.getRange('A2:A')
const hasBeenValidated = range.getValues()
.flat()
.some(value => value === id)
if (hasBeenValidated) {
// [...]
}
Notice that I assumed that id is on column A and that it has a header.
flat() is necessary because getValues() returns a 2D array (array of rows) and we only need an array of values.
With this snippet you can check for existing entries at ssGETDATA and/or ssVERIFY before making any changes. It should work for any column but you may need to change the value === id part depending on the type of it (dates, for example).
References
Range getValues() (Google Developers)
Array.prototype.flat() (MDN)
Array.prototype.some() (MDN)
SpreadsheetApp openByUrl(url) (Google Developers)

Google Sheets script help moving data between sheets

I am loading a list into a google sheet tab SheetA then amending the data cell by cell into the same google sheet in a different tab SheetB with some manipulation as it goes over.
But the only way I know how to do it is activate the sheet each time and its really slow. Is there a way to move the data without having to physically activate the sheet. So for eaxmple grap the value of cell A1 from SheetA without ever deactivating SheetB?
Here is a sample of the section of code where you can see it activating the sheets back and forth. I used to do a similar function in Excel but in Excel I didn't have to activate the sheets and I could turn off the visual during runtime which made the whole transfer quite fast.
Can you do the same in google sheets? If so what is the syntax?
while (SpreadsheetApp.getActiveSheet().getRange('A'+ COUNTERSheetA).getValue() != ""){
VALUEA = SpreadsheetApp.getActiveSheet().getRange('A'+ COUNTERSheetA).getValue()
VALUEB = SpreadsheetApp.getActiveSheet().getRange('B'+ COUNTERA).getValue()
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('SheetA'), true);
spreadsheet.getRange('A'+COUNTERSheetB).activate();
spreadsheet.getCurrentCell().setValue(VALUEA);
spreadsheet.getRange('B'+COUNTERSheetB).activate();
spreadsheet.getCurrentCell().setValue(VALUEB);
COUNTERSheetB = COUNTERSheetB + 1
COUNTERSheetA = COUNTERSheetA + 1
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('SheetA'), true);
}
function myfunc() {
const ss=SpreadsheetApp.getActive();
const shA=ss.getSheetByName('SheetA');//gets SheetA by name
const rgA=shA.getDataRange();//gets all of the data in the sheet
var vA=rgA.getValues();//gets all the data at one time as one two dimensional array of data
vA.forEach(function(r,i){
r.forEach(function(c,j){
vA[i][j]=(WhateverYouWanttoDoToEachCell);
});
});
const shB=ss.getSheetByName('SheetB');//gets SheetB by name
const rgB=shB.getRange(1,1,vA.length,vA[0].length).setValues(vA);//1,1 is A1 but you could choose the upper left corner to be anywhere. Loads all of the data at one time.
//If you're going to be doing something with those spreadsheet values immediately you may wish to employ SpreadsheetApp.flush() to guarantee that all of the values have been loaded into the spreadsheet.
SpreadsheetApp.flush();
}
Array.forEach() method
Spreadsheet Reference
You sure can. You can simply declare each sheet as a variable, then use the sheet class to make the calls. Example below.
Take into account that each time you use the getRange() method it's taxing on the runtime.
A better way to do this would be to take all values at once into a 2D array, then iterate over the array, converting into a new 2D array, then write that 2D array to the other sheet.
function myFunction() {
let COUNTERSheetA = 1;
let COUNTERSheetB = 1;
let VALUEA;
let VALUEB;
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheetA = spreadsheet.getSheetByName('SheetA');
const sheetB = spreadsheet.getSheetByName('SheetB');
while (sheetA.getRange('A'+ COUNTERSheetA).getValue() != ""){
VALUEA = sheetA.getRange('A'+ COUNTERSheetA).getValue()
VALUEB = sheetA.getRange('B'+ COUNTERSheetA).getValue()
sheetB.getRange('A'+COUNTERSheetB).setValue(VALUEA);
sheetB.getRange('B'+COUNTERSheetB).setValue(VALUEB);
COUNTERSheetB = COUNTERSheetB + 1
COUNTERSheetA = COUNTERSheetA + 1
}
}
Here is the actual sheet in case you want to play with it:
https://docs.google.com/spreadsheets/d/1Gev2KxpX5mPik92Io3eOeF3nKngVcKxnWiNktlHxdDI/edit?usp=sharing
Here is an example of pulling all values, iterating over them, then inserting them into the new sheet. If you can figure out the logic you need here, this is by far the fastest method.
function myFunction() {
let VALUES;
const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const sheetA = spreadsheet.getSheetByName('SheetA');
const sheetB = spreadsheet.getSheetByName('SheetB');
VALUES = sheetA.getRange(1, 1,sheetA.getLastRow(), 2).getValues();
for (let row of VALUES){
for (let val of row){
//Do your manipulations here if you can.
Logger.log(val);
}
}
sheetB.getRange(1, 1,sheetA.getLastRow(), 2).setValues(VALUES);
}
Here is the sheet for the above code:
https://docs.google.com/spreadsheets/d/1Gev2KxpX5mPik92Io3eOeF3nKngVcKxnWiNktlHxdDI/edit?usp=sharing

Google Sheets filter values by value type

I am looking for help to create a filter on Google Sheets Script.
I want the following:
I have a database Schedule which has table with information that I want to filter
Once the database A is updated I want to filter Colum b row 8 and only take the cells that have information and are filled with words, numbers, etc.
After that I want to copy the data filtered and paste on a new Sheet Data “Foreman on specific columns
Also, I want to copy and paste the format such as color, size, etc.
I have the following code which it does the partial job but I cannot figure it out to only get the specific data needed
function Foreman(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var scheduleCCC_sheet = ss.getSheetByName("Schedule");
var Foreman_sheet = ss.getSheetByName("Foreman");
var pasteforemans = Foreman_sheet.getRange(8,2);
var originalData = scheduleCCC_sheet.getRange(9,2,scheduleCCC_sheet.getLastRow()1,11).getValues();
var filter1 ="";
Foreman_sheet.getRange(8,2,Foreman_sheet.getLastRow(),11).clearContent().clearFormat();
var data = originalData.filter(filterlogic);
Foreman_sheet.getRange(9,2,data.length,data[0].length).setValues(data);
}
var filterlogic = function(item){
if(item[1] == ""){
return false;
}else {
return true;
}
In order to filter the values based on the condition that the cells are not empty, you can use the below snippet of code:
Snippet
function myFunction() {
var ss = SpreadsheetApp.openById("ID_OF_THE_SS").getSheetByName("Schedule CCC");
var otherss = SpreadsheetApp.openById("ID_OF_THE_SS").getSheetByName("Foreman");
var range = ss.getRange("START_ROW", "START_COL", ss.getLastRow(), ss.getLastColumn());
var filter = range.getFilter();
var filterCriteria = SpreadsheetApp.newFilterCriteria().whenCellNotEmpty().build();
filter.setColumnFilterCriteria("COL_POSITION", filterCriteria);
for (var i = 1; i <= ss.getLastRow(); i++) {
if (ss.isRowHiddenByFilter(i) == false) {
ss.getRange("RANGE_FROM_THE_CCC_SHEET").copyTo(otherss.getRange("RANGE_FROM_THE_FOREMAN_SHEET"));
}
}
}
Explanation
The above code gathers the filter from the source sheet and sets it the whenCellNotEmpty criteria. Afterwards it loops through the data and checks if a specific row is hidden by the filter; if the result of this is false, then it copies the row with its format onto the destination sheet. The format of the row is preserved by using the copyTo method.
Note
You will need to adjust the ranges to match the ones in your sheet and might need to add another condition when looping through the data from the source sheet.
Reference
Apps Script Sheet Class - isRowHiddenByFilter(rowPosition);
Apps Script Filet Class - setColumnFilterCriteria(columnPosition, filterCriteria);
Apps Script Sheet Class - copyTo(spreadsheet).

Update/edit google sheets row values from html input

I have an html form where the client's data is inserted in and it appends row with the values on to a google sheet.
In the form, there's a field that searches and returns the clients data when searching for a specific value (id number).
function getID(IDsearch){
var ws = SpreadsheetApp.getActiveSheet();
var data = ws.getRange(3, 1, ws.getLastRow(), 36).getValues();
var dataInput = data.map(function(r){return r[7];});
var position = dataInput.indexOf(IDsearch);
var dataArray = ws.getRange(position+3, 1, 1, 36).getValues();
if(position > -1){
return dataArray;
} else {
return position;
}
}
After this runs, all the input fields in the form are populated with the data from that row.
I need to edit the values in the form and when submit it should overwrite/update the existing row with that id number.
In google sheets documentation, I've found the spreadsheets.values.update method, but I cannot figure this out. I'm pretty new in this and any help would be appreciated.
Thanks everyone!
You want to achieve the following flow.
Input "ID" to id="insertID" and click "Search by ID".
Show the values from Spreadsheet by searching "ID".
Edit the values of id="name" and id="ID".
When "Save data" is clicked, you want to update the values on the Spreadsheet.
From your replying, shared Spreadsheet and script, I could understand like above. If my understanding is correct, how about ths following modification? Please think of this as just one of several possible answers.
Modification points:
In your case, processForm at Google Apps Script side is required to be modified.
Search the row using formObject and overwrite the values of cells.
Modified script:
When your script is modified, please modify processForm at Google Apps Script side as follows. I remove the Spreadsheet ID from the URL. So please set it, before you test the script.
function processForm(formObject) {
var url = "https://docs.google.com/spreadsheets/d/###/edit#gid=0";
var ss = SpreadsheetApp.openByUrl(url);
var ws = ss.getSheetByName("Database");
// I added and modified below script.
var ranges = ws.getRange(4, 2, ws.getLastRow() - 3, 1).createTextFinder(formObject.ID).findAll();
if (ranges.length > 0) {
for (var i = 0; i < ranges.length; i++) {
ranges[i].offset(0, -1, 1, 2).setValues([[formObject.name, formObject.ID]]);
}
} else {
ws.appendRow([formObject.name, formObject.ID]);
}
}
In this modification, when the same IDs are existing, all rows of the same IDs are overwritten. For example, if you want to modify the 1st one, please modify to ranges[0].offset(0, -1, 1, 2).setValues([[formObject.name, formObject.ID]]);.
Reference:
Class TextFinder
Try this:
function getID(IDsearch){
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();//dont know what the sheet is
var rg=sh.getRange(3,1,sh.getLastRow()-2,36);
var data=rg.getValues();
var idA=sh.getRange(3,8,sh.getLastRow()-2,1).getValues().map(function(r){return r[0];});//it looked like column 8 was your id column
var idx=idA.indexOf(IDsearch);
if(idx>-1) {
return ws.getRange(pos + 3,1,1,36).getValues()[0];//flattened the row to a 1d array
}else{
return idx;
}
}
#dianadfonseca, as #Tanaike points out, without more detail about your data structure, people will be speculating in order to answer your question. As I will be...
Please read the following answer, and tailor it to your needs if it works for you.
Example:
function getRow(id){
var ws = SpreadsheetApp.getActiveSheet();
// Number of headers to skip
var numHeaders = 2;
// the starting row
var startRow = numHeaders + 1;
// The column where the IDs are is known
var idCol = 8;
// The number of rows with data not headers
var numRows = ws.getDataRange().getLastRow() - numHeaders;
// An array with the ids to find a match in
// getRange() returns a 2D array, so you can transpose it to flatten it
var ids = ws.getRange(startRow,idCol,numRows).getValues();
ids = transpose(ids)[0];
// Get the index where id matches in ids
var row = ids.indexOf(id);
// If there's a match
if(row > -1){
// Correct row indexing
row = row + startRow;
}
return row;
}
function updateRow(row,data){
var ws = SpreadsheetApp.getActiveSheet();
// The column for each property is known
var propertyOneCol = 1;
// Update property using setValue()
ws.getRange(row,propertyOneCol).setValue(data.propertyOne);
// And so on...
}
// Transpose to avoid looping through the array
function transpose(a)
{
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
You can take a look the spreadsheet used for this example here with its bound script to play around.
Here is the function I used for testing
function test(){
// You are receiving this from your form
var data = {"propertyOne":"Juan","propertyTwo":20, "id":123467};
var id = data.id;
updateRow(getRow(id),data);
}