Force conditional formatting apply - google-sheets

I have a google spreadseet table with conditional background formatting rules on it. I also have a function that autosort sheet when user change a cell (it's a list of tasks with priorities). Unfortunately, the autosorting can somehow set a wrong background for cells which can be fixed manually by selecting a column and then clicking "background->reset parameters" button. I need to do the same with script automatically to keep correct backgrounding of cells. How do I force google-spreadsheet to re-render cells with its conditional formatting rules?
Autosorting function:
function onEdit(event){
var sheet = event.source.getActiveSheet();
var editedCell = sheet.getActiveCell();
var columnToSortBy = 1;
var tableRange = "A2:Z1000";
if(editedCell.getColumn() == columnToSortBy){
var range = sheet.getRange(tableRange);
range.sort( { column : columnToSortBy, ascending: false } );
// code below doesn't help to solve the problem:
//var statusRange = sheet.getRange("B2:B1000");
//statusRange.clear({formatOnly: true})
//statusRange.clearFormat();
//SpreadsheetApp.flush()
}
}

What is possibly happening is that you have applied conditional formatting to a range of cells.
When your sheet is sorted by a script some/all of the cells may be affected because the range the conditional formatting applies to is being moved.
I will try to answer your question but I think you may be looking at the problem from the wrong angle. Given that your table is huge, entire page except header row? You could be applying the conditional formatting incorrectly. If it is acting on the whole page then reordering the page should not affect it. I have seen similar problems when rows are added or deleted within a formatting range. So if you want to post your formatting rules I may spot something there.
Getting back to your questions.
var range = sheet.getRange(tableRange); is correct.
I don't think you can use
statusRange.clear({formatOnly: true})
statusRange.clearFormat();
because .clear and .clearFormat are applied to the sheet.
Your table looks like it is taking up the entire sheet except for a header row? If so then try.
sheet.clearFormat();
This will clear your sheet formats so you are now left with white background colour.
Now, I do not know any way of using a script to set conditional formatting rules directly. I do have two possible solutions that I have used myself.
Abandon conditional formatting and set the format you want with a script.
You can set various cell formats directly, one of the the Background colour.
I don't know hoe you want to do this, your logic, but there are several functions to do this with CSS or RGB or to set a range to different colours.
When you have selected your cell or range you can use
range.setBackground("red");
red can be replaced with notation e.g. '#ff0000'.
Use a hidden conditional formatting template .
After your header row create another row. So adjust your table range to
var tableRange = "A3:Z1000";
Now row 2 becomes your template. Set the conditional formatting rules you want in row 2 and hide the row. Don't clear the formatting, instead copy the format form row 2 over the page.
var sheet = event.source.getActiveSheet();
var source = sheet.getRange(2,1,1,26); // Gets row 2
source.copyFormatToRange(sheet, 1, 26, 3, 1000); // will repeat down rows.

Related

Google Sheets: Conditional Formatting in Cell based on TEXT in another Cell, Not Number Value

How do I create a conditional formatting rule in Google Sheets that changes the colour of a cell based on the text in another cell?
I want to create a rule whereby if I type "tested" in ANY cell, the two following cells in the row change colour automatically to show the testing window.
The sheet is very large so I need to also know how to make this rule apply to all cells, without all formatting relating to the text in just one cell - it always needs to be the cell with the text relating to the following two cells in the row.
Thanks in advance!
I've tried to use the basic conditional formatting, and tried googling, but all answers are based on a number value and don't apply when I try to use the same custom formula.
try:
=A1="tested"
and 2 rules. one for B1:Z and 2nd for C1:Z

Google sheets - Relative conditional format based on cell above

I search in the deepest parts on the internet for a google sheets relative conditional formating based on the cell above value, which means, that whenever i add a new value in the cell below, it will automatically check the cell above value and format the cell according to it.
I've finally came to the solution explained below.
The result will be something like this:
I hope it works for you, weary traveller.
Select the range of cells that you want to format.
Go to >Format > Conditional Format > Add rule.
Under format rules select the option "Custom Formula is".
Paste the next formula if you want to check that your current cell is BIGGER THAN the cell above: =INDIRECT(ADDRESS(ROW();COLUMN())) > INDIRECT(ADDRESS(ROW()-1;COLUMN()))
OR the next formula if you want to check that your current cell is LOWER THAN the cell above: =INDIRECT(ADDRESS(ROW();COLUMN())) < INDIRECT(ADDRESS(ROW()-1;COLUMN())).
Select the color you like to apply, and click in DONE.
If the range of cells is A2:G, this rule will also work:
=AND(A2<>"",A2<A1) [RED]
=AND(A2<>"",A2>A1) [GREEN]

How to (pre)format the (empty) cells of a Google Sheet so that the formatting sticks?

I want all cells of a Google sheet to be formatted identically (same font, same font size, same wrapping, same alignment). However, even if I select the whole sheet and set all formatting values, every time I enter a new value in an empty cell (sometimes copy-pasted from web pages, sometimes typed), the 'preset' formatting specs seem to have been lost and I must respecify them. Does someone know of a way to make the preformatting stick?
Copying and pasting the usual way brings with it the formatting of the source as best as Sheets can manage. Instead of using "Paste" or Ctrl-V, use "Paste Special" (Ctrl-Alt-V). A small clipboard icon will appear to the lower right of the on-screen paste area. Click it and choose "Paste values only."
This must be done even if you paste from one sheet within Google Sheets to another. If you just paste the regular way, it not only brings in the formatting of the source sheet, it breaks up any existing conditional formatting ranges you have in place.
Try using CTRL+SHIFT+V to paste. Doing so will only paste the copied value to the sheet without affecting the formatting.
Potential workaround:
With Apps Script you can run a simple onEdit() trigger to run every time an edit is made on the sheet. So you could use this to run a script that changes the format of cells every time an edit is made.
This would involve getting the whole data range and getting the rich text values of each cell, making a copy of the rich text value object and modifying it with the RichTextValueBuilder. This is turn involves copying and modifying the TextStyle with the TextStyleBuilder.
The wrapping and alignment are set on the whole range with setWrap(isWrapEnabled) and setHorizontalAlignment(alignment).
Example
function onEdit() {
// initialize main variables
let file = SpreadsheetApp.getActive();
let sheet = file.getSheetByName("Sheet1"); // change to your sheet name
let range = sheet.getDataRange();
// This sets the whole range wrap and alignment
range.setWrap(true);
range.setHorizontalAlignment("center")
// Get the rich text values in a 2D array
let richTextValues = range.getRichTextValues();
// Two map functions to return the modified 2D array.
let newRichTextValues = richTextValues.map(row => {
return row.map(cell => {
// Gets the text style from the richText value
let style = cell.getTextStyle()
// Copy the text style and set the bold, font and size
let styleCopy = style.copy()
.setBold(true)
.setFontFamily("Comfortaa")
.setFontSize(11)
.build();
// Set the new rich text value
let newRichTextValues = cell.copy()
.setTextStyle(styleCopy)
.build();
return newRichTextValue
})
})
// Set the whole range to the rich text value.
range.setRichTextValues(newRichTextValues)
}
This should work as-is by copying this into the script editor, trying to run it once from there to get the authorizations done, and then editing your sheet. Remember to add in your sheet name.
Demonstration
This is what it looks like in action:
In this example, I used
Text wrapping as on.
Center alignment
Bold text
"Comfortaa" font
11 font size
You should change these attributes to the ones that you want. There are other attributes available to customize too.
As you can see, it could get a bit tricky if you need to exclude certain ranges, but this is absolutely possible depending on your exact use case.
It should also be mentioned that this is quite an inefficient approach, as it gets the whole range and updates everything. Ideally you want to identify the exact changes and update those, but again, this depends on your exact use case. To get the range that was modified with an onEdit trigger you can use the Event object.
References
simple onEdit() trigger
RichTextValue
RichTextValueBuilder
TextStyle
TextStyleBuilder
setHorizontalAlignment(alignment)
setWrap(isWrapEnabled)
Event object

Google Sheets: Conditionally Shade an Individual Set of Repeating Groups of Cells Based on Value

I have a Google Sheet I use to document my quotes for customers. I've copied and pasted it down the sheet several times. Within each quote is a list validated field where the options are "Won" or "Lost." When I select "Won," I want to turn that background color of JUST that quote green. However, I also only want to shade green the fields that I am not entering text into or accomplishing the calculations on (the data fields); I want to shade the background of the "form" and the "labels." (See screenshot where I did this by hand.)
I've attempted do this myself, but I'm having two issues.
I have to create separate conditional format rules for each quote/group of cells. This is tedious. I'd like, if possible, to create one rule that is able to adapt the conditional test of ="Won" to each group/quote separately.
I have to individually select each and every cell to be highlighted because if I just do A1:G33, all of the cells change color, even the ones in black and gray. I know this is expected, but is there a way around it?
I'm confused why applying the rule to the first group and copying and pasting it doesn't work. All of the quotes change green if the first quote shows "Won." This functionality works correctly with the built-in conditions that test the value of the cell itself. However, custom formulas to test the value of another cell don't "repeat" and operate individually it seems.
EDIT: Link to spreadsheet: https://docs.google.com/spreadsheets/d/1OH16NXLiRzY3-EdZaxmUl5Vp6cQNPzY-_-LV7VIDl8U/edit#gid=983650786
in your case perhaps best would be to color the first table exactly as you wish and then select it, copy it, select the first cell of the next table and:
Use Apps Script
This way you can have a lot of flexibility and its easier to manage.
You seem to already have an onEdit trigger, so you could integrate some more logic into that to test for statues. I can't implement everything you want but this should get you well on the way.
function onEdit(e){
// Getting the information on the edited cell
let editedCell = e.range;
let sheet = editedCell.getSheet()
// If the edited cell is in column 6, in "Quotes" and is value "Won"
if (editedCell.getColumn() == 6 && sheet.getName() == "Quotes" && editedCell.getValue() == "Won") {
// Get the row to know where to change the format
let statusRow = editedCell.getRow();
// Get the range of the whole form
let formRange = sheet.getRange(statusRow, 3, 17, 6)
// Set the background color
formRange.setBackground("green")
}
}
Hopefully you can see how you might extend this to include other ranges. You would need to base everything of the position of the edited cell. I have identified it by its column, the sheet that contains it, and its value. You can extend this to include checks on the value next to it for example. Then to change the color of each black box, you would need to define a range for each, relative to the edited cell.
References
setBackgroundColor
getRange

How To Detect Which Cells Are Merged In Google Sheets

While trying to remove duplicate phone numbers from a relatively large list I recently combined, Google Sheets presented me with this error message:
There was a problem.
Your selection contains a merged cell. To remove duplicates, all cells must contain the same number of rows and columns.
The formula I used to test and try to expose merged cells within Google sheets was:
=if(columns(A2:F2) = 6, "True", "False")
But this always returned true Because even though the cells may be merged they are still considered individual cells.
I am wondering if there is an easy way to discover and sort out these cells in Google Sheets. Excel used to have a very simple way of doing it but has since removed the functionality.
Any ideas?
if you have such an option you can use Conditional Formatting to check for merged cells like:
=MOD(COLUMN(),2)=0
where you can immediately spot merged cells where the color pattern is interrupted
in the same manner you can use this formula for rows:
=MOD(ROW(),2)=0
or you can play with scripts to find merged cells: https://issuetracker.google.com/issues/36753230
Custom formula
function isMerge(sheetName, a1Notation) {
var range = SpreadsheetApp.getActive().getSheetByName(sheetName).getRange(a1Notation);
var merges = [];
for (var i = 0; i < range.getHeight(); i++)
{
var merge = range.offset(i, 0, 1, 1).isPartOfMerge();
merges.push(merge);
}
return merges;
}
Usage:
Paste the code above to the Editor: menu Tools > Script Editor...
Save Project
Use as usual formula: =isMerge(sheetName, a1Notation)
you can copy and paste the column somewhere, for example creating an extra column next to it.
You can then create a new column. You can run increasing numbers in both and subtract each cell from each other. If the result is not 0, then cells have been merged.
I was facing a similar issue and found a hack - ctrl+shift+down button to select all the data in the column. This automatically became a selection of two columns (the one I want to select plus the one next to it). I then worked from the bottom of the list up, using ctrl+shift+down button to select all data in that column, starting from the bottom 20 entries - with this, only data in that column was select - it didn't automatically include the next row too, which meant that the merged cell was not within these cells.
I repeated this step, going up the rows ~50 rows at a time, until the selection suddenly became two rows instead, when I was actually just selecting a single row's data. This meant that the merged cell was somewhere in the last 50 rows, and I just went down the list within that selection to check for the merged cell.

Resources