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.

Custom Google Sheet tab sort menu

Step 5: You will be prompted to run authorisation of the script the first time the script is run. You can learn more about this here:

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.

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

Got a more specific problem you need help with, but don’t have the time to develop the skills? Make an enquiry on my ‘Hire me!’ page. I occasionally pick up projects. If I'm unable to right now, I can still help you find a great trusted freelancer.


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.

Line 8: To create a menu we use the Create Menu method and add the menu label “Extras” as an argument.

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.

You can learn more about building menus in Google Sheets, Docs and Slides here:

How to build a menu item in Google Sheets

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.

 

That’s all there is to it.

If you want to learn more about how to modify Google sheets tabs with Apps Script, check out these tutorials:

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

Performance of Google Apps Script Text Finder Class on 2 Approaches to Searching Large Datasets

Inspired by research into a recent blog post, the Google Apps Script Text Finder Class’ Find All (findAll()) and Find Next (findNext()) methods were benchmarked over two different datasets containing 50,000 rows. The first dataset contained 1,000 cells matching the search text. The second dataset contained 100 matching cells.

For each dataset, a test was conducted to retrieve either the first 10 matching cells or the first 100 matching cells. The Find All and Find Next approaches were tested and compared on each test.

It was expected that Find Next would perform best on the condition where the dataset contained a large number of found items and only a small number of first cells needed to be reported. The benchmark results suggest that this hypothesis is most likely.

First number of cells to retrieve Test Function Avg. run time over 100 runs. Fastest Function Fastest Avg. Time Avg. time Difference
1000 items to find
10
1
v2 findAll 1626.24 v3 findNext 1368.45 257.79
v3 findNext 1368.45
50
2
v2 findAll 1578.19 v2 findAll 1578.19 4993.61
v3 findNext 6571.8
100 items to find
10
3
v2 findAll 360.94 v2 findAll 360.94 975.16
v3 findNext 1336.1
50
4
v2 findAll 377.13 v2 findAll 377.13 6175.59
v3 findNext 6552.72

Table: The average time in milliseconds of 100 runs of each test of Apps Script Text Finder findAll() and findNext() methods. Image link for mobile-friendly viewers.

Method

Sample Data

Two columns of data 50,000 rows deep were generated for this test. Each cell in each column consisted of a number; either 1, 2, 3, 4 or 5. An equal spread of numbers 1 through 4 where added to each row. Each column differs by the number of 5s in each row:

  • Col A: 1,000 5’s
  • Col B: 100 5’s

Each column was then selected and randomised with: Data > Randomise range.

Test

Two functions are compared to test their performance based on four test conditions based on 100 runs of each test:

  1. Retrieve the first 10 cells containing the search text where the range contains 1,000 matching search items.
  2. Retrieve the first 50 cells containing the search text where the range contains 1,000 matching search items.
  3. Retrieve the first 10 cells containing the search text where the range contains 100 matching search items.
  4. Retrieve the first 50 cells containing the search text where the range contains 100 matching search items.

The time in milliseconds was recorded using the JavaScript Date.now() method before and after the functions were run. The difference in time in milliseconds was then appended to an array and added to a Google Sheet column for each test type. This culminated in 8 sets of 100 results.

The average of each test was then recorded and used to compare performance.

Note: Performance.now() is not available in Google Apps Script. 

Code

All code and results can be found copied from this sheet:

Analysis of Google Apps Script Create Finder Class Retrieve n found values

To explore the code and run your own independent tests, make a copy of the Google Sheet: File > Make a copy.

More detailed breakdowns of the code for each test function can be found in the source tutorial.

Note! There is no v1. The version numbers refer to the tutorial related to this post.

Main Test RUN

This function ran all the test conditions. Modify colPastePosition to add the culminated times to the desired columns. Then uncomment the desired run.

test_v2 – Google Apps Script Text Finder Class- findAll()

Code breakdown can be found here: link.

This function retrieves the full list of all found cells using the findAll() method from the Text Finder Class. All available found items in the range are then stored in the found variable.

It then relies on a for-loop to iterate through each cell and collect the cell location using the Spreadsheet App Class’ range getA1Notation method. Each cell location is then stored in the locations variable as an array item before returning the array to the initialising function.

The for-loop breaks when the total number of required cell items (the position) equal the index variable (i) in the loop.

test_v3 – Google Apps Script Text Finder Class- findNext()

Code breakdown can be found here: link.

In this function, a call is made to the spreadsheet to retrieve the found cell value each time findNext() method of the Text Finder Class is called. On each iteration, the getA1Notation method is used to retrieve the cell location. This location is then stored as an array value in the locations variable before being returned to the initiating function.

The function used a while-loop to iterate through each next item found until the counter – or the number of required cells to collect – is reached.

Results & Discussion

Analysis of Google Apps Script Create Finder Class Retrieve n found values
Performance in Milliseconds to Retrieve the first 10 or 50 Matching Values over a 50,000 Row Range Contain Either 1000 or 100 Matchable items Using the Google Apps Script Spreadsheet App Finder Class.

Test 1: Retrieve the first 10 cells containing the search text where the range contains 1,000 matching search items.

Version 3 –findNext() performed better on average when there were 1000 potential items to find in the range but only the first 10 items need to be selected. Versions 3’s average speed was 1368.45ms compared to version 2’s average run speed of 1826.24ms. This is a performance increase of 257.79ms for version 3.

Version 2’s lower performance is likely due to needing to collect all available found cells before it can extract the top 10 items.

Version 3, makes 10 calls to the Google Sheets in this example. Compared to version 2, this takes relatively less time than collecting all available found cell references to the search item.

TEST 1: 1,000 randomised items to find in 50,000. Return first 10 matches using v2-findAll and v3-findNext functions.
TEST 1: 1,000 randomised items to find in 50,000. Return first 10 matches using v2-findAll and v3-findNext functions.

Test 2: Retrieve the first 50 cells containing the search text where the range contains 1,000 matching search items.

Version 2 – findAll() performed significantly better over 100 runs than version 3 when retrieving the top 50 found cells from a possible 1000. Version 2 was, on average, 4993.61ms faster at an average runtime of 1578.19ms compared to version 3’s sluggish 6571.80ms average.

It was expected that test one and test two’s times for version 2 would be similar and there are only 48.05ms between their average runtimes.

Version 3’s poor performance is likely due to its reliance on calling the spreadsheet to collect the cell data on all 50 calls it needs to make.

TEST 2: 1,000 randomised items to find in 50,000. Return first 50 matches using v2-findAll and v3-findNext functions.
TEST 2: 1,000 randomised items to find in 50,000. Return first 50 matches using v2-findAll and v3-findNext functions.

Test 3: Retrieve the first 10 cells containing the search text where the range contains 100 matching search items.

Version 2, again, performed better by 975.16ms than version 3 when there was a smaller potential number of items to find in the range and only the first ten items need to be retrieved.

Here the performance margin between the two versions was closer than in the previous test. Version 2’s average run speed was 360.94ms while version 3’s runtime was 1336.10ms.

With a smaller number of retrieved items, the version 2 findAll() function did not have to work as hard to collect the methods related to each range it collects. Whereas version 3 still needed to make 10 performance-intensive calls back to the Google Sheet each time with relatively no performance change to test one.

TEST 3: 100 randomised items to find in 50,000. Return first 10 matches using v2-findAll and v3-findNext functions.
TEST 3: 100 randomised items to find in 50,000. Return first 10 matches using v2-findAll and v3-findNext functions.

Test 4: Retrieve the first 50 cells containing the search text where the range contains 100 matching search items.

Predictably, version 2 – findAll() performed the best when the expected match sample is small (100 available matches) and the total first set of cells to retrieve was relatively large (50).

Version 2’s average completion time was 377.13ms compared to version 3’s average of 6552.72ms, performing on average 6175.59ms faster. This is by far the largest margin on performance between the two versions.

Here again, version 3 must perform 50 calls to the Google Sheet, each one retrieving the cell range data. Alternatively, version 2 makes one call to the spreadsheet and then retrieves the cell data for all collected values. This is significantly faster than version 3’s approach.

TEST 4: 100 randomised items to find in 50,000. Return first 50 matches using v2-findAll and v3-findNext functions.
TEST 4: 100 randomised items to find in 50,000. Return first 50 matches using v2-findAll and v3-findNext functions.

Overall

On datasets that may have the potential to contain a large number of matching items, but fewer required results to return, version 3 may be the best option. In all other cases, version 2 is the most optimal approach to finding data in a range.

It is important to note that it can be difficult to accurately measure performance with Apps Script runs because resource allocation to run a script does seem to vary. Nevertheless, with a sample size of 100 runs, it is hoped that average values will be more accurate than a smaller sample.

Grab Your Own Copy of the Google Sheet and Attached Code here

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

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

Got a more specific problem you need help with, but don’t have the time to develop the skills? Make an enquiry on my ‘Hire me!’ page. I occasionally pick up projects. If I'm unable to right now, I can still help you find a great trusted freelancer.


~Yagi

 

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

In this tutorial, we will explore how to find the first and last values in a Google Sheets Range using Google Apps Script. Then we will modify our code to find a value at a specific location. We will then find the position of the first set of values in our Google Sheets range. Lastly, we will create a reusable function to find the first or last set of values in a range.

This tutorial accompanies the YouTube tutorial of the same name:

The starter sheet for the video tutorial:

Starter Sheet

The code for each section of the tutorial can be found below under each section header along with any explanation, where needed.

In our previous tutorial, we covered how to find all values in a Google Sheet, a sheet table or a range. Check it out here:

Find All Values in Google Sheets with Apps Script


The Runsies Function

This is an example function that you can use to run your find functions below. All arguments for the functions below are placed in here along with the execution of the desired function.

In the example below we are running the first function.

 

Find the first value or text in a Google Sheets Range using Apps Scripts FindAll method

In this approach, we make use of our previous tutorial’s script and use the findAll method of the createTextFinder Class.

This method returns an array for each found item that can access the Google Apps Script range class methods.

Line 15 – Once all items in the range are found, we can select the zeroeth item. Incidentally, we could get the last item in the range with this approach by modifying this line to:

const lastVal = foundValue[foundValue.length - 1];

Of course, you would need to update the variable names too.

Line 17 – Here we log the cell position of the first found item using the SpreadsheetApp Range Class getA1Notation method.

Line 19 – Finally to make it easier to test. We set our selected cell value to activate. This makes the cell active and makes it easy for us to crosscheck in our testing. It also has the benefit of navigating the user on the Google Sheet to the desired cell. Check out the image below for an example:

Find first value in a Google Sheets Range with apps script and activate it

Note! This approach can be much, much slower than the next option, particularly if your text finder discovers a lot of cells.

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

Find the first value or text in a Google Sheets Range using the iterator method

A much more common approach to finding the first position of the matching value is using the findNext() iterator method of the Text Finder Class.

This is considerably faster on large datasets where you expect to find many occurrences of the found item. Why? Because, the find-all approach will collect all cells containing the value, whereas findNext() will only collect the next value to be found.

Line 13 – Here we replace findAll() with findNext().

Find the last value or text in Google Sheets Range

In this example, we swap the findNext() method with the findPrevious() method.

Interestingly, if we call the find previous method straight after creating the text finder, It will look for the first item starting in reverse order. This means it will start its search from the bottom of the range.

 

Find the position of the nth value in a Google Sheets Range with Apps Script

Here we want to find the nth value in a range. Perhaps the 3rd value or the 10th.

Lines 14-15-  In this function, we return the findAll() method and then identify the position of the value in the selectedVal array.

Line 12 – Note that we will need to subtract one from our position value here before we can use it to find the value in the array. Remember, the array will start at zero.

 

Find the first n values in a Google Sheets Range

In this scenario, we want to find a starting set of values from our range. Maybe we want to grab the top 3 found cells or the first 5.

Line 15 – Here we use the findAll() method again to get a list of all values in the range.

Line 19-29 – Next, we will use a JavaScript ‘for’ loop to iterate over the found cells. We will need to store all the found A1 notation locations in a locations variable on line 19.

Line  25 – On each iteration, we will append the locations with our new cell value.

Line 28 – However, if the index (i) matches the same number as the position variable then we want to break our loop.

 

Find the first or last values of a selected number in a Google Sheets Range

Finally, we have two functions here. Both functions allow you to find either the first set or last set or cells where the search term is found. Their usage really depends upon the type of data that you are working with.

Both functions take 4 arguments:

  1. sheetName – The name of the sheet tab.
  2. text – The text to search.
  3. n – The number of found cells to collect.
  4. reverse (optional) – If true, conduct the search in reverse.

Again, both functions will return an array containing all found cell locations in A1-notation.

Checkout the post below for a detailed benchmark analysis of each function:

Performance of Google Apps Script Text Finder Class on 2 Approaches to Searching Large Datasets

 

Find All Approach

This approach is more performant when you don’t expect to find a lot of matching cells in a large range. It is also suitable if you want to extract a larger list of items starting from the beginning or end of the range.

Why? Because if there are a large number of found variables then the findAll method will take more time to collect the full list of ALL cell locations before we can continue and select the ones we want. Whereas if we use the next option using findNext or findPrevious then each item will be retrieved one at a time, making the second option more performant.

Alternatively, if we want to retrieve say the first 100 items, then the first item would be a better approach. This is because we only make one call to the Google Sheet instead of 100 which is a much slower approach.

Line 16 – Here, we use the findAll() method again.

Line 22 – Note the if-statement here that checks if the reverse parameter is set to true.

Line 24 – If we want to start the search from the bottom of the range, we first set a counter to zero.

Line 25 – Then we run a reverse for loop, starting from the bottom of the found array.

Line 29 – If we find a cell we add it to the locations list like in our previous example.

Lines 31-33 – Finally, we update the counter and then check the counter count against n and break the look if we have a match.

Lines 36 -46 – If there is not reverse argument or the argument is set to false then we want to start our search from the top of the range. Here, we use the same for-loop as the previous chapter.

 

Find Next or Previous Approach

This approach performs better in a large range when there the range contains many found cells, but you may only need to collect only a few of the first or last proceeding items.

Line 15 – To start our search, we only initialise the text finder class.

Line 17 – Set our empty location array.

Line 18 – Creates a counter base on the number (n) of found cell locations that we want to retrieve.

Line 20 – Next, we generate JavaScript while loop to finish once the counter reaches 1. The loop will either find the next or find the previous cell range.

Line 22 – We set the found variable to receive the cell location.

Lines 24-28 – If we have set the item to be reversed we use the findPrevious method and collect each cell location.

Lines 29-34 – Alternatively, we will use the findNext method if reverse is set to false or not included.

Line 36 – Next, we push the cell reference to the locations array.

Line 28 – The last task in the loop is to decrease our counter by one.

Line 43 – Outside our loop, we return the locations array back to the initiating function.

 

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

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

Got a more specific problem you need help with, but don’t have the time to develop the skills? Make an enquiry on my ‘Hire me!’ page. I occasionally pick up projects. If I'm unable to right now, I can still help you find a great trusted freelancer.


Sort and randomize data in Google Sheets with Apps Script

You might want to sort some Google Sheet data based on a condition in your Google Apps Script or simply sort by selected columns and rows after inserting a new row.

If you are always building sample data for tutorials like me, you might also be interested in randomising your data programmatically.

Fortunately, Google Apps Script’s SpreadsheetApp Class has built-in methods to handle just that for you. Plus it’s super easy to implement.

Check out the video tutorial below or grab one of the code snippets to add into your own project.

Continue reading “Sort and randomize data in Google Sheets with Apps Script”

Add a Row of Data Below the Header in Google Sheets with Apps Script

Sometimes it is just more intuitive to add a row of data to a Google Sheet just below the header instead of at the bottom of the Sheet.

One instance when this comes to mind is when we need to monitor time-dependent data as it is being input programmatically based on a trigger through Google Apps Script. Seeing purchases or sign-ins at the top of your sheet live might be more convenient than at the bottom of the sheet.

In this tutorial, we will walk through how to insert a row and add a new row of data to that row. We’ll also look at how to maintain formatting during this process.

Then if you need to maintain a Named Range or Some formula columns, we’ll walk through that too.

Let’s dive in!

The Starter Sheet

If you want to try out the script examples directly or are playing along from the video tutorial, here is a copy of the starter script:

Add a Row of Data Below the Header with Apps Script – STARTER

The Video

The Basic Code to Add a Row after A Header

In this example, we have a simple Google Sheet where we need to add our data to a row just below the header.

Simple example of adding a row below the header in Google Sheets With Apps Script
A simple example of adding a row below the header in Google Sheets With Apps Script

The main run function is the insertRowAtTop_v1() function. This contains all the code we need to complete our task.

The runsies_example1() function is simply a sample function that simulates how you can integrate the insertRowAtTop_v1() function into your own project.

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

insertRowAtTop_v1()

Set up the function

The insertRowAtTop_v1() function takes 3 arguments:

  1. data – This is a 2d array of data containing the values you want to enter into your new row.
    Google Sheet data is presented as a 2d array in Google Apps Script where a row of data is an entire array and each row array is contained in an outer array. So for example, a sheet range that is 3 columns by 4 rows deep would look like this:
  2. sheetName – This is the sheet tab name.
  3. targetRow – This is the row where you want to insert your range. If your header data is deeper than one row, then you can change this value.

First, we call the getActiveSpreadsheet() method from the Google Apps Script SpreadsheetApp class. You can use the openById() or openByUrl() methods.

Now that we have access to our sheet we can invoke the getSheet() method taking the selected sheet as our parameter. For our example, the sheet will be ‘Example 1’ as indicated by the sheetName parameter.

insert a row into the sheet

Our next task is to add a row to our sheet. We can do this with the .insertRowBefore(targetRow) method. This method takes a target row as a parameter. For us, our argument for this parameter is row 2Line 21

This method will insert a row above the target row.

Now you might have also seen the .insertRowAfter() method and may be wondering why this was not used. These insert methods reference their formatting (i.e. Font, font colour, borders, background colours etc.) from the target row. So if we used the ‘after’ method we would have the header formatting in our cell, which is not what we want.

add data to the new row

With the new row added, we can add the data to that range.

First, we need to get the range where we will add our data. We do this with the getRange() method. This can take a number of parameter formations, but we will use the 4-integer set. These include:

  1. Row Start – This will be the target row we set.
  2. Column Start – All our data will begin in Column A so we set this to one.
  3. Row Depth – We are only inserting one row of data so our depth will be one.
  4. Column Width – The width of the range will be determined by the width of the data that we will put into it. This means that if we get the length or total count of each cell item in the row then this will be the column width.
    We can do this by using the JavaScript length property. Note that we need to get the length of the inner array (data[0].length). This is done by referencing the first or zeroeth item in the array. Line 23

Now that we have our range we can set the values from our data parameter. We do this using the setValues() methodLine  24

Flush the Spreadsheet

Flush Your SpreadsheetWhile Google Apps Script will try and bundle your data together into one operation, a Flush can ensure that all operations on the spreadsheet are complete before any other operations are done on the sheet.

We achieve this with the SpreadsheetApp.flush() method.

runsies_example1()

This example function helps us to understand what parameters we can enter into insertRowAtTop_v1().

Here we set our target row to row 2 and the sheet name to ‘Example 1’.

For our dummy data, we will abuse the JavaScript Date constructor to generate the current date time stamp (Line 39). Then we will convert the date to a time in milliseconds with the getTime() method (Line 40).

We will then use the time as an ID, the date as, well… the date and build a dummy email from the time and a ‘@example.com’ string.

After that, add these variables into the function insertRowAtTop_v1() call parameters.

Handling The Edge of a Named Range

In this example,  we have added a named range to our data range. Perhaps to make it easier to handle the data in another operation in our sheet or in our script.

However, if we were to run our script in ‘Example 1’ above on this we would find that after inserting a new row, our Named Range will change its range. It will go from ‘Example 2’!A2:C15 to ‘Example 2’!A3:C16  as you can see in our Example 2 sheet DataSet named range in the image below. Each subsequent addition to the range will add another row to the DataSet named range.

This will cause problems for us because it will miss the new data we add.

We need to fix this.

Adding a row below the header in Google Sheets with a Named Range With Apps Script

Check out the code for our updated function insertRowAtTop_v2():

Update insertRowAtTop_v2()

In this updated version we have added an extra parameter called namedRangeName. In our example, this will be the DataSet named range. Line 8

On lines 22-26, we need to update the named range, maintaining the existing row and column height, and column width but expanding its row depth.

Two new variables

Lines 13 and 14 add two new variables to our function and will be used to recalculate the range of our named range:

  1. rowDepth: This is the last row number subtracted by the target row + 3. In the example image above our target row is row 2. The last row with data is row 14. If we subtract 14 from 2 we get 12. However, we have 13 items in our sheet and our name range also included an empty space at the bottom – Which means we need to add 2. We will also add an extra row during our process so now our formula would look like this:
    14 - 2 + 3 = sheet.getLastRow() - targetRow + 3
  2. colWidth: We will now need to get the column width twice from our data parameter. Once when we get the range and, once when we get the width of the named range. Let’s call the length property only once (data[0].length) and then reference the resulting value.

find the named range and update it

The only way we can update a named range with the SpreadsheetApp class is to first get an array of all named ranges in the spreadsheet. This is done with the getNamedRanges() methodLine 22

From here we can use the JavaScript Find method that will return the first matching item in the array. Line 23

.find(namedRange => namedRange.getName() === namedRangeName)

The Find method takes a function as an argument containing an iterator parameter that we set to namedRange. This will run through each named range in the array until it finds our desired match.

For simplicity, we are using an arrow function here.

On each iteration, we can call the getName() method on the selected named range and compare that with our namedRangeName parameter (e.g. ‘DataSet’). If there is a match Find will conclude its iteration and return the current named range.

Once we have our selected named range we can use the setRange() method to update the range (Line 25). This method takes another range construct as an argument (Line 26).


Here we set the start row to our target row in column A and then assign our row depth and column widths we generated earlier in the function.

Including preexisting formulas into the newly inserted row

You may have a scenario where you have some formulas in your sheet that you need to add to your data row when it is added to your Google Sheet.

In our ‘Example 3’ sheet tab, we have added two formula rows to our data set in columns D and E that we want to include in our new row entries.

Adding a row below the header in Google Sheets with a Named Range and formula columns With Apps Script

Let’s take a look at the updated function now:

Here we have included a new optional parameter hasFormulas that is set to false by default. You can set this option to true if you wish to include formulas at the end of your row input. Line 9 

Adding the formulas to the input

We have included an if condition after we created our row on lines 21-27. Here we check if the sheet has formulas at the end. If it does then get the total number of columns in the sheet with the getMaxColumns method.  Line 22

Next, we need to get the ranges for the newly inserted row (rowAbove) and the row below it (rowBelow). We will add one to the row to grab the row below and apply the maxCols variable from line 22 to indicate the width of the range.

Finally, we will copy the row below in its entirety to the row above with the copyTo method.

The format for this method is as follows:

sourceRange.copyTo(destinationRange)

Without any other optional parameters, this method will copy over the formatting and the formulas from the previous range. If the formulas are not set to absolute ranges (with the $ sign) then they will adjust automatically to the new cell range.

Conclusion

While there are probably still some edge cases that these examples don’t cover, I think that they will handle the majority of scenarios that you come across. The examples should also provide you with some understanding of the workings of the code to make your own modifications where you see fit.

It’s always interesting to hear how you apply the scripts to your own projects. Feel free to comment below.

Further Reading

If you are looking for an alternative approach to adding data to a sheet check out these tutorials:

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

Got a more specific problem you need help with, but don’t have the time to develop the skills? Make an enquiry on my ‘Hire me!’ page. I occasionally pick up projects. If I'm unable to right now, I can still help you find a great trusted freelancer.


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

%d bloggers like this: