问题
Link to demo sheet
I have a sheet which is sorted by column E. Values in column E can be duplicate, which means that several rows can have the same value in column E. Now I want to color rows which signify a change in column E. Here's the code that I've built based on some great answers on StackOverflow:
function quicktest() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var rangeData = spreadsheet.getDataRange().getValues();
var lastRow = spreadsheet.getLastRow();
// var searchRange = spreadsheet.getRange(1, 1, lastRow-1, 5);
// var rangeValues = searchRange.getValues();
var previousclient = rangeData[2][5];
console.log(previousclient);
for ( j = 1 ; j < lastRow - 1; j++){
var currentclient = rangeData[j][5];
console.log(previousclient," ",currentclient);
if (previousclient != currentclient) {
spreadsheet.getRange(j,1,1,5).setBackground("#cc4125");
previousclient = currentclient;
};
}
The code runs, but the result is that it's "painting" the wrong cell and it's also not painting the entire row (columns A to H), it's painting just A to C. I've also read some answers here that recommend sending the values to rangeValues, but that didn't work me. That's why it's listed as a comment in the code. Perhaps I do need to use it. Here's how I'd like to demo sheet to look like after running this code:
Thanks
回答1:
Be careful with indices - arrays start with [0]
The respective confusion leads to several problems in your code:
rangeData[2][5]means cellF3- notE, if you want to retrieve the columnE- it corresponds to the array index4(both for previous and current client!)- Given that the initial
previousclientis not suposed to be colored (only the following onew) you should set it to the header row, sorangeData[0][4] - When you use the method
getRange()- the row indices start with1(unlike array elements!!!), so array elementicorresponds to the rowi+1
To fix those issue modify your code as following:
function change_row_color() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var rangeData = spreadsheet.getDataRange().getValues();
var lastRow = spreadsheet.getLastRow();
var previousclient = rangeData[0][4];
console.log(previousclient);
for ( j = 1 ; j < lastRow - 1; j++){
var currentclient = rangeData[j][4];
console.log(previousclient," ",currentclient);
if (previousclient != currentclient) {
spreadsheet.getRange(j+1,1,1,5).setBackground("#cc4125");
previousclient = currentclient;
};
}}
UPDATE
Calls to external services including SpreadsheetApp methods should be minimized because they make your code slower.
So, for example calling setBackground within each loop will result in a longer execution time.
If you want to set the colors only once with setBackgrounds instead of setBackground, you can do it like this:
function change_row_color() {
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var range = spreadsheet.getDataRange();
var rangeData = range.getValues();
var lastRow = spreadsheet.getLastRow();
var previousclient = rangeData[0][4];
console.log(previousclient);
var colors = [[0,0,0,0,0]];
for ( j = 1 ; j < lastRow; j++){
var currentclient = rangeData[j][4];
console.log(previousclient," ",currentclient);
if (previousclient != currentclient) {
colors.push(["#cc4125","#cc4125","#cc4125","#cc4125","#cc4125"]);
previousclient = currentclient;
} else{
colors.push([0,0,0,0,0]);
}
}
range.setBackgrounds(colors);
}
Either this approach will be faster strongly depends on your data size and amount of duplicates.
来源:https://stackoverflow.com/questions/62590592/google-script-change-row-color-based-on-data-change-sheet-sorted