Conditional Borders in Google Sheets
I am trying to do exactly what this other post is asking, but the accepted answer simply does not work. The original post was very clear, so here it is once more:
Excel apparently has this type of conditional formatting built-in: https://sites.google.com/site/techyhelp85/excel-tips/group-borders
I'd like to accomplish the same in Google Sheets via Google Apps Script. The following should demonstrate the before and after conditions:
Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
3 orange Florida
4 orange Valencia
5 pear Garden
6 banana Chiquita
Resulting Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
-----------------------------------
3 orange Florida
4 orange Valencia
-----------------------------------
5 pear Garden
-----------------------------------
6 banana Chiquita
-----------------------------------
The script/answer to this question should display a bottom border under the entire row (of columns 'A', 'B' & 'C') for rows: 2, 4, 5, & 6.
The accepted answer to this original post provides the following script:
function onOpen() {
GroupMyData(); // trigger this function on sheet opening
}
function GroupMyData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1'); // apply to sheet name only
var rows = sheet.getRange('a1:g'); // range to apply formatting to
var numRows = rows.getNumRows(); // no. of rows in the range named above
var values = rows.getValues(); // array of values in the range named above
var testvalues = sheet.getRange('a1:a').getValues(); // array of values to be tested (1st column of the range named above)
rows.setBorder(false, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // remove existing borders before applying rule below
//Logger.log(numRows);
for (var i = 0; i <= numRows - 1; i++) {
var n = i + 1;
//Logger.log(n);
//Logger.log(testvalues[i] > 0);
//Logger.log(testvalues[i]);
if (testvalues[i] > 0) { // test applied to array of values
sheet.getRange('a' + n + ':g' + n).setBorder(null, null, true, null, null, null, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
}
};
That script that functions like so:
A border will appear along the bottom of each row where column A's cell has a number in it (and no letters), regardless of whether the number is the same as the one in the cell above it or different.
However the goal is for A to have text, and wherever consecutive text down column A changes from a repeated string to a differing string, there should be a border between the differing strings.
Thanks!
google-apps-script google-sheets google-sheets-api conditional-formatting
add a comment |
I am trying to do exactly what this other post is asking, but the accepted answer simply does not work. The original post was very clear, so here it is once more:
Excel apparently has this type of conditional formatting built-in: https://sites.google.com/site/techyhelp85/excel-tips/group-borders
I'd like to accomplish the same in Google Sheets via Google Apps Script. The following should demonstrate the before and after conditions:
Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
3 orange Florida
4 orange Valencia
5 pear Garden
6 banana Chiquita
Resulting Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
-----------------------------------
3 orange Florida
4 orange Valencia
-----------------------------------
5 pear Garden
-----------------------------------
6 banana Chiquita
-----------------------------------
The script/answer to this question should display a bottom border under the entire row (of columns 'A', 'B' & 'C') for rows: 2, 4, 5, & 6.
The accepted answer to this original post provides the following script:
function onOpen() {
GroupMyData(); // trigger this function on sheet opening
}
function GroupMyData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1'); // apply to sheet name only
var rows = sheet.getRange('a1:g'); // range to apply formatting to
var numRows = rows.getNumRows(); // no. of rows in the range named above
var values = rows.getValues(); // array of values in the range named above
var testvalues = sheet.getRange('a1:a').getValues(); // array of values to be tested (1st column of the range named above)
rows.setBorder(false, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // remove existing borders before applying rule below
//Logger.log(numRows);
for (var i = 0; i <= numRows - 1; i++) {
var n = i + 1;
//Logger.log(n);
//Logger.log(testvalues[i] > 0);
//Logger.log(testvalues[i]);
if (testvalues[i] > 0) { // test applied to array of values
sheet.getRange('a' + n + ':g' + n).setBorder(null, null, true, null, null, null, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
}
};
That script that functions like so:
A border will appear along the bottom of each row where column A's cell has a number in it (and no letters), regardless of whether the number is the same as the one in the cell above it or different.
However the goal is for A to have text, and wherever consecutive text down column A changes from a repeated string to a differing string, there should be a border between the differing strings.
Thanks!
google-apps-script google-sheets google-sheets-api conditional-formatting
add a comment |
I am trying to do exactly what this other post is asking, but the accepted answer simply does not work. The original post was very clear, so here it is once more:
Excel apparently has this type of conditional formatting built-in: https://sites.google.com/site/techyhelp85/excel-tips/group-borders
I'd like to accomplish the same in Google Sheets via Google Apps Script. The following should demonstrate the before and after conditions:
Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
3 orange Florida
4 orange Valencia
5 pear Garden
6 banana Chiquita
Resulting Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
-----------------------------------
3 orange Florida
4 orange Valencia
-----------------------------------
5 pear Garden
-----------------------------------
6 banana Chiquita
-----------------------------------
The script/answer to this question should display a bottom border under the entire row (of columns 'A', 'B' & 'C') for rows: 2, 4, 5, & 6.
The accepted answer to this original post provides the following script:
function onOpen() {
GroupMyData(); // trigger this function on sheet opening
}
function GroupMyData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1'); // apply to sheet name only
var rows = sheet.getRange('a1:g'); // range to apply formatting to
var numRows = rows.getNumRows(); // no. of rows in the range named above
var values = rows.getValues(); // array of values in the range named above
var testvalues = sheet.getRange('a1:a').getValues(); // array of values to be tested (1st column of the range named above)
rows.setBorder(false, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // remove existing borders before applying rule below
//Logger.log(numRows);
for (var i = 0; i <= numRows - 1; i++) {
var n = i + 1;
//Logger.log(n);
//Logger.log(testvalues[i] > 0);
//Logger.log(testvalues[i]);
if (testvalues[i] > 0) { // test applied to array of values
sheet.getRange('a' + n + ':g' + n).setBorder(null, null, true, null, null, null, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
}
};
That script that functions like so:
A border will appear along the bottom of each row where column A's cell has a number in it (and no letters), regardless of whether the number is the same as the one in the cell above it or different.
However the goal is for A to have text, and wherever consecutive text down column A changes from a repeated string to a differing string, there should be a border between the differing strings.
Thanks!
google-apps-script google-sheets google-sheets-api conditional-formatting
I am trying to do exactly what this other post is asking, but the accepted answer simply does not work. The original post was very clear, so here it is once more:
Excel apparently has this type of conditional formatting built-in: https://sites.google.com/site/techyhelp85/excel-tips/group-borders
I'd like to accomplish the same in Google Sheets via Google Apps Script. The following should demonstrate the before and after conditions:
Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
3 orange Florida
4 orange Valencia
5 pear Garden
6 banana Chiquita
Resulting Example Dataset
A B C
1 apple Macintosh
2 apple Granny Smith
-----------------------------------
3 orange Florida
4 orange Valencia
-----------------------------------
5 pear Garden
-----------------------------------
6 banana Chiquita
-----------------------------------
The script/answer to this question should display a bottom border under the entire row (of columns 'A', 'B' & 'C') for rows: 2, 4, 5, & 6.
The accepted answer to this original post provides the following script:
function onOpen() {
GroupMyData(); // trigger this function on sheet opening
}
function GroupMyData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet 1'); // apply to sheet name only
var rows = sheet.getRange('a1:g'); // range to apply formatting to
var numRows = rows.getNumRows(); // no. of rows in the range named above
var values = rows.getValues(); // array of values in the range named above
var testvalues = sheet.getRange('a1:a').getValues(); // array of values to be tested (1st column of the range named above)
rows.setBorder(false, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // remove existing borders before applying rule below
//Logger.log(numRows);
for (var i = 0; i <= numRows - 1; i++) {
var n = i + 1;
//Logger.log(n);
//Logger.log(testvalues[i] > 0);
//Logger.log(testvalues[i]);
if (testvalues[i] > 0) { // test applied to array of values
sheet.getRange('a' + n + ':g' + n).setBorder(null, null, true, null, null, null, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
}
};
That script that functions like so:
A border will appear along the bottom of each row where column A's cell has a number in it (and no letters), regardless of whether the number is the same as the one in the cell above it or different.
However the goal is for A to have text, and wherever consecutive text down column A changes from a repeated string to a differing string, there should be a border between the differing strings.
Thanks!
google-apps-script google-sheets google-sheets-api conditional-formatting
google-apps-script google-sheets google-sheets-api conditional-formatting
edited Nov 27 '18 at 19:06
asked Oct 29 '18 at 20:42
etudes
83
83
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
The Questioner refers to a previous Q&A which was based on evaluating a number. In the questioners case, the evaluation is based on a string.
I referred to the question noted by the Questionner. I also referred to How to compare strings in google apps script which contains a very elegant and efficient approach by Harold which I have carried through in this answer. This uses indexof
to detect new values, and so underlining can be linked with each new value.
function so53053492() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, LastColumn).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log(row+" is not referenced. Adding it");//DEBUG
// underline the previous row
var range = sheet.getRange((+i + 1), 1, 1, 2).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, LastColumn).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// Logger.log(ListofFruits);// DEBUG
}
UPDATE - Accounting for Headers
The previous version assumed no headers. This version takes headers into account. There are several lines of code affected, but the key variable is headerRows
which allows the user to nominate the depth of the headers.
function so53053492_01() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet3");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
var NumColumns = sheet.getMaxColumns();
// allow for headers
var headerRows = 2;
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, NumColumns).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange((+1 + headerRows), 1, (LastRow - headerRows), LastColumn).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// Logger.log("Inside LOOP: i = "+i+", value = "+ row);// DEBUG
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log("Inside IF#1: i = "+i+", "+row+" is not referenced. Adding it");//DEBUG
// underline the previous row
if (i != 0) {
// This IF statement to avoid underlining the Header row
var range = sheet.getRange((+i + 1 + headerRows), 1, 1, NumColumns).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, NumColumns).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
//Logger.log(ListofFruits);// DEBUG
}
Screenshot showing headers:
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53053492%2fconditional-borders-in-google-sheets%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The Questioner refers to a previous Q&A which was based on evaluating a number. In the questioners case, the evaluation is based on a string.
I referred to the question noted by the Questionner. I also referred to How to compare strings in google apps script which contains a very elegant and efficient approach by Harold which I have carried through in this answer. This uses indexof
to detect new values, and so underlining can be linked with each new value.
function so53053492() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, LastColumn).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log(row+" is not referenced. Adding it");//DEBUG
// underline the previous row
var range = sheet.getRange((+i + 1), 1, 1, 2).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, LastColumn).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// Logger.log(ListofFruits);// DEBUG
}
UPDATE - Accounting for Headers
The previous version assumed no headers. This version takes headers into account. There are several lines of code affected, but the key variable is headerRows
which allows the user to nominate the depth of the headers.
function so53053492_01() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet3");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
var NumColumns = sheet.getMaxColumns();
// allow for headers
var headerRows = 2;
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, NumColumns).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange((+1 + headerRows), 1, (LastRow - headerRows), LastColumn).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// Logger.log("Inside LOOP: i = "+i+", value = "+ row);// DEBUG
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log("Inside IF#1: i = "+i+", "+row+" is not referenced. Adding it");//DEBUG
// underline the previous row
if (i != 0) {
// This IF statement to avoid underlining the Header row
var range = sheet.getRange((+i + 1 + headerRows), 1, 1, NumColumns).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, NumColumns).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
//Logger.log(ListofFruits);// DEBUG
}
Screenshot showing headers:
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
add a comment |
The Questioner refers to a previous Q&A which was based on evaluating a number. In the questioners case, the evaluation is based on a string.
I referred to the question noted by the Questionner. I also referred to How to compare strings in google apps script which contains a very elegant and efficient approach by Harold which I have carried through in this answer. This uses indexof
to detect new values, and so underlining can be linked with each new value.
function so53053492() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, LastColumn).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log(row+" is not referenced. Adding it");//DEBUG
// underline the previous row
var range = sheet.getRange((+i + 1), 1, 1, 2).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, LastColumn).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// Logger.log(ListofFruits);// DEBUG
}
UPDATE - Accounting for Headers
The previous version assumed no headers. This version takes headers into account. There are several lines of code affected, but the key variable is headerRows
which allows the user to nominate the depth of the headers.
function so53053492_01() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet3");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
var NumColumns = sheet.getMaxColumns();
// allow for headers
var headerRows = 2;
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, NumColumns).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange((+1 + headerRows), 1, (LastRow - headerRows), LastColumn).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// Logger.log("Inside LOOP: i = "+i+", value = "+ row);// DEBUG
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log("Inside IF#1: i = "+i+", "+row+" is not referenced. Adding it");//DEBUG
// underline the previous row
if (i != 0) {
// This IF statement to avoid underlining the Header row
var range = sheet.getRange((+i + 1 + headerRows), 1, 1, NumColumns).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, NumColumns).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
//Logger.log(ListofFruits);// DEBUG
}
Screenshot showing headers:
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
add a comment |
The Questioner refers to a previous Q&A which was based on evaluating a number. In the questioners case, the evaluation is based on a string.
I referred to the question noted by the Questionner. I also referred to How to compare strings in google apps script which contains a very elegant and efficient approach by Harold which I have carried through in this answer. This uses indexof
to detect new values, and so underlining can be linked with each new value.
function so53053492() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, LastColumn).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log(row+" is not referenced. Adding it");//DEBUG
// underline the previous row
var range = sheet.getRange((+i + 1), 1, 1, 2).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, LastColumn).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// Logger.log(ListofFruits);// DEBUG
}
UPDATE - Accounting for Headers
The previous version assumed no headers. This version takes headers into account. There are several lines of code affected, but the key variable is headerRows
which allows the user to nominate the depth of the headers.
function so53053492_01() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet3");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
var NumColumns = sheet.getMaxColumns();
// allow for headers
var headerRows = 2;
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, NumColumns).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange((+1 + headerRows), 1, (LastRow - headerRows), LastColumn).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// Logger.log("Inside LOOP: i = "+i+", value = "+ row);// DEBUG
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log("Inside IF#1: i = "+i+", "+row+" is not referenced. Adding it");//DEBUG
// underline the previous row
if (i != 0) {
// This IF statement to avoid underlining the Header row
var range = sheet.getRange((+i + 1 + headerRows), 1, 1, NumColumns).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, NumColumns).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
//Logger.log(ListofFruits);// DEBUG
}
Screenshot showing headers:
The Questioner refers to a previous Q&A which was based on evaluating a number. In the questioners case, the evaluation is based on a string.
I referred to the question noted by the Questionner. I also referred to How to compare strings in google apps script which contains a very elegant and efficient approach by Harold which I have carried through in this answer. This uses indexof
to detect new values, and so underlining can be linked with each new value.
function so53053492() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, LastColumn).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log(row+" is not referenced. Adding it");//DEBUG
// underline the previous row
var range = sheet.getRange((+i + 1), 1, 1, 2).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, LastColumn).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
// Logger.log(ListofFruits);// DEBUG
}
UPDATE - Accounting for Headers
The previous version assumed no headers. This version takes headers into account. There are several lines of code affected, but the key variable is headerRows
which allows the user to nominate the depth of the headers.
function so53053492_01() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet3");
// get key variables
var LastRow = sheet.getLastRow();
var LastColumn = sheet.getLastColumn();
var NumColumns = sheet.getMaxColumns();
// allow for headers
var headerRows = 2;
//erase any current formatting
var ClearRange = sheet.getRange(1, 1, LastRow, NumColumns).setBorder(false, false, false, false, false, false); // clear all formatting
// get the data
var data = sheet.getRange((+1 + headerRows), 1, (LastRow - headerRows), LastColumn).getValues();
// setup new array
var ListofFruits = new Array();
// Loop through the fruits (Column A)
for (var i in data) {
var row = data[i][0].toString();
// Logger.log("Inside LOOP: i = "+i+", value = "+ row);// DEBUG
// search for unqiue values
if (ListofFruits.indexOf(row) == -1) { // if value =-1, then the variable is unique
// Logger.log("Inside IF#1: i = "+i+", "+row+" is not referenced. Adding it");//DEBUG
// underline the previous row
if (i != 0) {
// This IF statement to avoid underlining the Header row
var range = sheet.getRange((+i + 1 + headerRows), 1, 1, NumColumns).setBorder(true, false, false, false, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
}
// continue to build array
ListofFruits.push(row);
}
}
// underline the last row of the fruits column
var range = sheet.getRange(LastRow, 1, 1, NumColumns).setBorder(null, null, true, null, false, false, "red", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
//Logger.log(ListofFruits);// DEBUG
}
Screenshot showing headers:
edited Nov 14 '18 at 1:18
answered Nov 13 '18 at 1:34
Tedinoz
6682816
6682816
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
add a comment |
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
This is close to perfect. I so appreciate the clarity of this code. Two small things I'm trying to adjust: (1) how do I get this to begin adding borders after a certain row number? ie. to ignore the first two rows, which are headers in my actual document. And (2) I'd like the border to span the full length of the row, no matter how many columns may exist. I see my original post didn't visualize that properly, will fix. I found the number that will change how many columns it spans in line 30, but ideally it wouldn't be a static number of columns that exist, which may change. Thanks!
– etudes
Nov 13 '18 at 7:12
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53053492%2fconditional-borders-in-google-sheets%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown