I tried to get the value of a range and than remove all points from the cell.
var FILE = SpreadsheetApp.openById("xyz");
var CONTENT = FILE.getSheetByName("Sheet1");
var A1 = CONTENT.getRange("I17").getValue();
A1. replace(".", "");
It gives me that can't find the replace function. Is there any function in Google Apps Script that allows me to replace the string?
If this is an exact copy of your script then you have a space in-between A1. and replace but I assume it is not.
#SergeInsas is right the content needs to be a string for the replace() function to work, so if your trying to replace the . in a decimal number then you can use the toString() method first like below.
var FILE = SpreadsheetApp.openById("xyz");
var CONTENT = FILE.getSheetByName("Sheet1");
var A1 = CONTENT.getRange("I17").getValue();
var A1String = A1.toString().replace(".", "");
Or you can multiply the number to get rid of the decimal but this will depend on how many decimal places you have :)
There is a more powerful, and simpler, method available: TextFinder.
The accepted answer to this question requires an additional step to post the replaced string back to the cell.
The TextFinder method does not need you to write the data back to the cell.
And if you want to search multiple cells, then this method saves you the iterations.
var FILE = SpreadsheetApp.openById("xyz");
var CONTENT = FILE.getSheetByName("Sheet1");
var A1 = CONTENT.getRange("I17");
A1.createTextFinder(".").replaceAllWith("");
I haven't tested it on a large data set but I suspect this would be quite quick.
Edit: I wrote a short tutorial on this.
For some reason, this solution doesn't work for me. Here is my whole code that should replace the '+' symbol with 'nothing'
// I need to replace more occurrences of different strings, so this is just an example..
var ui = SpreadsheetApp.getUi();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getRange("G5:G7").getValues();
// this is a loop, to go through multiple cells that may contain the text, that needs to be replaced.
for (var i = 0 ; i<range.length ; i++) {
var le = range.length;
var stri = range[i].toString().replace("+", "");
Logger.log(stri);
}
var msg = ui.alert("Replaced?");
return msg;
Hope this help you
function removeAccents() {
var spreadsheet = SpreadsheetApp.getActive();
var range = spreadsheet.getRange("F3:F");
var data = range.getValues();
for (var row = 0; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
data[row][col] = (data[row][col]).toString().replace(/é/g, 'e');
data[row][col] = (data[row][col]).toString().replace(/ã/g, 'a');
}
}
range.setValues(data);
};
Sharing a very helpful solution from Bannager Bong on this Google Docs Editor Help Forum thread. Made a slight modification to the function so that it accepts arguments for the find, replace values and then added a range argument so that the function can target a specific region. Even so, this method is extremely slow (my sheets have 5k rows).
function Cleanup12m() {
var spreadsheet = SpreadsheetApp.getActive();
//fandr(",", "");
//fandr("\"","");
fandr("�","",spreadsheet.getRange('BA:BA')); //uses specific range
};
function fandr(find, repl) {
var r=SpreadsheetApp.getActiveSheet().getDataRange();
var rws=r.getNumRows();
var cls=r.getNumColumns();
var i,j,a,find,repl;
//find="abc";
//repl="xyz";
for (i=1;i<=rws;i++) {
for (j=1;j<=cls;j++) {
a=r.getCell(i, j).getValue();
if (r.getCell(i,j).getFormula()) {continue;}
//if (a==find) { r.getCell(i, j).setValue(repl);}
try {
a=a.replace(find,repl);
r.getCell(i, j).setValue(a);
}
catch (err) {continue;}
}
}
};
//Revised to apply to a selected range
function fandr(find, repl, range) {
var r= range;//SpreadsheetApp.getActiveSheet().getDataRange();
var rws=r.getNumRows();
var cls=r.getNumColumns();
var i,j,a,find,repl;
//find="abc";
//repl="xyz";
for (i=1;i<=rws;i++) {
for (j=1;j<=cls;j++) {
a=r.getCell(i, j).getValue();
if (r.getCell(i,j).getFormula()) {continue;}
//if (a==find) { r.getCell(i, j).setValue(repl);}
try {
a=a.replace(find,repl);
r.getCell(i, j).setValue(a);
}
catch (err) {continue;}
}
}
};
Related
Completely new to using the AppsScript in Google but I came across a script that would allow GoogleSheets to count cells if coloured, and it automatically updates thanks to that last bit of code that sets a random value that essentially triggers a recalculation:
// Unsed third argument
function countColoredCells(countRange,colorRef,unUsed) {
var activeRg = SpreadsheetApp.getActiveRange();
var activeSht = SpreadsheetApp.getActiveSheet();
var activeformula = activeRg.getFormula();
// The regex matches the parentheses as an array, gets the arguments as a string,
// then splits the arguments on the comma into another array
var arrayOfArguments = activeformula.match(/\((.*)\)/).pop().trim().split(',');
// Get the first argument which is the range
var countRangeAddress = arrayOfArguments[0];
// Get the second argument, which is the reference color
var colorRefAddress = arrayOfArguments[1];
var backGrounds = activeSht.getRange(countRangeAddress).getBackgrounds();
var BackGround = activeSht.getRange(colorRefAddress).getBackground();
var countCells = 0;
for (var i = 0; i < backGrounds.length; i++)
for (var k = 0; k < backGrounds[i].length; k++)
if ( backGrounds[i][k] == BackGround )
countCells = countCells + 1;
return countCells;
};
// If Cell A1 has ColouredCells, Writes a random number to B1
function onEdit(e) {
if SpreadsheetApp.getActiveSheet().getRange('A1')="ColouredCells" {
SpreadsheetApp.getActiveSheet().getRange('B1').setValue(Math.random());}
}
Specifically I'm looking to edit the last part of the code so that this script only runs on sheets which I'd like it to (instead of randomly changing my B1 cell on all sheets I touch). As per the comments I'd like it to only run if cell A1 has the string "ColouredCells". Sorry newbie to all this so apologies if this is a really simple ask! Appreciate any help I can get on this one, I've tried googling quite a few different things but can't seem to to find the solution on this one!
This is the part I specifically need help with.
// If Cell A1 has ColouredCells, Writes a random number to B1
function onEdit(e) {
if SpreadsheetApp.getActiveSheet().getRange('A1')="ColouredCells" {
SpreadsheetApp.getActiveSheet().getRange('B1').setValue(Math.random());}
}
Thank you!
To run the code for specific sheets only you have to first get the name of the sheet and with an if-statement run the code as you wish
function onEdit(e){
// code
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
if ("Sheet 1" === sheet.getName() || "Sheet 2" === sheet.getName()) {
// Run your code
}
}
I need a way to remove all conditional formatting by running a script (my client will be using this and he doesn't want to have to repeat the process of removing conditional formatting for each worksheet in each of a large number of spreadsheet files).
Is there any way to do this via Google Apps script? All I see is .clearFormat(), which unfortunately clears all formatting, of which a lot should not be deleted (eg, font color, bg color, font, font weight, font rotation, cell outlines)
How to do this in such a way that only one button needs to be pressed for each spreadsheet file?
Google Apps Scripts now supports removing conditional formatting using clearConditionalFormatRules
var sheet = SpreadsheetApp.getActiveSheet();
sheet.clearConditionalFormatRules();
https://developers.google.com/apps-script/reference/spreadsheet/sheet#clearconditionalformatrules
This is possible with Google Sheets API v4, which Apps Script can access via Advanced Sheets Service (note that it must be enabled before use, as the linked page instructs). Here is a script that deletes all conditional formatting rules in Sheet1 of the current spreadsheet (you'll want to loop over sheets, etc).
function clearSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
var sheet = ss.getSheetByName("Sheet1");
var sheetId = sheet.getSheetId();
var format_req = {
"requests": [{
"deleteConditionalFormatRule": {
"index": 0,
"sheetId": sheetId
}
}]
};
var string_req = JSON.stringify(format_req);
while (true) {
try {
Sheets.Spreadsheets.batchUpdate(string_req, ssId);
}
catch(e) {
break;
}
}
}
Each conditional format rule has a 0-based "index". Deleting the rule with index 0 causes other indices to decrease by 1. So the loop continues deleting index = 0 rule until there isn't one, and an error is thrown (and caught, exiting the loop).
This is a weird way of sending requests: I'd much rather send one batch request like this:
var format_req = {
"requests": [
{
"deleteConditionalFormatRule": {
"index": 0,
"sheetId": sheetId
}
},
{
"deleteConditionalFormatRule": {
"index": 1,
"sheetId": sheetId
}
}]
};
but to do this, one must know how many conditional formatting rules are there (and I don't see how one would find out). If you ask for more rules to be deleted than exist in the sheet, the entire request fails and nothing is deleted.
Without advanced service
With plain Apps Script, the best one can do is this:
var sheet = SpreadsheetApp.getActiveSheet();
var range = sheet.getRange(1, 1, sheet.getMaxRows(), sheet.getMaxColumns());
var backgrounds = range.getBackgrounds();
var fontColors = range.getFontColor();
var fontFamilies = range.getFontFamilies();
// ... other get methods from https://developers.google.com/apps-script/reference/spreadsheet/range
// tricky part: modify the backgrounds, replacing the colors used in conditional formatting by white
range.clearFormat();
range.setBackgrounds(backgrounds)
.setFontColors(fontColors)
.setFontFamilies(fontFamilies)
// .set other things
Here I am assuming that conditional formatting affects only cell backgrounds. If one is unable to filter the background colors (which requires knowing exactly what colors were used in conditional formatting rules), the effects of conditional formatting will become ordinary background color, which is very undesirable... it may be better to forego setting the background colors at all.
So after my comment to if....
but to do this, one must know how many conditional formatting rules are there (and I don't see how one would find out)
decided to extend his code:
function get_clear_Formatting() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssId = ss.getId();
// 1 part - get conditional formatting data for all sheets in active spreadsheet
var params = {
'fields': "sheets(properties(title,sheetId),conditionalFormats)"
};
var getFormatResult = Sheets.Spreadsheets.get(
ssId,
params
);
var sheets = getFormatResult.sheets;
var ConditionalFormatIndex = {
"sheetID" : [],
"sheetTitle" : [],
"formatRulesCount" : []
}
for (var i = 0; i < sheets.length; i++) {
ConditionalFormatIndex.sheetID[i] = sheets[i].properties.sheetId;
ConditionalFormatIndex.sheetTitle[i] = sheets[i].properties.title
ConditionalFormatIndex.formatRulesCount[i] = (sheets[i].conditionalFormats) ?
sheets[i].conditionalFormats.length :
0;
}
// 2 part - clear all conditional formatting in an all sheets in active spreadsheet
var ClearFormat_req = []
for (var i = 0; i < ConditionalFormatIndex.sheetID.length; i++) {
if ( ConditionalFormatIndex.formatRulesCount[i] ) {
for (var cf = 0; cf < ConditionalFormatIndex.formatRulesCount[i]; cf++) {
ClearFormat_req.push(
{
"deleteConditionalFormatRule": {
"index": 0,
"sheetId": ConditionalFormatIndex.sheetID[i]
}
});
}
};
}
Sheets.Spreadsheets.batchUpdate({'requests': ClearFormat_req}, ssId);
}
Copy a cell that doesn't have any conditional formatting.
Select the cell(s) you want to remove the conditional formatting from.
Edit -> Paste special -> Paste conditional formatting only.
A bit late, but I found a way, if that may help someone.
remove every conditional formatting on ranges intersecting the one in parameters
Then leave every other conditional formatting untouched (actually : rebuild it).
function test(){
var sh=shWork;//define your sheet
var r= sh.getRange("A3:A6");//example
clearEveryConditionalFormattingOnRange(sh,r)
}
function clearEveryConditionalFormattingOnRange(sh,r){
//build a parallel rules at looping on initial rule, in order to rebuild it without unwanted elements
//get rules
var rules=sh.getConditionalFormatRules();
//create new rules
var a_newRules= new Array();
//loop on rules
for (var i=0;i<rules.length;i++){
//create new currentRanges
var a_newCurrentRanges=new Array();
//loop on ranges from rule
var currentRule=rules[i];
var currentRanges=currentRule.getRanges();
for (var j=0;j<currentRanges.length;j++){
var currentRange=currentRanges[j];
var testIfIntersect_OK=RangeIntersect(r,currentRange);
//add this range to a_newCurrentRanges
if (!testIfIntersect_OK){
a_newCurrentRanges.push(currentRange);
}//if (testIfIntersect_OK){
}//for (var j=0;j<currentRanges.length;j++){
//create then add new rule to a_newRules
if (a_newCurrentRanges.length>0){
var a_newRule = SpreadsheetApp.newConditionalFormatRule()
.whenFormulaSatisfied(currentRule.getBooleanCondition().getCriteriaValues())
.setBackground(currentRule.getBooleanCondition().getBackground())
.setRanges(a_newCurrentRanges)
.build();
a_newRules.push(a_newRule);
}//if (a_newCurrentRanges.length>0){
}//for (var i=0;i<rules.lengthi++){
sh.setConditionalFormatRules(a_newRules);
}
//returns true if intersection between range1 and range2
function RangeIntersect(R1, R2) {
var LR1 = R1.getLastRow();
var Ro2 = R2.getRow();
if (LR1 < Ro2) return false;
var LR2 = R2.getLastRow();
var Ro1 = R1.getRow();
if (LR2 < Ro1) return false;
var LC1 = R1.getLastColumn();
var C2 = R2.getColumn();
if (LC1 < C2) return false;
var LC2 = R2.getLastColumn();
var C1 = R1.getColumn();
if (LC2 < C1) return false;
return true;
}
I ended up finding a solution based on David Friedman's answer. This script successfully removed the conditional format from just one column (D), and left the conditional formats in other columns unchanged.
// clearConditionalFormat
// Data must have header row that does NOT have conditional formatting
// Otherwise you must identify some other cell on the sheet that does not
// have conditional formatting
function test(){
var sheetName = "Sheet13"; // replace with your sheet's name
var rangeText = "D3:D"; // replace with the your range
clearConditionalFormat(rangeText,sheetName);
};
function clearConditionalFormat(rangeText,sheetName){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var rangeText = rangeText.toString().toUpperCase();
var range = ss.getRange(rangeText).activate();
var rangeTextSplit = rangeText.split(":");
// example: returns AA22 from AA22:AZ37
var rangeFirstLetter = rangeTextSplit[0].replace(/[0-9]+/g, "");
// example: returns AA from AA22
var rangeRowNum1 = rangeTextSplit[0].replace(/[A-Z]+/g, "")*1;
// example: returns the 22 of AA22:AZ37
var rangeHeaderText = rangeFirstLetter + (rangeRowNum1 - 1);
sheet.getRange(rangeHeaderText)
.copyTo(range,SpreadsheetApp.CopyPasteType
.PASTE_CONDITIONAL_FORMATTING, false);
};
I want to check values from a JSON URL against values within a defined range in my Google Sheet.
Should there be a match, I would like to query the properties of the cell containing the matching value (its row, its column, etc.)
How can I do this within Google Apps Script?
Everything you need to know about Spreadsheet operations in Apps Script can be found in Overview and SpreadsheetApp. You can start from there. For example, the methods to query properties like row and col are getRow and getColumn
Never mind. Got to my answer myself.
var i = 0;
// Bringing in the data from the third-party into Google Sheets.
var groupJSON = UrlFetchApp.fetch('<ANY-JSON-URL>');
var groupObjectRaw = JSON.parse(groupJSON);
// var groupObject = groupObjectRaw[0]; <--optional, for my use only
var membersGroupForm = groupObject.data['member'];
var projectsGroupForm = groupObject.data['project'];
var hoursGroupForm = groupObject.data['hours worked'];
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Details');
var membersRange = ss.getRange('Details!A:A');
var membersSheet = membersRange.getValues();
var projectsRange = ss.getRange('Details!1:1');
var projectsSheet = projectsRange.getValues();
function getRowNumber() {
for (i; i < membersSheet.length; i++) {
if (membersSheet[i][0] == membersGroupForm) {
return i + 1;
}
}
}
var rowNumber = getRowNumber(i, membersSheet, membersGroupForm);
Logger.log(rowNumber);
function getColumnNumber() {
for (var row in projectsSheet) {
for (var col in projectsSheet[row]) {
if (projectsSheet[row][col] == projectsGroupForm) {
return parseInt(col) + 1;
}
}
}
}
var columnNumber = getColumnNumber(projectsSheet, projectsGroupForm);
Logger.log(columnNumber);
var cell = ss.getRange(rowNumber, columnNumber);
cell.setValue(hoursGroupForm);
I have the results of a google form (a google spreadsheet). I would like to write an app script to check each column for a string "YES." If the column has that string, then I would like to change the background color of that column (or one cell in that column) green. The number of columns will vary each time the form is sent so it would need to check all columns used (Sorry, I mean I send out a similar form each time and want to use the same script on each one, except that each time the form is used it can come back with a different number of columns-responses - thanks corn3lius). Can this be done in a google form response spreadsheet? Here is the code I am playing with. (updated code with Cooper's input)
function colchk(){
var ss = SpreadsheetApp.getActiveSheet();
var resp = ss.getDataRange().getValues();
for(var n=0;n<resp.length;n++)
{
for(var p=0;p<resp[n].length;p++)
{
if(resp[n][p].toString().match(/^YES/)){ ss.getRange(n+1,p+1).setBackground('#00ff00')}}};
}
//this code works...Thanks Cooper!
This is an older post, but I'd like to leave an easier solution here for any future visitors:
function colorYesCells() {
var sheet = SpreadsheetApp.getActiveSheet();
var yesFinder = sheet.createTextFinder("YES");
var yesCells = yesFinder.findAll();
yesCells.forEach(function(cell){
cell.setBackground('#00ff00');
});
};
Try this:
if(resp[n][0].toString().match(/^YES/){ ss.getRange(n+1,1).setBackground('#00ff00') };
Perhap's something like this:
function colchk(){
var ss = SpreadsheetApp.getActiveSheet();
var resp = ss.getDataRange().getValues();
for(var n=0;n<resp.length;++n)
{
for(var p=0;p<resp[n].length;p++)
{
if(resp[n][p].toString().match(/^YES/){ ss.getRange(n+1,p+1).setBackground('#00ff00') };
}
};
Since I can't comment, I write here :
for(var n=0;n<resp.length;++n)
should be :
for(var n=0;n<resp.length;n++)
++n --> n++
typing too fast ?
based off #coopers code- small edits
function colchk(){
var ss = SpreadsheetApp.getActiveSheet();
var resp = ss.getDataRange().getValues();
for(var n=0;n<resp.length;n++)
{
for(var p=0;p<resp[n].length;p++)
{
if(resp[n][p].toString().match(/^YES/)) {
ss.getRange(n+1,p+1).setBackground('#00ff00') };
}
}};
Hello I wrote a small script to copy one template sheet in a spreadsheet, as a new sheet in the same spreadsheet.
I wrote two versions of it, one driven by a menu that asks for the name of the new sheet to be created:
function addonenewSheet() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var temp = ss.getSheetByName('template');
var naame = Browser.inputBox("CustomerID to be created");
try {
ss.setActiveSheet(ss.getSheetByName(naame));
}
catch (e) {
ss.insertSheet(naame, {template:temp});
}
}
This one works as intended, and names the new sheet 234 if I say so in the inputbox.
The second function is very similar, but parses some values and attempts to create many sheets at once:
function addmissingSheets() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var temp = ss.getSheetByName('template');
var sheet = SpreadsheetApp.getActiveSheet();
var data = sheet.getDataRange().getValues();
for (var i = 10; i < data.length; i++) {
if(typeof data[i][1] == 'number'){
try {
ss.setActiveSheet(ss.getSheetByName(data[i][1]));
}
catch (e) {
Logger.log('Customer ID: ' + data[i][1]);
var insertpage = data[i][1];
ss.insertSheet(insertpage, {template:temp});
}
}
}
}
As long as Logger.log is concerned, data[i][1] has the right value, but somehow insertSheet creates sheets named "copy of template", "copy of template 2"... Instead of taking the value assigned in data[i][1]
Would anyone know why this behaviour and how I can solve this issue?
your second script does not use correct variable types. The method you are using insert sheet uses types (<string>, {template:<sheet>}). Since your customer ID is a number it does not work. There is a simple fix you can do
Change
var insertpage = data[i][1];
into:
var insertpage = data[i][1].toString();
and you will now be able to use the customer ID (which is a number) to create a sheet name (which is a string)