Clear and Set Conditional Formatting Rules to a Specific Range in Google Sheets with Apps Script

I’ve created a small (pseudo) class that more easily clears and creates conditional formatting rules in a Google Sheet tab with Google Apps Script.

Why?

Well in Google Apps Script, conditional formatting rules are all or nothing.

You can only ever set, get or clear ALL rules in a specified Google Sheet tab.

So if you add a single rule to a sheet tab, all existing rules will be removed.

This means that each time you need to clear a rule or a portion of a rule or add in a new rule, you need to rebuild the entire rule set for that sheet tab.

It is an unpleasant experience.

The script below simplifies this process into some common clear and create processes for your conditional formatting.

Let me know in the comments below if you have a suggestion for another method for the class.

One last thing.

If you want to understand what is going on with the code (You are my kind of peeps), check out the video tutorial series.

The Code: Range_ConditionalFormatting()

To add this script to your own projects, I recommend that you create a new Google Apps Script file (page) and paste the code in there.

Check out the chapters below on how to use the class.

Note! Square brackets around parameters indicate optional parameters.

Class

The pseudo-class Range_ConditionalFormatting(sheet) tales one argument:

Video link: Range_ConditionalFormatting(sheet) 

Methods

Method Return Type
clearRule()
Clears a rule or rules by a single range or array or ranges, based on 3 clearing approaches.
setRule()
Sets a rule or rules while maintaining the existing rules in the Sheet tab.

clearRule(rangeOrRanges, [clearType])

Clears the conditional formatting rules in a Google Sheet tab by the selected range or ranges and clear type while maintaining the existing conditional formatting rules in the Google Sheet tab.

Video link: clearRule method

Parameters

Name Optional Type Description
rangeOrRanges Range or Range Array A SpreadsheetApp.Range or array of ranges that will be the target locations to clear.
clearType Number The way the method should clear the range (see below)

Default is clearType = 0

Clear types

  • 0 – Clears any conditional formatting rule that exactly matches the range.
  • 1 – Clears any conditional formatting rule that has a range within the target range.
  • 2 – Clears any conditional formatting rule or portions of the range of a rule that overlap the target range.

Examples

clearRule(range) – Single range and no optional clear type

Clears a conditional formatting range that exactly matches the single range provided.

Video link: clearRule(ranges) – Ranges and no optional clear type

clearRule(ranges) – Multiple ranges and no optional clear type

Clears the conditional formatting that exactly matches multiple ranges.

 

clearRule(range, clearType = 0) – Single range with clear type zero- Exact match

Clears a conditional formatting range that exactly matches the array of ranges provided. Clear type zero (0) is the default clear type.

Video link: clearRule(ranges, 0) – Exact match

clearRule(ranges, clearType = 0) – Multiple ranges with clear type zero – Exact match

Clears the conditional formatting that exactly matches multiple ranges.

clearRule(range, clearType = 1) – Single range with clear type one – Within range

Clears a conditional formatting rule range that has a range equal to or within the target range.

Video link: clearRule(ranges, 1) – Within range

clearRule(ranges, clearType = 1) – Multiple ranges with clear type zero- Within range

Clears all conditional formatting rule ranges equal to or within the target array of ranges.

clearRule(range, clearType = 2) – Single range with clear type one – Overlaps

Clears a conditional formatting rule range that has a range equal to or within the target range or rebuilds the range where any range overlaps the target range removing that portion of the range.

Video link: clearRule(ranges, 2) – Overlapping ranges

clearRule(ranges, clearType = 2) – Multiple ranges with clear type zero- Overlaps

Clears all conditional formatting rule ranges equal to or within the target array of ranges or rebuilds the range where any range overlaps the target range removing that portion of the range.

setRule(rules, [position])

The setRule method adds a conditional formatting rule or rules to an existing Google Sheet tab. It does not remove any existing rules in the selected tab.

The method has an optional position parameter that allows the user to customise where they wish to order the rule in relation to the existing rules on the Sheet tab.

Video link: setRule method

Parameters

Name Optional Type Description
rules Conditional Formatting Rules A

array of objects. This is an array of rules built with the Apps Script conditional formatting rule builder.

position Number The position of the new rule in the existing set of rules.

Default is position = -1, or the bottom of the rules array.

A position of zero (0) sets the rule to the top of the array set.

Positive numbers apply position up to max length of the rule set.

-1 for end of the rule

Rules with negative numbers are position from the last rule in reverse order up to zero.

Examples

Video Tutorial Series

You can check out the playlist for Conditional formatting here.

Apps Script – Google Sheets Conditional Formatting Playlist

The video tutorials:

  1. Clear Conditional Formatting Rules by Exact Match in Google Sheets with Apps Script
  2. Clear Conditional Formatting Rules Within a Range in Google Sheets with Apps Script
  3. Clear Conditional Formatting Rules that Overlap a Target Range in Google Sheets with Apps Script
  4. Add Conditional Formatting Rules to a Google Sheet Tab with Apps Script

Conclusion

Being such a short pseudo-class it is hardly worth slowing down your script by making this into a library. I recommend you just add it to your existing project for simplicity and performance.

If you think there are any other methods worth adding, please let me know in the comments.

I would also love to hear how you used this in your own projects.

Create and Publish a Google Workspace Add-on with Apps Script Course

Need help with Google Workspace development?

Go something to solve bigger than Chat GPT?

I can help you with all of your Google Workspace development needs, from custom app development to integrations and security. I have a proven track record of success in helping businesses of all sizes get the most out of Google Workspace.

Schedule a free consultation today to discuss your needs and get started or learn more about our services here.

~Yagi.

A custom-build HTML Time Input Element

Recently while working on a project, I found that the standard HTML Time Input field (see below) wasn’t sufficient for my needs.

<input type="time" id="setTime" name="setTime" />

Standard HTML time input field
Standard HTML time input field

I needed users to be able to input 24hr time right down to the milliseconds. Something like this:

Custom HTML Time Input Field
Custom HTML Time Input Field

Features

Mobile Input will display the number  pad

Under the hood, each input field is a number. This means that mobile devices should default to the number pad for convenience.

Value retrieval

Values are stored under the name time-<<timeType>> , for example time-hours.

You can loop over your form data and retrieve the names as needed or set a custom ID to the field as you create it dynamically with JavaScript. You can see an example of this in the Example 1: Single time field section.

Automatically moves to the next inputCustom HTML Time Input Field setting field character limits

Setting field character limitsSetting character limits on each time field allows the cursor to automatically move to the next fields.

Client-Side Validation

Removing ‘Accepted’ number input characters that are not numbers

Yeah, yeah, you know you got to validate server-side too, but it’s good to let the user know that if they accidentally put in an accepted number character like e, +, - that it will be removed for them automatically.

Cannot exceed the number range

The max and min number ranges are set by default, but you can always change them manually.

Maybe you want to start with minutes, but as a duration and not a time, have minutes that go all the way up to 10,000. All good, just change the max value in the time-minute number input.

If a user puts in a number greater or less than the default min or max, the number will be replaced by the min or max respectively.

So for example, if the user sets 69 (hur hur hur) minutes but the max minutes is 60 then the field will default to 60.

Likewise, if the user sets the millisecond cell to 2 but your min is 500, then it will default to 500 milliseconds.

This is done with some JavaScript event listeners.

Returning back a tab will clear the field

Returning back a tab by cursor or shift-tab will clear out the field for the user to start afresh.

Prepends Zeros (0) to Any Number Not At Max Character Length

This is just an aesthetic thing, but it makes a difference. When a number’s character length is less than the maximum character length, then additional zeroes will be added to the front of the number.

Quickly add or remove a time input

The values of the time inputs are formatted using a generated CSS method for number inputs within the timeInput class. Further event listeners are looped over this class to allow for fewer or greater number-input elements.

As such, you can add days, months and years or, nanoseconds, microseconds and zeptoseconds. Alternatively, you could remove one of the existing time measures from the field.

The Code for the Custom Time Input field

You can grab a basic sample of the code here:

Example 1: Single time field

In this simple example, we will encapsulate the time input into a form and add a ‘submit’ button. Of course, you can add other form elements to the form as well.

In our script section, we added two functions submitForm() and getFormData() that is called on submit and retrieve all values in the form by their ‘name’ attribute.

I’ve put the submit button outside the form so you can see the logged results. If you wish to refresh the page or move to another page you can add the submit button inside the form.

Custom HTML Time Input Field inside a form with logged values
Custom HTML Time Input Field inside a form with logged values

Check out the updated code:

 

Example 2: Multiple time fields

What if we want to have multiple instances of the custom time input in our HTML?

In this example, we will have a start and end time. Notice that we will need to change the name each time slightly so that the value is stored.

As such, in the example we append -start and -end to the input fields.

Yeap, that’s all you need to do.

Multiple Custom HTML Time Input Fields inside a form with logged values
Multiple Custom HTML Time Input Fields inside a form with logged values

Check out the updated code:

Example 3: Build Multiple HTML Custom Time Input fields dynamically with JavaScript

In this final example, we want to dynamically create time input fields equal to the number of tests we have. We will do this with the createTimeHanlder() function.

Next, we will add the HTML for the custom time input into a template literal (A string with inputs) and then add a name and append a counter to the name tags of each number input element.

Dynamically create Multiple Custom HTML Time Input Fields inside a form with logged values
Dynamically create Multiple Custom HTML Time Input Fields inside a form with logged values

Here’s the updated code:

 

Conclusion

That’s it. I would love to hear how you used this in your own projects and what modifications you made. Let me know in the comments.

I am actually using this for a project for a Google Workspace Add-on using Google Apps Script along with an accompanying hosted private site using Golang, SQLite, temple and HTMX.

Have fun!

If you have found the tutorial helpful, why not shout me a coffee ☕? I'd really appreciate it.

Setup Google Apps Script Word Completion in Sublime Text

When working on Google Apps Script projects locally with CLASP, it can be handy to have text completion for the Apps Script classes and methods.

I’m currently shopping for a new IDE or text editor (the developer’s existential crisis) and have decided to pick up Sublime Text again after a 9-year hiatus after a mediocre three-week trial of Neovim.

After a fresh install of Sublime Text 4 here is what I needed to do:

Requirements

  • Sublime Text 4 …  I mean… c’mon.
  • NPM to install CLASP and the text completion package.
  • CLASP – The command line Apps Script tool for local development.
  • Git (possibly) – If the TypeScript Sublime package is missing, you must install it via Git.

Setup

Google gracefully created a text completion package that uses Definitely Typed a TypeScript repository for type definitions that can be used with both TypeScript and vanilla JavaScript.

Install the TypeScript Package for Sublime Text

Check for the TypeScript Package

First, we check if the TypeScript package has been added to Sublime Text.

Select ctrl shift P (cmd ⌘ should replace ctrl for Apple) to get the Command Pallete and start typing: Package Control: List Packages and select it.

Sublime 4 Package control list
Sublime 4 Package control list

If the TypeScript package is present, move on to adding the Apps Script type package.

Add the TypeScript Package

Head back to the Command Pallete ( ctrl shift P ) and this time start typing Package Control: Install Package.

This will load the Sublime package. Search for ‘TypeScript’. The name must be exact. If it is in the package list (It wasn’t for me) install it and move on to adding the Apps Script type package installation.

If the package is not on the list we will need to use git to clone the package from the Windows GitHub repo for the TypeScrpt-Sublime-Plugin.

Linux

Windows

Mac

 

You may need to close and reopen Sublime Text to see the effects.

Install the Google Apps Script Type Package

In your terminal or shell, run the following:

npm install --save @types/google-apps-script

This will install the autocomplete types for all of the Google Apps Script Classes and Methods.

Testing the Google Apps Script text completion in Sublime Text

Go ahead and open Sublime Text and create a JavaSript *.js file or TypeScirpt *.ts file.

Navigating Autocomplete

Start typing a Google Apps Script class like SpreadsheetApp. You should see it appear in the list.

You can use the up-down (↑↓) arrow keys to navigate the list and enter to select the method or class.

Sublime 4 Google Apps Script Autocomplete selecting a method or class
Sublime 4 Google Apps Script Autocomplete selecting a method or class

Tooltips – Method argument instructions

Information for each method should appear as you enter the braces.

Sublime 4 Google Apps Script Autocomplete

Hovering over the method or class will reveal similar information.

Alt , will open the tooltip when the cursor is within the parentheses of the method.

Look at Multiple Arguments or tooltips

When there are multiple argument types, then you can click on the number to select from the list of types.

Sublime 4 Google Apps Script Autocomplete multiple argument types selection
Sublime 4 Google Apps Script Autocomplete multiple argument types selection

Or you can use the keyboard shortcuts:

Alt , – to open the tooltip if it is not available

Alt ↑ or Alt ↓ – to navigate to the next tooltip for the method.

Rename a Variable, Class or Function

Ctrl T Ctrl M – With your cursor over a variable, class, method or function you can rename it and all occurrences of it.

Formatting

You can also use the TypeScript plugin to format your document.

Ctrl T Ctrl F Formats the whole document

Ctrl T Ctrl F Formats the selection

Ctrl ; Formats the line

 

You can learn more shortcuts from the TypeScript Plugin for Sublime Text docs.

Getting *.gs files to display autocomplete

Sometimes we use the gs file ending for Google Apps Script files. To get these to autocomplete we need to pair them to either JavaScript or TypeScrit.

In Sublime Text first create any .gs file and ensure you are open in that file.

Then, go to View -> Syntax -> Open all with current extension as … . 

Select either JavaScript or TypeScript.

Now, when you edit the file, the Apps Script autocomplete will work as expected.

Conclusion

I’m not sure if I am going to stick with Sublime Text, but it is like slipping on a comfy pair of shoes after such a long break from it, so who knows?

I’d love to hear in the comments if you have used Sublime Text recently or are even using it for your own Apps Script projects. What do you love and not so love about it?

Oh, by the way, I recently built a little CLI tool to help update multiple Google Apps Script projects from a single source project. If this interests you, you can check it out here:

CLASPALL – Update Multiple Apps Script Projects From a Single Source

If you have found the tutorial helpful, why not shout me a coffee ☕? I'd really appreciate it.

~Yagi

CLASPALL – Update Multiple Apps Script Projects From a Single Source

CLASPALL is a command line app that runs with CLASP, allowing you to update multiple Google Apps Script projects from a single core project file.

When developing for clients I typically have 3 separate projects:

  • Development
  • Testing
  • Production

CLASPALL allows me to update my Testing and Production projects from my Development project with a single command in my terminal: CLASPALL.

Continue reading “CLASPALL – Update Multiple Apps Script Projects From a Single Source”

Extracting the Valid Workdays Between Two Dates in JavaScript

Given a start date, end date, weekends and, holidays we will extract the valid workdays between two dates in JavaScript in this tutorial.

Sometimes we need to work backward from a date range and extract all the valid workdays within that range. Of course, we will need to exclude holidays and also days off for this period too so it is not just a simple case of subtracting the end date from the start date and adding one.

The best way to illustrate what we want to accomplish is by sharing some example data.

If you are looking to get the end work date given a start date and number of workdays, check out this tutorial: 

Calculate the Workday End Date in JavaScript

The Example

For our example, we will need to prepare a list of date ranges, holiday periods and weekly days off (weekends).

We’ll say for convenience that we will work Monday to Friday and take Saturday and Sunday off. In JavaScirpt-land weekdays are represented as zero-based numbers with the USA-style start of the week occurring on Sunday. In this case, Sunday is zero (0) and Saturday is (6).

Let’s add in some holidays to give ourselves a well-earned break:

  • 15 Sep 2024
  • 31 Oct 2024  🎃🦇👻
  • 24 Dec 2024
  • 25 Dec 2024
  • 01 Jan 2025

This could also be drawn from a regional API that provides dates for holidays in your area.

Finally, we will provide a small sample list of date ranges that we can check, but keep in mind that you can iterate over a much larger list at relatively good speed here.

  1. 10 Sep 2024 – 23 Sep 2024.
    End day for work project JavaScript example range 1
  2. 26 Oct 2024 – 4 Nov 2024.
    End day for work project JavaScript example range 2
  3. 22 Dec 2025 – 16 Jan 2024.
    End day for work project JavaScript example range 3

The blue represents the actual workdays, while the white section indicates the actual date range. Orange bold and underlined days are holidays that don’t fall on weekends. Light red days are weekly days off (in our case, weekends).

Across the top of the dates are the days of the week as a JavaScript day running from 0 (Sunday) to 8 (Saturday).

 

The Video Tutorial

 

To the video tutorial

Releases 8 Oct 2024

The Code

The runsies() function

The runsies() function is the main test function. It contains the 3 different variables that we will send to the getWorkdays() function to generate our list of days.

We’re using the year-month-date (YYYY-MM-DD) format favoured by computer nerds like me.

Once we get the list of days back from the getWordays() function we will then map our existing testRanges array of objects and add the valid days as a property and the total count of valid days.

Finally, we will stringify the array object to make it pretty for logging.

Running the script will display these results:

The getWorkdays() function

Parameters

This function takes three arguments:

  1. workperiod: This is the array object containing the start date and end date for each of the sample periods.
  2. weekends: The array of designated weekends as a number. For example, Saturday and Sunday would look like this: [0,6]
  3. holidays: An array of holidays as date strings.

Function Variables and UTC dates

In this section, we’ll prepare our dates for efficient comparison by converting them into milliseconds so that we can extract our valid dates.

Calculating a Whole Day in Milliseconds (Line 16):

      • We start by calculating the duration of a whole day in milliseconds. This will allow us to iterate over each day and check if it is a valid date.

Handling Timezone and Daylight Saving (Lines 22-29):

    • To avoid any timezone-related quirks or issues with daylight-saving events, we’ll convert our date periods to Coordinated Universal Time (UTC). We’ll create a small private method at the top of our function to handle this conversion.
    • Note: We’ll encounter UTC conversions multiple times in our code, so having a dedicated method simplifies things.

Converting the Array of Holiday Dates to UTC Time (Line 32):

    • Finally, we’ll convert our holiday array of dates to UTC time in milliseconds so that we can directly reference them against the currently iterated day.

Map an array of workdays

Next, we need to map our array of found workdays for each sample date range (Line 35). To do this we will use the JavaScirpt map method that takes a function as an argument.

Map Variables

We will need to iterate through each day within our date range checking if the date is not a weekend or a holiday and then record that date. To do this, we will need to set a few variables.

Get start and end days as UTC time in milliseconds (Lines 37-38)

  • Both the start date and end date will need to be converted to UTC dates using our private getUTC() method.

Set Mutable Variables ( Lines 41-42)

  • When we look at each date we need to check that day’s day of the week. To determine the starting day of the week of our range of dates we use the JavaScirpt getDay() method.  This will update for each new day we check.
  • Next, we need to set our first day to check as a day.

Store Valid Wordays (Line 44)

  • Here we store our valid workdays in the validWorkday array.

Iterating over the days in the range

Our main task now is to iterate over each day in the range.

Not a Weekend or a Holiday (Line 49-52)

  • First, we check if the current day of the week is not included in the weekends array and the current day in UTC format does not exist in the holidayUTC array.
  • If both of these conditions are met, then the day is a valid workday and we add it to our validWorkay array.

Preparing for the Next Day (Lines 54-55)

  • Now we need to prepare for the next day check by:
    • Updating the day  by another day using the dayMilliseconds variable.
    • Getting the next day of the week. Here, we need to keep in mind that if the next day of the week is equal to seven then it will go back to the start of the week which will be zero.

Returning it all back

Once we have our valid workday for the selected range, we return that array to generate our mapped array of workdays.

Finally, we return the workdays array back to the calling function.

 

 

If you have found the tutorial helpful, why not shout me a coffee ☕? I'd really appreciate it.

That’s all there is to get a list of valid workdays in a range in JavaScript. I use this function often when providing analysis tools for clients who want to see aggregate workdays over a period of days.

I’d love to hear what you would use this function for.

 

~Yagi