Set Cell Colours in Google Sheet through Script with an Array - javascript

It's very straight forward to get a sheets cell values into an array. Then you can edit any individual cell or cells you want (In the array). Then write that same array back to the sheet. Like below.
var adSpendExprtSheet = ss.getSheetByName("Ad Spend Export");
var adSpendExprtSheetData = adSpendExprtSheet.getRange(1 ,1, adSpendExprtSheet.getLastRow(), adSpendExprtSheet.getLastColumn()).getValues();
Then you can change values in the array just saved.
adSpendExprtSheetData[0][0] = "Changing first cell in array"
Then we can use this same array. Which we have updated. Passing it back to be written on the actual sheet.
adSpendExprtSheet.getRange(1 ,1, adSpendExprtSheet.getLastRow(), adSpendExprtSheet.getLastColumn()).setValues(adSpendExprtSheetData);
Can we do this for setting colours?
Right now I would have to get the range of individual cells. Then use setBackground("#00ff00");
Can I put all colour values into an array? Change the colours of cells with a HEX value. Then write that array back to the sheet?
I need to optimize my script. Instead of taking 5 minutes. It could be done in seconds. By reading and writing to the sheet only a few times. Not hundreds.
I would appreciate any help!

In your case, how about using getBackgrounds() and setBackgrounds(color)? In this case, you can use it like getValues() and setValues() in your question. When your script is modified, it becomes as follows.
Modified script:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var adSpendExprtSheet = ss.getSheetByName("Ad Spend Export");
var range = adSpendExprtSheet.getRange(1 ,1, adSpendExprtSheet.getLastRow(), adSpendExprtSheet.getLastColumn());
var backgrounds = range.getBackgrounds();
backgrounds[0][0] = "#FF0000"; // This is red color as a sample.
range.setBackgrounds(backgrounds);
In this case, the value retrieved with getBackgrounds() is 2 dimensional array. And it can be put to the cells using setBackgrounds(). By this, I think that the process cost will be able to be reduced than that of getBackground and setBackground.
Note:
If you want to set one color to the range, you can also use the following script.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var adSpendExprtSheet = ss.getSheetByName("Ad Spend Export");
var range = adSpendExprtSheet.getRange(1 ,1, adSpendExprtSheet.getLastRow(), adSpendExprtSheet.getLastColumn());
range.setBackground("#FF0000");
References:
getBackgrounds()
setBackgrounds(color)

Related

Copy filtered range from one spreadsheet to another - Google app script

I have a large google sheet with 30275 rows and 133 columns in a google sheet. I want to filter the data and copy column AZ to another spreadsheet.
Link to spreadsheet: https://docs.google.com/spreadsheets/d/1aiuHIYzlCM7zO_5oZ0aOCKDwPo06syXhWvhQMKgJE2I/edit?usp=sharing
I have been trying to follow this link
I am not that familiar with javascript and the code is designed to exclude items from filter rather than including items on filter. I have 500+ items to exclude so need to work out something that will be efficient in filtering large dataset in short time before execution limit is reached.
Here is my code so far. Any help to get this working would be appreciated.
NOTE: Filter/ Query with importrange formulas dont work due to the large volume of data. So I need an efficient script to filter large dataset and move them to another sheet before execution time limit.
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
var destsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('JockeyList');
var demosheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValues();
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here
//Logger.log(jockey);
var hiddenValues = jockey;
values = values.filter(function(v) {
return hiddenValues.indexOf(v[51]) == 1;
});
Logger.log(values.length);
// Set filtered data on the target sheet
destsheet.getRange(10, 5, values.length, 2).setValues(values);
}
Ok so it seems like you want to copy only the values from AZ in 'Sheet1' that are equal to whatever string value is contained in cell L14 of sheet 'Betting data - Demo.' If that is the case, then here is a change to your original code that will accomplish that:
function filtered() {
var ss = SpreadsheetApp.openById('1u9z_8J-tvTZaW4adO6kCk7bkWeB0pwPcZQdjBazpExI');
var sheet = ss.getSheetByName('Sheet1');
// this assumes that your destsheet and demosheet are in the same spreadsheet. Keep in mind that opening spreadsheets with SpreadsheetApp is costly so you want to minimize your calls to new sheets.
var destsheet = ss.getSheetByName('JockeyList');
var demosheet = ss.getSheetByName('Betting data - Demo');
var jockey = demosheet.getRange('L14').getValue();
var searchTerm = new RegExp(jockey);
// Get full (non-filtered) data
var values = sheet.getRange('A:EC').getValues();
// Apply filter criteria here and return ONLY THE VALUE IN COLUMN AZ
var filteredValues = values.reduce(function(resultArray, row) {
if (searchTerm.test(row[51])) resultArray.push([row[51]]);
return resultArray;
}, [])
// Set filtered data on the target sheet
// Note* not clear why you are starting at row 10, but as is this will overwrite all of the data in column 5 of destsheet starting from row 10 every time this function runs
destsheet.getRange(10, 5, filteredValues.length, 1).setValues(filteredValues);
}
As it says in the code sample, this will only copy and paste the value in column AZ of 'sheet1'. It does not alter 'sheet1' in any way. If that is really all you want to do, then this function works, but it's overkill. Since you are just filtering values in AZ against a single string value, it would be more efficient to simply count the number of times that string occurs in column AZ and then add the string that number of times to your destination sheet.
Also note that your original function is pasting values into destsheet into a constant row (row 10). That means that every time your function runs, the data from row 10 on will be overwritten by whatever data you are copying from 'sheet1'

Google Appscript using for loop with if

The aim of my script is to loop through one column of data (Col 2 in my example) and where the cell says 'Approved' then adjust the formula which is sitting in the corresponding Col1 to be saved as a value. The script below achieves this but runs awfully slowly - can anyone help in speeding it up?
var ss = SpreadsheetApp.getActiveSpreadsheet();
var data = ss.getSheetByName('data');
var tracker = ss.getSheetByName('Tracker');
var rowlength = tracker.getLastRow();
for (r=2; r<rowlength+1; r++) {
var ApprovedCell = tracker.getRange(r,2).getValue();
if (ApprovedCell == 'Approved'){
var FormulaCell = tracker.getRange(r,1);
FormulaCell.copyTo(FormulaCell,{contentsOnly:true});
}}
}
Explanation:
The issue with your current solution is that you are iteratively using getValue, getRange and copyTo which is an extremely inefficient approach especially when the size of the data becomes large.
Instead you can use getValues() and getFormulas() to get all the values and the formulas respectively, of the given range, and then use setValues() to set all the desired values/formulas back to the sheet.
The following script will iterate over the values with a forEach() loop and will store the value, if cell in column B is 'Approved', otherwise store the formula, to an empty array repAr.
Then you can efficiently use a single line of code to set all the values/formulas back to column A:
tracker.getRange(2,1,repAr2D.length,1).setValues(repAr2D);
Solution:
function myFunction(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const tracker = ss.getSheetByName('Tracker');
const vals = tracker.getRange('A2:B'+tracker.getLastRow()).getValues();
const formulas = tracker.getRange('A2:A'+tracker.getLastRow()).getFormulas().flat();
const repAr = [];
vals.forEach((r,i)=>
repAr.push(r[1]=='Approved'?r[0]:formulas[i]));
const repAr2D = repAr.map(r=>[r]);
tracker.getRange('A2:A'+tracker.getLastRow()).clearContent();
tracker.getRange(2,1,repAr2D.length,1).setValues(repAr2D);
}
Bonus info:
Instead of a regular if condition, I used a ternary operator to make the code more clear.
getFormulas() returns a 2D array and this is why I am using flat() to convert it to a 1D array. This is more convenient given that the range is a single column and you can just slice the array with a single index.
It is a good practice to clear the content before you set data to a range that already contains some data.

Using If function for multiple cells

Hi I have a working program to pull data from one sheet to another sheet and place in the relevant cells, however with one column I want to change the results which reads a "K" from the source sheet and write an "A" to the target sheet using a if function but I can only seem to do one cell and not the full column. How can I do this for multiple cells? If I try.getRange("F18:41") it doesn't seem to work.
Please see the code below:
var sss = SpreadsheetApp.openById('....'); // sss = source spreadsheet
var ss = sss.getSheetByName('.....); // ss = source sheet
//Get full range of data sheet 1
var TypeWire = ss.getRange("F18");
//get A1 notation identifying the range
var A16Range = TypeWire.getA1Notation();
//get the data values in range
var SDataSixteen = TypeWire.getValues();
var tss = SpreadsheetApp.openById('.....'); // tss = target spreadsheet
var ts = tss.getSheetByName('....'); // ts = target sheet
//set the target range to the values of the source data
ts.getRange("C40:C61").setValues(SDataSeven);
if (SDataSixteen == "K")
{
ts.getRange("L16").setValue("A");
}
}
The getValues() method of Class Range returns a multidimentional (2D) array. The elements of the "outer" array are arrays that represent rows. The elements of the inner arrays are objects that represent the cell values for the corresponding row.
There are several ways to do what you are looking for. Perhaps the easier to understand is the technique shown in the Cooper's answer: Use nested for statements.
Use one for statement to iterate over the rows, then another for loop to iterate over the row cells.
IMPORTANT NOTE:
Using loops to write single cells values is very slow. For recommendations please read https://developers.google.com/apps-script/guides/support/best-practices
Related
Hide Row in Google Sheets if Cell Contains "no" - Multiple Sheets
How to compare values of cells in if condition?

Google Sheet Script Editor - setValues for array

I`m trying to replace old values with new values using setValues in Google sheet script.
The data is in the below link...
https://docs.google.com/spreadsheets/d/1pSUVkxM9FhSNgizedHbY2MnYGTnC2iiYLfrWsoPmDks/edit?usp=sharing
I`m basically trying to remove first 14 characters and the last 12 characters under "Tracker" column
Below is the code I tried..
function URLReplacement() {
var ss = SpreadsheetApp.getActive().getSheetByName("transformer");
var rng = ss.getRange("G:G");
var data = rng.getValues();
for (var items in data)
{
var newer = data[items][0].substring(14)
// Turn these strings into an array
var newerr = newer.split(" ")
// Turn this into 2 dimensional array to use setValues
ss.getRange("G:G").setValues([newerr])
Logger.log([newer]);
}
}
But now, I get errors with the setValues statement
Saying the range I set there do not match the data
What am I doing wrong here..?
Can anyone please provide me with suggestions / advice?
You want to convert from IMAGE_SUFFIX_"http://google.com"<xxxnouse>" to http://google.com at the column "G".
The format of IMAGE_SUFFIX_"http://google.com"<xxxnouse>" is constant.
If my understanding is correct, how about this modification? The reason of your error is that [newer] is not 2 dimensional array for using setValues(). If this error was removed, the header is removed by overwriting the empty value. So I would like to modify as follows.
Modification points:
When getLastRow() is used, the data size retrieved by it can be reduced from that retrieved by "G:G". By this, the process cost can be reduced.
Header is not retrieved by getRange(2, 7, ss.getLastRow(), 1).
From the format of IMAGE_SUFFIX_"http://google.com"<xxxnouse>", split() was used for parsing this value.
The converted data was put by setValues(). By this, the process cost can be also reduced.
Modified script:
function URLReplacement() {
var ss = SpreadsheetApp.getActive().getSheetByName("transformer");
var rng = ss.getRange(2, 7, ss.getLastRow(), 1); // Modified
var data = rng.getValues();
var convertedData = data.map(function(e) {return e[0] ? [e[0].split('"')[1]] : e}); // Added
rng.setValues(convertedData); // Added
}
Note:
In your shared sample Spreadsheet, the sheet name is "Sheet1". But your script uses "transformer" as the sheet name. Please be careful this.
If the format of actual values in your Spreadsheet is different from your shared Spreadsheet, this might not be able to be used.
References:
split()
setValues()
If this was not the result you want, I apologize.

Change my code from Variable to Array

I have a beautiful set of code provided from one of the best community member. What this code does is it reads a cell value from Google spreadsheet and then automatically check the checkbox of a html form. Now I want to make that code read a range of spreadsheet meaning making the values store in array and perform the same function in html form.
Here is the Javascript which reads a single cell value:-
function getValues(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
var match1 = sheet.getRange("B2").getValue();
return match1;
}
My new JS code has changed say
match1 = sheet.getRange(2,2,5,1).getValue();
how should my HTML code would change?
Here is the Index.html which performs the auto checkbox function:-
<script>
google.script.run.withSuccessHandler(checkDefault).getValues();
function checkDefault(val){
var checkBoxName = "name"+val;
document.getElementById(checkBoxName).checked = true;
}
</script>
Any help is appreciated. Thank You!
To read ranges you need to use the range's getValues() method, not getValue(); getValue returns the top leftmost cell's contents.
getValues() will return an array of rows. Each row being an array of cells within that row.
Be aware that it returns an array of arrays, even if it's just one column wide or one row high.
So if you want an array you can
var match1 = sheet.getRange("B2").getValues().map(function(row) {return row[0]});
In the script try
google.script.run.withSuccessHandler(checkDefault).getValues().forEach(checkDefault);

Categories

Resources