# Blog Feed

## Google Apps Script – How to Automatically Generate a Time From a Four Digit 24 hour Time in Google Sheets.

On a recent board post, a Google Sheets user wanted to change a four-digit number (for example, 1230) to a time, like 12:30, in the same cell that the item was entered.

Unfortunately, the user was not in a position to change the starting values, so they were left with the 4 digits.

There are two ways of doing this with varying levels of complexity:

## How to Sort Tabs in Google Sheets with Google Apps Script

Sometimes your Google Sheet tabs can get out of hand. They can be mixed up and confusing to users. It’s often necessary to simply sort them in ascending or descending order.

In this tutorial, we will use Google Apps Script to sort tabs in Google Sheets. We’ll also use a handy menu bar to quickly run the sort.

The approach below relies on a natural sort. In a normal sort where you also have numbers say:

`"2. Cheese", "10. Pizza", "1. Bananas"`

Then you ran your sort, you would not get what your expected but rather:

`"1. Bananas", "10. Pizza", "2. Cheese"`

With a natural sort, we consider the number numerically, rather than as characters. This means our sort would come out as expected:

`"1. Bananas", "2. Cheese", "10. Pizza"`

You can learn more about creating the Apps Script by following the video below or you can jump down and grab a copy of your code and run it in your own project.

You can grab the starter Google Sheet Here:

Sorting Google Sheet Tabs – Starter Sheet

## Sort Tabs in Google Sheets – Video

https://youtu.be/a7l6OEkMkIg

## The Code

Step 1: In your Google Sheet, Go to Extensions > Apps Script.

Step 2: copy the code from below and paste it into the edits and save.

Step 3: Next, reload the Google Sheet. You will see a menu item called Extras. Click it and you will see your two sort options.

Step 4: Go ahead and click an option.

You should see your tabs being sorted.

Running Google Apps Script for the first time.

Step 6: Select an option again and you will see the tabs being sorted.

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

Need help with Google Workspace development?

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

## Code Breakdown

### onOpen()

The `onOpen()` function is a Google Apps Script simple trigger that runs automatically when the user opens the Google Sheet.

Line 5: In our example, we call the Spreadsheet App UI class, so that we can build the menu.

Lines 9-10: Next, we can add menus to the main menu header with the Add Item method. These menus take a menu label and then a function or an object method that will run when the menu is selected. Ensure that you don’t include parentheses in these arguments and contain them in a string.

Line 11: Finally, we need to build the menu by adding all the menu items to the UI.

### The Sheet Tab Sorter object

The tabSorter object contains 3 properties:

• `ascending`
• `descending`
• `sortTab`

#### Ascending and Descending Property Methods

Both of these property methods run the `sortTabs` method providing either true for ascending or false for descending as the argument.

We need to encapsulate these method calls inside their own anonymous functions so that they don’t run automatically when the menu is loaded.

` ascending: function(){this.sortTabs(true)},`
`descending: function(){this.sortTabs(false)},`

#### The sort Google Sheet Tabs machine (sortTabs)

The `sortTabs` property does all the heavy lifting in this object.

It takes a boolean as an argument that will determine if the sort is ascending or descending.

##### Get a list of sheets

Our first task is to get an array containing all the Google Sheets in the currently active sheet. We can do this with the SpreadSheet App Get Sheets method. This will contain an array with all the methods available for each found sheet tab.

##### Using Intl Collator for natural sorting

We want to sort our sheet tabs naturally just in case we have numbers in the name of the tab (e.g. “1”, “2”, “4. Cake”). We can do this with the JavaScript `Intl.Collator` object to sort the sheet tabs in a natural order, meaning that numeric values are sorted in numerical order and text values are sorted alphabetically. You can modify this function to use a different sorting algorithm or change the sorting order.

Line 2: Here, we create a new `Intl.Collator` constructor. The first optional parameter of the constructor defines the locale or language tab. We don’t need this option, so we set it to ‘undefined’.

The second parameter sets the options for the collator.

Line 3: First, we use the numeric property and set it to true. This will allow us to order the numbers properly so that 1 < 2 <10.

Line 4: Secondly, we set the sensitivity to base. This means that we do not take into account any accents or other markings on letter characters. If you are using this Google Sheets sort tab code in other languages, then you might want to modify this.

##### Sort Google Sheet tabs Apps Script-side

Now that we have our collator set up we use the JavaScript sort method to sort through the array of sheet names.

Line 2: Here, we use an arrow function with a standard a, b parameter set. These parameters refer to the first and second elements of comparison respectively.

Line 3: Use our collator and apply the compare method to compare the sheet names against each other.

##### Reversing the sort

If `isAscending` parameter of the `sortTabs` method is set to false, then we use JavaScript `reverse()` to reverse the array order of the `sheetNames`.

##### Updating the Google Sheet tabs to the desired order

Finally, once our array is in the desired order we need to update the Google Sheet with the new tab order.

Line 2: First, we loop through the sheet names array with the JavaScript forEach() method.

Line  3: Inside each loop, we need to set the active sheet to the currently iterated sheet.

Line 4: Finally, we move the active sheet to the next position in the sheet tabs. Note that sheet indexes start from one (1) however our array index starts from zero (0). This is why we need to add one to the index.

### Starting the sort after a set number of tabs

Perhaps you have an instruction tab or dashboards that you want to leave to the left of your sort. Here you can update the moveActiveSheet() by increasing the value to add to the index by the desired number plus 1.

Let’s say I have an ‘Instructions’ tab and a ‘Dashboard Tab’ that I want to keep to the far left and is not included in my sort list. my moveActievSheet() function would look like this:

Here I add 1 to the zero-based index and another 2 for the two tabs I want to keep in position.

## Google Sheet Tabs by Date

Check out my bonus video on sorting tabs by leading date.

The Starter Sheet

That’s all there is to it.

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

## Changelog

2024-05-31

• Added chapter on keeping static sheet tabs to the right and sorting after them. Thanks to Cassidy for the question.

## Find and Hide Rows in Google Sheets with Apps Script

Using the Spreadsheet App Class’ Text Finder Class to find and hide rows in Google Sheets containing target text in a cell can be a fast way to hide values. In many situations, this may be a faster way to hide rows based on cell value in Google Sheets with Google Apps Script than iterating through a range and extracting rows.

In this tutorial, we will cover 3 approaches to using the Text Finder class to hide rows. Each may be useful in its own circumstances.

This tutorial accompanies the YouTube video series of the same name. You can find the links to each of the related videos in each of the sections along with the starter Google Sheets so that you can play along.

## V1 – Basic Find and Hide Rows based on cell values in Google Sheets

### Starter Sheet

Version 1 – Starter Sheet

### The Video

https://youtu.be/alI2f7w7xjU

### The Code

Unlike when formatting rows and cell activation, – as we did in the previous tutorial – our fasted approach here is to hide and unhide sheets while looping through all the found cells.

In this basic approach, our function contains 3 parameters:

• `text` – The text to search.
• `sheetName` – The sheet name to search.
• `isHide` – An optional argument set to true by default to hide values or false manually to unhide them.

Lines 10-11 – We first collected our current Google Sheet workbook and then select the sheet tab we will be working in.

Lines 13-14 – Then we use the Text Finder class in the Spreadsheets App to search for our target text and then use the `findAll()` method to get an array constructor of all the found value cell ranges. You can learn more about this in the first tutorial in this series here:

Find All Values in Google Sheets with Apps Script

Line 16 – Next we iterate through each found row with a JavaScript `forEach()` loop.

Line 17 – On each iteration, we collect the row number. We do the same thing here in our previous tutorial when activating and formatting entire rows.

Lines 19-23 –  Lastly we need to check if the user has set `isHide` to false to show the rows or true (or not used) to hide the row. We then call the sheet and apply either the Spreadsheets Apps Hide Rows (`hideRows()`) method or (`showRows()`) Show Rows method. These methods can take a single row as an argument. We provide this with the `row` variable.

This is a quick and easy solution to understand. However, it does not perform well with a large dataset. It will also try and hide rows multiple times when a found cell is on the same row as a previously found cell.

The function, just like the other two examples, can be called from another function with:

`hideAllRowsWithVal(text, sheetName, boolean)`

e.g.:

`hideAllRowsWithVal("koala", "Sheet1", true)`

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

## V2 – Find and Hide Rows based on cell values in Google Sheets with Range Grouping to improve performance

### Starter Sheet

Version 2 – Starter Sheet

### The Video

https://youtu.be/CeWUAOK7Ui8

Released Monday 12 Feb 2023. Subscribe (Top right) to get a notification for when this video comes out.

### The Code

In larger, ranges we might have a lot of situations where our found text is on multiple adjacent rows.

In the image above, we can see that rows 30 and 31, 38-43, and 46-49 can all be batched together into a single range.

Furthermore, rows with the found text (Koala) on the same row can be ignored, the consecutive times that they are found.

Let’s go ahead and fix our code to make it more efficient.

Note that lines 9-16 of the code are the same as the previous function. Refer to this for an explanation.

#### The Hide Range METHOD

Line 22 – After we have collected our ranges of found rows we will create a `hideRange()` method. This will either hide or show the range based on the `isHide` argument.

This function takes a single object parameter that contains a start row and a number of rows.

Lines 24 – 26 – Unlike the previous version, we use the Hide Rows and Show Rows extra parameter to include the number of rows deep to hide.

#### Row Range variable

Lines 32 – 35 – This mutable variable stores the start row and row depth as we collected each range of rows to hide in our sheet.

#### Iterate through all cells

Line 37 – Here, we start the `forEach` loop that iterates through each found cell range. We include the index (`idx`) in our arguments in our arrow function as well here.

Line 39 – Next, we grab the row number with the Get Row (`getRow()`) method.

Line 40 – Then we get the next possible row in the current range collection by adding the start row with the row depth. This will be used in a moment ot compare against the currently iterated row.

#### On the first iteration

Lines 42-46 – On our first loop through our found cells, all we need to do is add our first found row and add one to our depth.

#### There is another cell on the same row

Lines 47-51 – If there is another cell on the same row, then we don’t need to do anything and we simply return the function for that iteration.

#### There is a cell directly below the previous one

Lines 52-55 – If the next found row is only one cell down (adjacent), then we just want to add one to the number of rows of the existing `rowRange` variable.

Lines 57-60 – If the row is the last found row, then we can run the `hideRange` function on our update range set.

#### A new range begins

If the next found row is not directly below the previous one. We need to:

1. Line 63 – Run the `hideRange` on the current `rowRange` variable set.
2. Lines 65-66 – Reset the `rowRange` variable adding in the current row to the start range and one to the depth.

Lines 69-71 – Again, if we are on the last found row, we can just run `hideRow` to end the loop.

Need help with Google Workspace development?

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

## V3 – Find and Hide Rows based on cell values in Google Sheets using the Google Sheets Advanced Service API and Range Grouping

### The Video

Released Thursday 13 Feb 2023. Subscribe (Top right) to get a notification when this video comes out.

### Starter Sheet

Version 3 – Starter Sheet

### The Code

I found version two to be remarkably efficient. However, if you want to do a lot of editing to the sheet tab then you might want to consider using the Google Apps Script Advanced Sheet Service API.

#### Main Variables

We need to add a few more variables to our main variables here.

Line 12 – We will need to get the spreadsheet ID to use in our batch update.

Line 13 – The sheet name does not work the same as an identifier in the advanced service, so we will need to extract the sheet ID too.

#### A request list

Line 21 – The Sheets batch request property requires a list of requests as its value. Here we will store an array of all the requests that we want to batch together to hide each row range of the Google Sheet.

#### Update Dimension Properties

Line 27 – The `appendRequest(setRange)` function pushes a new request to the `requests` property.

When hiding and displaying rows or columns in a Google Sheet with the Advanced Service we are updating a dimension property. These properties can be a number of different field types, but for us, we want to hide rows.

Let’s  take another look at the layout of this JSON object:

Lines 3-8 – The first sub-property is the range object. This object requires a sheet ID. The dimension is either the columns or rows.

Then we need to set the start index. Note that the cell ranges will start from zero instead of 1. We must then subtract 1 from our start row to get the correct start index of our row range.

Finally, we set the end row. This will be one row after our desired end row. Think, ‘up to, but not including this row’.

Lines 9-11 – Next, we identify the property that we want to change. For hiding and showing rows this is the `"hiddenByUser"` property, where the value is a boolean. This conveniently fits with our `ishide` parameter.

Line 12 – Weirdly, we then need to declare that we are using the `"hiddenByUser"` property by adding it to the fields list.

#### Store the current row range

Lines 46-49 – Just like the previous version, we need to store each range before sending it to `appendRequest()`. Unlike the previous version, our last property is the end row rather than the number of rows.

#### Starting the loop

Lines  52-54 –Now we can commence our loop through the found cells.

Here, the first task is to collect all the row numbers.

#### On the first iteration

Lines 56-60 – On the first loop of our cell array, we just want to add the current row number to the start and end row of `rowRange`.

#### If the next row is on the same row

Lines 61 – 65 – If we have more than one result on the same row we want to ignore it and return the current loop.

#### If its the next row below

Line 69 – We add one to our end row value in `rowRange`.

Lines 72-74 – If we are on our last found row, send it to `appendRequest()`.

#### Create a new row range

Line 77 – If the current row is not the next row down then we send `appendRequest()` with our current `rowRange`.

Lines 79-80 – Next, we create a new `rowRange`.

Line 83-85 – If the current row is the last row in the array, we sent it to `appendRequest()`.

#### The Batch request

Line 90. Here we use the batch request of the spreadsheet resource. The batch request takes an object with a requests property. This property, in turn, requires an array of JSON object requests.

For its second argument, we reference the Spreadsheet ID.

## Some notes

If you know that there may not be any matches in your text finder then you might wish to add a return agent after the `allOccurrences` variable:

`if(allOccurences.length === 0) return;`

Another good measure might be to use a try/catch statement in the third version when running the batch call, just in case there is an error with the API server.

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

~ Yagi

## Find and Select or Format rows in Google Sheets with Apps Script

In this tutorial, we create 3 Google Apps Script functions that are used to:

1. Find and select the row containing the first or last value in a Google Sheets sheet tab.
2. Find and select all rows containing the search value.
3. Format all rows containing the search text.

You can grab a copy of the starter Google Sheet to play along here:

Find & Select or Format Rows – Tutorial

This tutorial accompanies the YouTube video of the same name:

https://youtu.be/Y7rnQT6qYiA

All functions are built to be run from another function, making it easy for you to integrate them into your own projects.

For our example, we will use the `runies` function for this purpose.

All three of the  examples below take two arguments as parameters:

• `text` – the search text.
• `sheetName` – the Name of the selected sheet tab.

These functions rely on the Apps Script Spreadsheet App Text finder class to search for the target text within the range.

All examples search a selected sheet tab. However, you can easily modify the script to search a specific range or the entire Google Sheets workbook. You can learn more about how to do this here:

Find All Values in Google Sheets with Apps Script

## Find and activate the first or last row in a Google Sheet with Apps Script

Lines 10-12 – In this scenario, we activate the first (`findNext()`) or last (`findPrevious()`)found row based on a search item that can be found anywhere in the row. We then store this cell range in the `cell` variable.

Line 17 –  From the cell variable, we can select the Spreadsheet App Range `getRow()` method to get the row number of the cell.

Line 19-21 – Next, we can activate the range of the selected row using the activate method.

We set the entire range by using A1-notation here within a template literal (that is a string within backticks (`)). In Google Sheets, we can set the full width of a sheet by leaving the last column value blank in the notation, for example:`

``` A1:1 or even 1:1. Incidentally, you can also select a portion of the width by including an end letter in the range, for example: ```

`A1:K1 or in the script .getRange(A\${row}:K\${row}`)`

Find first, last or nth value in a Google Sheets range with Apps Script

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

## Find and activate all rows in a Google Sheet with Apps Script

In this example, we select all of the rows containing the target search value.

Line 13 – First, we modify the Text Finder variable to the findAll method and rename the variable. This will return an array of all the cells where the values are found as an array.

Lines 15-16 – Now, we can map over each item in the array creating a new array of ranges that contain A1-notation of the selected row.

Line 18 – Finally, we can use the Spreadsheet App Sheet Class` getRangeList()` method to collect all ranges in our array and then activate them.

## Find and format all rows in a Google Sheet with Apps Script

This last function is virtually the same as the previous one. However, we are doing something much more useful, we are programmatically updating the format of the selected rows.

Lines 18-21 – Using the `getRangeList` method, we can modify the formatting of any range in the list. In our example, we set the background of the row to a dark blue, changed the text colour to white and bolded the font.

### More formatting methods you can use.

Here is a list of common formatting methods that you can apply to a range list:

1. Clear Format`clearFormat()` – Clears the formatting of the selected range.
2. Set background Colour`setBackgroundColor(colour)` – Use CSS notation like hexadecimal colours, colour names or RGB colours
3. Set font Colour`setFontColor(colour)`– Use CSS notation like hexadecimal colours, colour names or RGB colours.
4. Set font Weight`setFontWeight(type)` – Either “bold” or “normal”.
5. Set font Size= `setFontSize(size)` – The font size as a number.
6. Set font Style`setFontStyle(style)` – The style, e.g. “Helvetica”, “Poppins”.
7. Set vertical alignment`setVerticalAlignment(alignment)` – “top”, “middle” or “bottom”.
8. Set horizontal alignment`setHorizontalAlignment(alignment)` – “left”, “center”, “right”.
9. Set text rotation`setTextRotation()` – Sets the rotation of the text in each cell in degrees from the original horizontal plain.

In the next tutorial, we will cover how to hide and unhide rows based on found values in a range. The process is a little different, so well worth checking out.

Subscribe to get an email when the next tutorial in this series comes out or get regular updates on my latest tutorials.

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

~Yagi

## GWAOw! 5 – Insert Special Characters by Sheets Help

In this episode of GWAOw!!! we look at Insert Special Characters by Sheets Help.

As the name suggests, the Insert Special Character Add-on allows you to access the complete list of special characters like maths symbols, shapes and arrows, currency symbols, dingbat and Greek and Coptic symbols from the sidebar of your Google sheets.

This is all accessible from the convenience of the sidebar within your selected Google Sheet.

### Features

The Insert Special Character Google Workspace Add-on comes with some handy features. You can:

1. Modify the colour and size of the characters before installing them.
2. Insert Multiple characters into one cell.
3. Filter the character list by:
1. Arrows
2. Geometric Shapes
3. Currencies
4. Maths Symbols
5. Dingbats
6. Greek and Coptic Symbols
4. Use the search bar to search for a specific character.

## Pricing

The add-on comes with a 7-day free trial followed by a very reasonable one-time \$7 purchase, but…I spoke to Adam from Sheets Help and managed to get you 20% off.

I don’t know how long the offer will last so I recommend that if you find this Add-on useful, take advantage of the discount while it is still available.

Use the code SPECIAL20 at checkout to get the discount. You can find the code in the description below this video.