Append List Items, Paragraphs and table cell items with a date-time stamp in Google Docs using Google Apps Script

Recently, I thought it would be a cool idea to add a date-time stamp to the end of a Google Doc checklist item with Google Apps Script. So I knew when I completed a task.

I often share a project Google Doc with clients and then add my tasks to the document list. With Google’s new check box list item, I wanted to add the date and time that I completed the task when I checked the box.

The bad news is that there is no onEdit() trigger (like in Google Sheets) for the DocumentApp class that would listen for an edit of the document and see a change of the checked box from unchecked to checked and then apply the date-time stamp. 😢

All good, I settled for the next best thing! A menu item.

Take a quick look at the results.

What the Date-Time Stamp Button does

The timestamp button allows you to set your cursor anywhere on a:

  • List Item
  • Paragraph
  • Table cell item
  • Header

… and then click the ‘AddDTS’ menu item. The Google Apps Script will then run the script and your custom date time stamp will be added.

The Code

Run the script

Go to Tools > Script editor to open the Google Apps Script IDE. Copy the code above and paste it into the script editor. Ctrl + s to save.

You will probably be prompted to change the title of the script. Generally, for document bound scripts it’s good practice to give the script the same or similar name as the attached document.

Close the editor and go back to your Google Doc. Refresh the page and your menu will now reload each time with your new menu item.

The first time you run the script you will get a warning to authenticate the code.

You can find out more about this here:

Running Google Apps Script for the First time. What’s with all the Warnings!

After you have run the code for the first time, you can now click the menu item and it will add the date-time stamp to where ever you have your cursor.

Looking to learn more about Google Apps Scripts in a more structured format? Udemy has some great courses that can get you from the basics to a real Google Apps Script pro.

Got a more specific problem you need help with, but don’t have the time to develop the skills? I can connect you with a trusted freelancer. I have a team of hand-picked experts ready to help.

*The above affiliate links have been carefully researched to get you to what you specifically need. If you decide to click on one of these links it will cost you just the same as going to the site. If you decide to sign up, I just get a little pocket money to help pay for the costs of running this website.

Code breakdown

onOpen()

The onOpen() function is a Google Apps Script custom simple trigger that is run each time the Google Doc, (Slide, Form or Sheet) is opened.

For our purposes, we want to create a menu item. Menu items are part of the Google Docs user interface and also consist of dialogue boxes, sidebars, prompts and alerts. So we can use the getUi() method from the DocumentApp ClassLine 6

To build the menu item, we first call the createMenu(‘menu title’) method that takes a title as an argument and commences the build chain to develop the menu. Line 7

We can add as many sub-menu items to our main menu by using the addItem() method. For example, if you wanted to create different displays of your date-time stamp append tool you could add more here.

Each addItem() takes two arguments (Line 8):

  1. The title of the menu item: For us, this is “Add DTS”.
  2. The function to run when you click the menu item: In our case, this is “appendElement”.

Once we have added everything we wanted to our menu, we build it with the addToUi() method. Line 9

Google Docs custom menu item for appending elements using Google Apps Script

appendElement()

This is the main function that runs your date-time stamp appender.

Let’s see how it works.

Document variables

Our first task is to set up our document variables.

To get the Google Doc we are using in Google Apps Script, we call the DocumentApp class and then call the getActiveDocument() method. This will create an instance of the DocumentApp class containing all the methods that you can use to work with the document. We’ll assign this instance as ‘doc’. Line 7

Referencing our ‘doc’ instance, our next job is to get where the cursor is. We can do this with the getCursor() method. Line 8

A Google Doc is broken into elements, like paragraphs, lists, tables, pictures, headers and more. Each element can have child elements as well.

Once we have our cursor position, we can find the element that the cursor is on. This will come in handy in a moment when we append the element. Line 9

Input variables

Our next task is to add our input variables.

This is where you can start getting really creative and change what is displayed when you click the ‘Add DTS’ menu item.

In our example, we are going to add a string of text containing:

  • Today’s date.
  • Today’s time.
  • The current user’s email.

We first create a new date with JavaScript’s Date constructorLine 4

Next, let’s use the Google Apps Script Session class to grab our email. We can find the active user, a.k.a. the current user, with the getActiveUser() method that then has a child method to get the email with getEmail()Line 5

Note that all editors of your Google Doc will need to give permission for the scope that controls the Session class the first time that they click the menu button.

Now we can put our date and email together in a string. I am using template literals indicated with backticks or grave accents to store our string data because it makes it easy to insert variables into the string with the ${code} template approach.

After I indicate “Complete” at the beginning of the text string, I use the Javasript toDateString() and then toLocaleTimeString() methods on the date variable. This will provide the date and time in your local area (Or more specifically, to the date and time that you have assigned to your script). Line 6

Finally, I add my email.

You can remove any of these items that you don’t want or move them into a better order to suit your own purposes.

get element lengths

To style our appended date time stamp we will need to get the length of the element and then get the length of the element plus the newly added date-time stamp. Line 4

We then get the length of the chosen element. Line 5

We will be applying our styling to the end of the old element length through to the length of the element plus the length of the input.

Note that we will subtract 2 from this value. Why? Because if we added the value right to the end of the element and a user select the end of the element and hits ‘enter’, they will bring the formatting with them. This will make the user sad. Nobody wants a sad user. Line 6

Create text styling

There are two ways of applying styling to text elements in Google Apps Script. We could simply chain a related method like setBold(), setFontFamily() or setForegroundColor() methods to your appended text. This is an okay approach for one or two styles but will slow your code down for more. There is a better approach.

The setAttributes() allows you to set a whole bunch of styles on a particular area of text and then send them to your Google Doc in one big hit.

We will be chaining the setAttributes() method to our text append method in a moment, but first, let’s talk about how the method takes style data.

The last argument for setAttribues() is a list of attributes. These attributes are formatted in an object. Each of the objects property keys needs to come from the DocumentApp.Attribute enumerator. You can find a list of properties here:

Document App Attribute Properties

To make things easier, let’s create the attr variable and assign it to DocumentApp.Attribute. Line 4

Next, we can build our object of attributes. Lines 5-11

Note that I have used square brackets around each key to generate the property key allowing for computed property names.

Append the text and styling

Finally, we get to append the text to the chosen element.

We first grab the element and read it as a text item (Text Class). Line 4

Next, we append the inputVal text to the end of the element with the appendText() method. Line 5

Finally, we use the setAttributes() method to add our style. This method can take:

  1. A start range: {number} For us, that this is the elements original length.
  2. The end range: {number} This will be our combined length of the original element plus our appended text minus 2.
  3. The style: {Object} This is the object of style properties we created in the previous section.

Conclusion

That’s all there is to it. You can modify the style and what you write in your text to how you would like it. I would love to hear how you modified your script for your own project. It is always interesting to see.

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

Happy coding!

~Yagi

How to find and replace text in a Google Doc with a link or a list of links with Google Apps Script

So you are a citizen Google Apps Script developer and you’ve decided to make yourself a mail-merge-type project where you want to create new documents from a template. You have discovered the simplicity of the replaceText() method:

Now you want to take it to the next level and replace the text with a hyperlink containing the text and the URL. You might be scratching your head wondering where the replaceTextWithLink() method is or why you can’t simply chain the setLinkUrl() method without making a hyperlink out of the entire body of the document.

via GIPHY

What to do?

In this tutorial, I’ll cover how to find and replace text in a Google Doc with a hyperlink with Google Apps Script under three common conditions:

Danger!!! Word repetition warning ahead!

  1. Find text and replace it with new text and a link where the text is the only text in a document.
  2. Find text within a paragraph and replace it with new text and a link.
  3. Find text and replace it with a list of hyperlinks.

I encourage you to play along. Here is a link to the Google Doc without the code attached:

Test Google Doc.  

Just go to File > Make a copy to get your own copy of the Google Doc. Then Tools > Script Editor.

While you are testing, you can just use undo (ctrl + z) to return the text to its original state.

Let’s dive into the three examples.

1. Find a single item of text as a completed paragraph in a Google Doc and replace it with new text and a link

In our first example, we have a paragraph where we have just the text that we want to replace. Take a look at the image:

Find a single item of text as a completed paragraph in a Google Doc and replace it with new text and a link Apps Script v2

Here’s the code:

Once we have grabbed our body element on line 12, we set up our chain of methods to produce our hyperlink.

First, we use the findText() method to grab the text we want to find in the body. This method takes our textToFind variable as an argument and returns a range element indicating the position of the searched text. Line 14

Next, we get the element that the found range of text is in using the getElement() method. This will be a text element. Line 15

Note! You can find the type of text element by using this approach:

We then call the asText() method to get the current element as … well … um … text so that we can edit it. This allows us to perform rich text editing of the element. Line 16

Now we can set the text we want to use to replace the current text with setText(), inputting our text variable. Line 17

Finally, we add our link using setLinkUrl(). This will take our url variable as its argument. Line 18

Note that this approach will replace all the text associated with the element removing your reference search text and any other text. If you want to replace the selected text in a paragraph and add a link to it, check out the next example.

2. Find text within a paragraph and replace it and add a link.

In this example, we only want to replace the target text (and add a link) that resides inside a paragraph. Here is our example:

Find text within a paragraph and replace it with new text and a link DocApp Google Apps ScriptWe need to do three things here.

  1. We need to find the text element from which template text we want to replace resides.
  2. Get the offset where the found text starts in the overall text.
  3. Replace the text with our new text and link.

Check out the code:

Again we start off by grabbing our body on line 12. We won’t be able to chain our methods too much here because we need to get some extra information out of them. So instead we set foundText to the result of our findText() method call. Line 14

Our next task is to get the start and end locations of the text within the greater text. We can get the start location (or offset) by using the getStartOffset() method. This essentially gets how many characters in our text starts on. Line 17

We then need the location where our text will end. Now, this is not the end location of the current text. It is the location of the text that we are going to use to replace it. To calculate this, we add the startText to the length of our replacement text. We need to subtract one because the startText value is the beginning location of our text and not the character location previous. Line 18

Now we can get cracking and replace our text.

First, we grab the element (text) of our foundText. Line 21

We can then chain our next steps by setting the element to text. Line 24

This time around we can use the beloved replaceText() method to find the text again only searching inside the text element and replacing it with our desired text. Line 25

From here we can now set our link. This time around we will take advantage of setLinkUrl() method’s alternate parameter arrangement which takes:

  1. Start text index – startText
  2. End text index – endText
  3. the URL – url

This allows us to set the link at a specific location in the text.

But what if you want to add multiple hyperlinks to a list, Yagi?

3. Find text and replace it with a list of hyperlinks

In this final example, we want to add a list of links based on a text reference in the document.

Take a look at the document.

Find and replace text with list of hyperlinks DocApp Google Apps ScriptHere is the code:

The Data Source

In this example, we have an array of objects containing the title and URL for each of the links we want to add within our links variable. Lines 6 – 19

Just like in the previous two examples, you could get your data from many other sources. This is just an easy example of data to follow.

Get the paragraph element containing the text.

Before I explain this step, it is important to know that our sample text resides inside a text element that resides inside a paragraph element which will probably reside inside the body element.

Our ultimate goal is to remove the selected text and replace it with a list. If we just remove the text element, we will still be left with the paragraph, which will look like a carriage return (do kids still use that term?). So we will want to remove that whole paragraph.

This means that our first step is to get the paragraph element that contains our text.

We do this first by finding the text (Line 27). We grab the text element (Line 28). This allows us to get the element’s parent with the getParent() method. This is stored in our element variable.

Get the index of the paragraph containing the text

Here on line 32, we grab the index location of our template text. We head back to the body for this one and use the getChildIndex() on our paragraph element of the selected text. This method returns an index of the location in the body element.

The index will allow us to add our list of links in a moment.

Removed the paragraph element from the text

Now that we have the index location of where we need to add our list of links, we can safely remove our reference text.

To do this, we grab the paragraph element and use the removeFromParent() method. Line 35

Add the list of hyperlinks

Our final step is to push our list into our Google Doc at our new index location.

The text will be inserted into the new index location. This means that if we looped through our text and inserted it at the same index each time, the links will appear in the opposite order that we originally had them in our array.

The first step then is to get a reversed copy of the array before we start our loop (We get a copy because we don’t want to change the original array). This is achieved with the Javascript slice() method without any parameters, which collects the whole array. Then we use the reverse() Javascript method on it to reverse the order of the array. Now we have a copy of the array in reverse order, but we haven’t change the original array. Line 37

Now we can run our foreach() loop to iterate through each array item.

Inside each iteration of our loop, we want to use the insertListItem() method  to add our list item to the index location of our Google Doc body (Line 39). This method takes two arguments:

  1. The index location – index
  2. The text – link.text

The method then returns the newly created list item element.

Here we can then add our link using setLinkUrl().

Before we finish with our list item we can set the type of list we want by using the setGlyphType() method. The method takes a ‘list character type’ which is drawn from the Glyph Type enumerator. For our example, we set our list to be numbered.

Give it a crack yourself!

Conclusion

So that’s it. Three different scenarios for you to insert hyperlinks based on a text key in Google Docs with Google Apps Script. Of course, there is more than one way to do things. I would love to hear your approach to these problems in the comments below.

I’d also love to hear how you used these scripts in your own project. It is always inspirational.


Looking to learn more about Google Apps Scripts in a more structured format? Udemy has some great courses that can get you from the basics to a real Google Apps Script pro.

Got a more specific problem you need help with, but don’t have the time to develop the skills? I can connect you with a trusted freelancer. I have a team of hand-picked experts ready to help.

*The above affiliate links have been carefully researched to get you to what you specifically need. If you decide to click on one of these links it will cost you just the same as going to the site. If you decide to sign up, I just get a little pocket money to help pay for the costs of running this website.

~Yagi