Borders when row has data but no border if empty - google-apps-script

I have a sheet that I want to dynamically add borders to filter results. I have it working where it adds the borders, but when i select another filter it keeps the rows with previous data borders. So if data set is smaller it has all empty borders under it. How would I fix this with this script?
function onEdit(ss) {
var classeur = SpreadsheetApp.getActiveSpreadsheet();
var ss = classeur.getActiveSheet();
var range = ss.getRange("A5:a"); // Modified
range.setBorder(false, false, false, false, false, false);
var values = range.getValues();
var offsetRow = range.getRowIndex(); // Added
for (var i = 0; i < values.length; i++) {
if (values[i][0]) { // Modified
ss.getRange("A" + (i + offsetRow) + ":P" + (i + offsetRow))
.setBorder(true, true, true, true, true, true, "black",
SpreadsheetApp.BorderStyle.SOLID_MEDIUM) // Modified
.setBackground('#FFFFFF');
}
}
}

Try this:
function onEdit(e) {
var sh=e.range.getSheet();
sh.getRange(1,1,sh.getMaxRows(),sh.getMaxColumns()).setBorder(false, false, false, false, false, false);
var range = sh.getRange(5,1,sh.getLastRow()-4,1); // Modified
range.setBorder(false, false, false, false, false, false);
var values = range.getValues();
for (var i=0;i<values.length;i++) {
if (values[i][0]) { // Modified
sh.getRange(i+5,1,1,16).setBorder(true, true, true, true, true, true, "black",SpreadsheetApp.BorderStyle.SOLID_MEDIUM).setBackground('#FFFFFF');
}
}
}
You cannot call this function from the script editor unless you supply the event object.

Related

Conditional borders troubleshooting (Google sheets)

I have a dataset with four different treatment types in blocks of 5 or 7 rows. I want to add borders between each treatment set, so I tried modifying Tedinoz's code. The problem is that this code only adds a border to unique values, and I want to add a border whenever the value is different from the previous row. How can I modify the if statement if (Treatments.indexOf(row) == -1) to search instead for rows whose value for 'Treatment' is different from the previous row?
Here is the full code:
function lineBetween() {
//setup spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// get key variables
var LastRow = 417
var LastColumn = sheet.getLastColumn();
var NumColumns = 8;
// allow for headers
var headerRows = 1;
//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 Treatments = new Array();
// Loop through treatments(Column C)
for (var i in data) {
var row = data[i][2].toString();
// Logger.log("Inside LOOP: i = "+i+", value = "+ row);// DEBUG
// search for unqiue values
if (Treatments.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, "black", SpreadsheetApp.BorderStyle.SOLID); // format if true
}
// continue to build array
Treatments.push(row);
}
}
// underline the last row of the treatments column
var range = sheet.getRange(LastRow, 1, 1, NumColumns).setBorder(null, null, true, null, false, false, "black", SpreadsheetApp.BorderStyle.SOLID_MEDIUM); // format if true
//Logger.log(Treatments);// DEBUG
}
[1]: https://stackoverflow.com/questions/53053492/conditional-borders-in-google-sheets
Try this:
function lineBetween() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getSheetByName("Sheet1");
sh.getDataRange().setBorder(false, false, false, false, false, false); // clear all formatting
let sr = 2;//data start row
const data = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn()).getValues();
data.forEach((r, i, arr) => {
if (i > 0) {
if (r[2] != arr[i - 1][2]) {
sh.getRange(i + sr, 1, 1, sh.getLastColumn()).setBorder(true, true, true, true, false, false);
}
}
});
}
Actually I think this works better for me:
function lineBetween() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sh = ss.getSheetByName("Sheet0");
sh.getDataRange().setBorder(false, false, false, false, false, false); // clear all formatting
let sr = 2;//data start row
const data = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn()).getValues();
let uA = [];
let dA = [];
data.forEach((r, i, arr) => {
if (i > 0) {
if (r[2] != arr[i - 1][2]) {
sh.getRange(i + sr, 1, 1, sh.getLastColumn()).setBorder(true, false, false, false, false, false);
}
}
});
}

Conditional formatting of borders in Google Sheets using Apps Script

I would like to add borders to cells in a Google Sheet using conditional formatting. I am aware that you cannot do this using the standard conditional formatting process in Google Sheets so I'm trying to get to grips with how to do it using a script.
I have copied a script from the following solution, and attempted to edit it for my needs: (Add border format to row if condition met in Google Sheets)
However, I am still coming to terms with how these scripts work and haven't yet been able to make this work as desired.
The desired effect is that for all rows 5 and higher, where A is not null, a border should be applied to all cells in columns A to M. The sheet is called 'Kit check list', and the script should be triggered any timean edit is made to the sheet.
Here is the my attempt so far
function onEdit() {
GroupMyData(); // trigger this function when edits are made
}
function GroupMyData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Kit check list'); // apply to sheet name only
var rows = sheet.getRange('A5:M'); // 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('a5:a').getValues(); // array of values to be tested (1st column of the range named above)
rows.setBorder(false, false, false, false, false, false, "black", SpreadsheetApp.BorderStyle.SOLID); // 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 + ':m' + n).setBorder(true, true, true, true, true, true, "black", SpreadsheetApp.BorderStyle.SOLID); // format if true
}
}
};
Unfortunately all it only resets the borders in the specified area, and does not apply a borders to the desired rows.
Any help with this would be much appreciated.
Try this:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == 'Kit check list') {
const sr = 5;
const rg = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn());
const vs = rg.getValues();
rg.setBorder(false, false, false, false, false, false, "black", SpreadsheetApp.BorderStyle.SOLID);
const numcolumns = sh.getLastColumn();
vs.forEach((r, i) => {
if (r[0]) {
sh.getRange(i + sr, 1, 1, numcolumns).setBorder(true, true, true, true, true, true, "black", SpreadsheetApp.BorderStyle.SOLID);
}
});
}
}
Demo:
Note: you cannot run this function without providing the event object which populates the e. The only reasonable way to test it is to set it up and save it and edit the sheet.
You might actually like it better this way:
function onEdit(e) {
const sh = e.range.getSheet();
if (sh.getName() == 'Kit check list') {
const sr = 5;
const rg = sh.getRange(sr, 1, sh.getLastRow() - sr + 1, sh.getLastColumn());
const vs = rg.getValues();
//rg.setBorder(false, false, false, false, false, false, "black", SpreadsheetApp.BorderStyle.SOLID);
const numcolumns = sh.getLastColumn();
vs.forEach((r, i) => {
if (r[0]) {
sh.getRange(i + sr, 1, 1, numcolumns).setBorder(true, true, true, true, true, true, "black", SpreadsheetApp.BorderStyle.SOLID);
} else {
sh.getRange(i + sr, 1, 1, numcolumns).setBorder(false, false, false, false, false, false, "black", SpreadsheetApp.BorderStyle.SOLID);
}
});
}
}
Your script works fine. I just fixed one line.
Instead of this:
var n = i + 1;
You need:
var n = i + 5;
Here is the code:
function onEdit() {
GroupMyData(); // trigger this function when edits are made
}
function GroupMyData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Kit check list'); // apply to sheet name only
var rows = sheet.getRange('A5:M'); // 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('A5:A').getValues(); // array of values to be tested (1st column of the range named above)
rows.setBorder(false, false, false, false, false, false, "black", SpreadsheetApp.BorderStyle.SOLID); // remove existing borders before applying rule below
for (var i=0; i <= numRows-1; i++) {
var n = i + 5;
//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 + ':M' + n).setBorder(true, true, true, true, true, true, "black", SpreadsheetApp.BorderStyle.SOLID); // format if true
}
}
};
without any script, you can do it by first using conditional formatting in MS Excel, then importing the workbook into google sheets ! weird ...

Deleting empty rows within a table

I am new to Google Apps Script script writing and trying to self teach by starting off making a generic table. So far I have:
made a header;
changed the background;
changed the font;
added data validation;
added thick outside borders as well as other borders
and keeping a maximum of five rows and columns at any one time
My question is:
How do I remove empty rows in a data range? I have tried multiple methods so far but I like to have the top row as a border so don't want to delete that. This is the script I have written so far
function formatScriptLearning1() {
var ScriptLearning = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Script learning 1");
var Header = ScriptLearning.getRange("B2").getDataRegion(SpreadsheetApp.Dimension.COLUMNS);
var LastRow = ScriptLearning.getLastRow();
var MaxRows = ScriptLearning.getMaxRows();
var LastColumn = ScriptLearning.getLastColumn();
var MaxColumns = ScriptLearning.getMaxColumns();
var Range = ScriptLearning.getRange(2, 2, LastRow - 1, LastColumn - 1);
var Outside = Range
var DataVal = ScriptLearning.getRange(3, 7, LastRow - 1, 1);
var validation = SpreadsheetApp.newDataValidation().requireValueInList(['Yes', 'No'], true).build();
var RemainingRows = ScriptLearning.getRange(LastRow + 1, 7, MaxRows);
var RemainingColumns = ScriptLearning.getRange(2, LastColumn + 1, 1, 5);
Range.setBorder(true, true, true, true, true, true, null, SpreadsheetApp.BorderStyle.SOLID);
Outside.setBorder(true, true, true, true, true, null, null, SpreadsheetApp.BorderStyle.SOLID_MEDIUM);
Header.setBorder(true, true, true, true, true, true, true, SpreadsheetApp.BorderStyle.SOLID_MEDIUM);
Header.setFontSize(11).setBackground("#ea9999").setFontWeight("Bold").setFontLine("Underline").setFontFamily("Georgia");
if (MaxRows - LastRow != 0) {
ScriptLearning.deleteRows(LastRow + 1, MaxRows - LastRow);
}
if (MaxColumns - LastColumn != 0) {
ScriptLearning.deleteColumns(LastColumn + 1, MaxColumns - LastColumn);
}
DataVal.setDataValidation(validation);
ScriptLearning.insertRowsAfter(LastRow, 5);
ScriptLearning.insertColumnsAfter(LastColumn, 5);
RemainingRows.clearDataValidations().clearFormat();
RemainingColumns.clear();
Any help would be greatly appreciated!
function removeEmptyRows() {
const ss=SpreadsheetApp.getActive();
const sh=ss.getActiveSheet();
const rg=sh.getDataRange();
const vs=rg.getValues();
let d=0;
vs.forEach(function(r,i){if(r.join('').length==0) {sh.deleteRow(i+1-d++);}});
}

How to Clear all row range rows

I would like to know how to clear the contents of all lines that are being hidden through this code, specifically in the two IFS.
I tried to include this excerpt:
ss.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});}
but it is only cleaning the contents of the selected cell itself
function remcausa() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var cell=sh.getActiveCell();
var row=cell.getRow();
if (row<47) {
sh.hideRows(row + 0, 4);ss.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});}
else { if(row>50) {sh.hideRows(row -1, 4)};
ss.getActiveRangeList().clear({contentsOnly: true, skipFilteredRows: true});}
}
the expected result would be to clear the contents of all the lines being hidden.
Thanks
How about this?
function remcausa() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var cell=sh.getActiveCell();
var row=cell.getRow();
if (row<47) {
sh.hideRows(row, 4);
sh.getRange(row,1,4,sh.getLastColumn()).clearContent();
}else if(row>50) {
sh.hideRows(row-1, 4);
sh.getRange(row-1,1,4,sh.getLastColumn()).clearContent();
}
}

Borders to cells on the same line

I have a script to create cell borders when they are not empty:
function checkRange2(ss) {
var classeur = SpreadsheetApp.getActiveSpreadsheet();
var ss = classeur.getActiveSheet();
var range = ss.getRange("B5:B100");
range.setBorder(false, false, false, false, false, false);
var values = range.getValues();
for (var i = 0; i < values.length; i++) {
for (var j = 0; j < values[i].length; j++) {
if (values[i][j] !== "") {
range.getCell(i + 1, j + 1).setBorder(true, true, true, true, true, true)
.setBackground('#FECB8D');
}
}
}
}
I wish that when the cell, B5 for example, contains a text, the range B5: E5 is with borders. And others lines too. Is it possible?
Cordially.
How about this modifications? I don't know whether I could understand what you want to do. If I misunderstand your question, please tell me. I would like to modify them.
In this modified script, at first, it retrieves the values of B5:E100. When strings are included in column B, the borders are given to cells from column B to column E for the row. For example, when a cell B5 has strings, the cells of "B5:E5" is surrounded by the borders.
Modification points :
When the column B is evaluated for the values retrieved from the range of B5:B100, it can be done as if (values[i][0]) { using one time of "for loop".
In this modified script, the range of B5:E100 is used. The values retrieved this range can be also evaluated by if (values[i][0]) {.
When you want to use the borders for the range of B5:E5, you can achieve this using range.setBorder().
At the script, the range is defined using the a1Notation obtained by adding offsetRow.
Modified sample :
function checkRange2(ss) {
var classeur = SpreadsheetApp.getActiveSpreadsheet();
var ss = classeur.getActiveSheet();
var range = ss.getRange("B5:E100"); // Modified
range.setBorder(false, false, false, false, false, false);
var values = range.getValues();
var offsetRow = range.getRowIndex(); // Added
for (var i = 0; i < values.length; i++) {
if (values[i][0]) { // Modified
ss.getRange("B" + (i + offsetRow) + ":E" + (i + offsetRow)).setBorder(true, true, true, true, null, null) // Modified
.setBackground('#FECB8D');
}
}
}
Note :
If you want to give the borders to all cells, please use .setBorder(true, true, true, true, true, null).
In your case, the borders are given to one row. So the last parameter of setBorder() can use null.
Reference :
setBorder()
If I misunderstand your question, I'm sorry.