How to GetSheetByName using partial string in google apps script - google-apps-script

I am trying to use .getSheetByName('') to grab a sheet whose name contain a certain string like, 'V1' or 'V4', not an exact match. Say the name of the sheet is '2020 0304 V1', the first part is always changing but it contains V1, I tried .getSheetByName('*V1') but it is not working. Any hint on how to achieve this?

Issue and workaround:
Unfortunately, in the current stage, the method like the regex cannot be used with getSheetByName(). So in this case, it is required to use the workarounds.
In this answer, I would like to propose 2 patterns.
Pattern 1:
In this pattern, test is used for searching the sheet name. getSheetName() is used for retrieving the sheet name. In this case, it supposes that the pattern is like 2020 0304 V1.
Sample script:
function myFunction() {
const searchText = "V1";
const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
const regex = RegExp(`\\d{4} \\d{4} ${searchText}`);
const sheet = sheets.filter(s => regex.test(s.getSheetName()));
if (sheet.length > 0) console.log(sheet[0].getSheetName());
}
In this case, if there is only one sheet which has the sheet name of the pattern of \d{4} \d{4} V1 in your Spreadsheet, you can retrieve the sheet by sheet[0].
Pattern 2:
In this pattern, includes is used for searching the sheet name. getSheetName() is used for retrieving the sheet name.
Sample script:
function myFunction() {
const searchText = "V1";
const sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
const sheet = sheets.filter(s => s.getSheetName().includes(searchText));
if (sheet.length > 0) console.log(sheet[0].getSheetName());
}
In this case, if there is only one sheet which has the sheet name including V1 in your Spreadsheet, you can retrieve the sheet by sheet[0].
Note:
In this case, please enable V8 at the script editor.
References:
getSheetByName(name)
getSheetName()
test()
includes()

Related

How to set a named range for a data validation programmatically (in Google apps script) in a Google spreadsheet?

Use Case
Example. I have a named range Apples (address "Sheet10!B2:B"), which in use for data validation for plenty of sheet cells. The data range for Apples can be changed (in a script), e.g. to "Sheet10!D2:D".
It works from UI
I can set manually a named range as a data source of data validation.
In this case, the data validation of a cell will always refer to the named range Apples with updated the data range.
How to make it in Google Apps Script?
GAS Limits
The code, for setting data validation, should look like this, if you have a namedRange object:
mySheet.getRange('F5')
.setDataValidation(
SpreadsheetApp.newDataValidation()
.requireValueInRange(
namedRange.getRange()
)
.setAllowInvalid(false)
.build()
);
DataValidationBuilder.requireValueInRange() does not work here as it requires only class Range (it cannot get NamedRange), and no reference to a named range will be used.
Is there a workaround or so?
UPD1 - Spreadsheet.getRangeByName() does not work
Getting range by name does not help, the data validation will get actual range address.
SpreadsheetApp.getActive().getRangeByName("Apples")
UPD2 No way to make it so far in GAS
As #TheMaster posted, it's not possible at this moment.
Please set +1 for posts:
https://issuetracker.google.com/issues/143913035
https://issuetracker.google.com/issues/203557342
P.S. It looks like the only solution will work is Google Sheets API.
I thought that in your situation, I thought that when Sheets API is used, your goal might be able to be used.
Workaround 1:
This workaround uses Sheets API.
Usage:
1. Prepare a Google Spreadsheet.
Please create a new Google Spreadsheet.
From Example. I have a named range Apples (address "Sheet10!B2:B"), which in use for data validation for plenty of sheet cells. The data range for Apples can be changed (in a script), e.g. to "Sheet10!D2:D"., please insert a sheet of "Sheet10" and put sample values to the cells "B2:B" and "D2:D".
Please set the named range Sheet10!B2:B as Apple.
2. Sample script.
Please copy and paste the following script to the script editor of Spreadsheet and save the script. And, please enable Sheets API at Advanced Google services.
function myFunction() {
const namedRangeName = "Apple"; // Please set the name of the named range.
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName("Sheet10");
const requests = [{ updateCells: { range: { sheetId: sheet.getSheetId(), startRowIndex: 0, endRowIndex: 1, startColumnIndex: 0, endColumnIndex: 1 }, rows: [{ values: [{ dataValidation: { condition: { values: [{ userEnteredValue: "=" + namedRangeName }], type: "ONE_OF_RANGE" }, showCustomUi: true } }] }], fields: "dataValidation" } }];
Sheets.Spreadsheets.batchUpdate({ requests }, ss.getId());
}
In this request, the name of the named range is directly put to userEnteredValue.
3. Testing.
When this script is run to the above sample Spreadsheet, the following result is obtained.
When this demonstration is seen, first, you can see the named range of "Apple" which has the cells "B1:B1000". When a script is run, data validation is put to the cell "A1" with the named range of "Apple". In this case, the values of data validation indicate "B1:B1000". When the range named range "Apple" is changed from "B1:B1000" to "D1:D1000" and the data validation of "A1" is confirmed, it is found that the values are changed from "B1:B1000" to "D1:D1000".
Workaround 2:
This workaround uses the Google Spreadsheet service (SpreadsheetApp). In the current stage, it seems that the Google Spreadsheet service (SpreadsheetApp) cannot directly achieve your goal. This has already been mentioned in the discussions in the comment and TheMaster's answer. When you want to achieve this, how about checking whether the range of the named range is changed using OnChange as following workaround 2?
Usage:
1. Prepare a Google Spreadsheet.
Please create a new Google Spreadsheet.
From Example. I have a named range Apples (address "Sheet10!B2:B"), which in use for data validation for plenty of sheet cells. The data range for Apples can be changed (in a script), e.g. to "Sheet10!D2:D"., please insert a sheet of "Sheet10" and put sample values to the cells "B2:B" and "D2:D".
Please set the named range Sheet10!B2:B as Apple.
2. Sample script.
Please copy and paste the following script to the script editor of Spreadsheet and save the script. And, please install OnChange trigger to the function onChange.
First, please run createDataValidation. By this, data validation is put to the cell "A1" of "Sheet10". In this case, the set range is the range retrieved from the named range "Apple". So, in this case, the range is Sheet10!B2:B1000.
As the next step, please change the range of the named range from Sheet10!B2:B1000 to Sheet10!D2:D1000. By this, onChange` function is automatically run by the installed OnChange trigger. By this, the data validation of "A2" is updated. By this, the values of data validation are changed.
const namedRangeName = "Apple"; // Please set the name of the named range.
const datavalidationCell = "Sheet10!A2"; // As a sample. data validation is put to this cell.
function onChange(e) {
if (e.changeType != "OTHER") return;
const range = e.source.getRangeByName(namedRangeName);
const a1Notation = `'${range.getSheet().getSheetName()}'!${range.getA1Notation()}`;
const prop = PropertiesService.getScriptProperties();
const previousRange = prop.getProperty("previousRange");
if (previousRange != a1Notation) {
const rule = SpreadsheetApp.newDataValidation().requireValueInRange(e.source.getRangeByName(namedRangeName)).setAllowInvalid(false).build();
e.source.getRange(datavalidationCell).setDataValidation(rule);
}
prop.setProperty("previousRange", a1Notation);
}
// First, please run this function.
function createDataValidation() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const rule = SpreadsheetApp.newDataValidation().requireValueInRange(ss.getRangeByName(namedRangeName)).setAllowInvalid(false).build();
ss.getRange(datavalidationCell).setDataValidation(rule);
const prop = PropertiesService.getScriptProperties();
const range = ss.getRangeByName(namedRangeName);
const a1Notation = `'${range.getSheet().getSheetName()}'!${range.getA1Notation()}`;
prop.setProperty("previousRange", a1Notation);
}
References:
Method: spreadsheets.batchUpdate
UpdateCellsRequest
DataValidationRule
Currently, This seems to be impossible. This is however a known issue. +1 this feature request, if you want this implemented.
https://issuetracker.google.com/issues/143913035
Workarounds from the tracker issue creator:
If a validation rule is manually created with a NamedRange via the Sheets GUI, it can then be copied programmatically using Range.getDataValidations(), and subsequently used to programmatically create new DataValidations. DataValidations created this way maintain their connection to the NamedRange, and behave like their manually created counterparts. This demonstrates that the functionality to 'use' NamedRanges for data validation rules is already possible with Apps Scripts, but not the option to 'create' them.
As a half-answer, if you want just validation and can live without the drop-down list of valid values, you can programmatically set a custom formula that references the named range. This reference to the named range will not get expanded in the AppsScript, so future changes to the Named Range's actual range will percolate to the validator. Like so:
mySheet.getRange('F5')
.setDataValidation(
SpreadsheetApp.newDataValidation()
.requireFormulaSatisfied(
'=EQ(F5, VLOOKUP(F5, ' + namedRange.getName() + ', 1))'
)
.setAllowInvalid(false)
.build()
);
(The formula just checks that the value in the cell being tested is equal to what VLOOKUP finds for that cell, in the first column -- I'm assuming the named range content is sorted.)
Use getRangeByName()
function lfunko() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName("Sheet0");
var cell = sh.getRange(1, 10);//location where datavalidation is applied
var rule = SpreadsheetApp.newDataValidation().requireValueInRange(ss.getRangeByName("MyList")).build();
cell.setDataValidation(rule);
}

How do I copy the active file and name it using a value in a Named range - Goolgle script

I am an expert VBA programmer struggling to come to grips with Google Scripts in Google Sheets.
I'm trying to create a copy of the active file and name it from a Named Range. I can get it to copy, but the name of the new file ends up being "Range".
Here is the code I have.
function SaveFileAndCopy() {
var spreadsheet = SpreadsheetApp.getActive();
var rffilename = spreadsheet.getRangeByName("rfFileName");
spreadsheet.copy(rffilename);
};
In that case, how about the following modification?
From:
var rffilename = spreadsheet.getRangeByName("rfFileName");
To:
var rffilename = spreadsheet.getRangeByName("rfFileName").getValue();
In this case, please retrieve the cell value using getValue().
Or, you might be able to also use getDisplayValue() instead of getValue(), when you want to use the display value of the cell.
References:
getValue()
getDisplayValue()

I am trying to automatically apply a filter to a column - and sort the sheet in descending order by that column

I'm trying to have the spreadsheet automatically sort by Column B, in descending order. However the raw data as the "-" text so I'm using the formula in Column C "=abs(B2)" and then trying to filter by Column C instead.
I would like the sheet to automatically apply the filter and then sort when edits are made. I've been playing with the Apps Script but cannot get it to work.
Any help would be appreciated!
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
ss.getRange ("C2").setFormula("=abs(B2)");
var lr = ss.getLastRow();
var fillDownRange = ss.getRange (2,3, lr-1);
ss.getRange("C2").copyTo(fillDownRange);
}
function autosort(){
const ss = SpreadsheetApp.getActiveSpreadsheet()
const ws = ss.getSheetByName("Trustlines")
const range = ws.getRange(2,1,ws.getLastRow()-1,3)
range.sort({column: 3, ascending: false})
}
function onEdit(e){
const row = e.range.getRow()
const column = e.range.getColumn()
if(!(column === 3 && row>= 2)) return
autosort()
}
You probably do not want to get your data from IMPORTHTML. The main reason for that is that the onEdit trigger is not triggered unless the user changes some data (witch is probably not what you want to use).
What I would propose instead is to make all the calculations using Apps Script and only adding to the spreadsheet the result. This will be done following this steps:
Get the page source. This can be done using UrlFetchApp.
Interpret the source and extract the data. XmlService should allow you to do so.
Filter and sort the data. Use the native sort and filter JavaScript Array methods.
Add the result as values on the sheet.
References
Simple Triggers (Google Apps Script guide)
URL Fetch Service (Google Apps Script reference)
XML Service (Google Apps Script reference)
Array.prototype.sort() (MDN JavaScript reference)
Array.prototype.filter() (MDN JavaScript reference)

Can i have a simple script on sheet1 and sheet2?

I have made a script that automatically sorts data when i make a change. It workds fine on the one sheet but i cannot find a way to apply it on sheet2 too.
So i need it to sort both sheet1 and 2 (the sheets are simular so the same sort range and everything needs to be the same - i just need it to apply on sheet2 also-
I have tried to make a copy of the code and change sheet_name to sheet2.
I Insert picture of the code. I would be very happy if you could help.
Explanation:
Take advantage of the event object. This will give you very important information regarding the edit/event which took place.
The idea is to use the script for multiple sheets. One way to do that is to construct an array of the sheet names you want to include:
const sheet_names = ["Management Associate","Finance Associate"];
and check if the name of the active sheet is included in this list:
if(sheet_names.includes(sheet.getName())){
// the rest of the code here
}
As a more complete implementation, I modified the last line of your code to include the name of the sheet that was edited. To do that, I used template literals but of course this approach is optional:
ss.toast(`Sort complete in ${sheet.getName()}`);
Solution:
function onEdit(e) {
const sheet_names = ["Management Associate","Finance Associate"]; // add sheets here
const sort_data_range = "A2:H999";
const sort_order = [{column:6, ascending:true}];
const ss = e.source;
const sheet = ss.getActiveSheet();
if(sheet_names.includes(sheet.getName())){
const range = sheet.getRange(sort_data_range);
range.sort(sort_order);
}
ss.toast(`Sort complete in ${sheet.getName()}`);
}

How to change the cell value of multiple sheets in Google Sheets [Google App Script]?

I have many sheets {(for example) 01.01, 01.02, 01.03 ..... 12.30, 12.31}.
Sheets are duplicated by one sheet, so all sheets of cell address J1 is the same date value.
I want to change J1 cell value by Google App Script.
For example:
J1 value in 01.01 sheet is 2020.1.1
J1 value in 01.02 sheet is 2020.1.2
J1 value in 01.03 sheet is 2020.1.3
J1 value in 12.30 sheet is 2020.12.30
J1 value in 12.31 sheet is 2020.12.31
Here is my Google Sheet
Seeing your sheet it is in korean so I don't know exactly how you want your information to be formatted.
But what I understand is that you want to format the same cell in every sheet using the name of the sheet. I can explain how to get started in that.
function updateCell() {
const a1NotationRange = "J1"; // The range to be modified in every sheet
// Retrieve the spreadsheet
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Get the full list of sheets and change the value of `a1NotationRange`
// And execute a function for every single sheet
const sheets = ss.getSheets();
sheets.forEach((sheet) => {
const sheetName = sheet.getName();
// If you want to modify the format to be inserted you should expand
// this snippet of code here.
sheet.getRange(a1NotationRange).setValue(sheetName);
})
}
The concept is very simple, get the all the sheets inside a variable. And then iterate through them to change the range reflected in a1NotationRange.
Reference:
If you are new to javascript programming you could use some of these links to guide you in this code:
forEach()
Arrow functions expressions
If you need more help using the Apps Script services:
getActiveSpreadsheet()
getSheets()
setValue()