Online data entry forms are a powerful tool that you can use to collect many types of data more easily and accurately. Google Sheets is the most powerful cloud-based spreadsheet application that you can use absolutely free. Google is also offering another free tool named Google Apps Script (GAS) to increase the power of your favorite Google apps. In this post, I will explain to you how you can create a free online form (or Web App) that can perform Create, Read, Update, and Delete (CRUD) Operations on Google Sheets using Google Apps Script and Google Sheets API v4.
Table of Contents
Why I Should Create Online Data Entry Forms
You can improve the productivity of your work by creating an HTML form to submit data to Google Sheets than directly typing data on the Sheet.
- Easy to share the form and ask all your staff or team members to submit data to the same Sheet and at the same time.
- You need not give Google Sheet edit access to your team, so your data is secure
- Reduce human errors
- Increase the reliability of your data -form validation
- Fast data entry (if you are doing mass data entry work) – Save both time and money
- Monitor data entry work in real-time and let you make proactive decisions
- And so many…
All the above-mentioned apps and services are packed with your Google Account completely free. So, you can build an absolutely free data entry form or any type of online form to perform CRUD Operations on Google Sheets. So, let’s get started.
In a previous post also, I explained, “How to Create Data Entry Form with Google HTML Service and Submit Data to Google Sheets“. However, using that code you can only write data to Google Sheets. If you only need to submit data to Google Sheets, you may use that method because that code is less complex than this.
What you need
Basic knowledge of HTML, CSS, JavaScript
Basic Knowledge of Google Apps Script
You need to have basic programming knowledge of HTML, CSS, and JavaScript to modify the code in this post. However, I will try my best to make the code readable and editable by non-programmers too.
Overview of creating an Online Data Entry Form that can Perform CRUD Operations on Google Sheets
In this tutorial, we are going to create a web form that can Create, Read, Update, and Delete (CRUD) records in Google Sheets.
For creating this online form I am using Google Apps Scripts. There are two ways that you can use Google Apps Scripts namely Container-bound Scripts and Standalone Scripts. Here I am using the Standalone Scripts. So you have to create Google Sheets and the App Script files separately in your Google Drive.
We are going to perform CRUD operations on Google Sheets using Google Sheets API v4. (in the previous post that I mentioned above create the HTML form without using APIs)
The Concept
To perform CRUD operations, you need to create a unique ID for your records. For this purpose, I will use a universally unique identifier (UUID). However, this identifier is not guaranteed to be unique across all time and space. Therefore, you may need to use another method, if you need this for high-frequency data entry work.
I briefly explain the logic behind the CRUD operations used in this method below.
Create/ Insert Data
The user fills out the form and hit the submit button. If it passes the browser validation data is sent to the server-side script. If it is not an update request (does not contain an ID) server-side script adds a new id (UUID) and append data to the specified range.
Read Data
The server-side script request data for a given range using APIs. after you perform, create, update, or delete actions, The web app updates the data table in the front with changed data.
Update Data
When you click the update button, it passes the record ID to the server-side script. The server-side script validates the ID, and if it exists, it reads the relevant row. The data passes to the form for editing.
Once you hit the submit button, it passes data to the server-side script. It validates the ID and if it exists, replaces the relevant row with new data.
Delete Data
When you click the delete button, it passes the record ID to the server-side script. The server-side script validates the ID. If the ID exists, delete the relevant row and shift the cells up.
Live Demo
Use the following links to access the live form and the Data Sheet.
Go to the Google Sheet
(Data Sheet)
How to Create this online form using Google Apps Script and perform CRUD operations on Google Sheets
Here I am not going to explain the code line by line. Instead, I will briefly explain the purpose of each function, and file, and present you with the relevant code below.
If you are already familiar with Google Apps Script, you can copy the Google Apps Script file and the Google Sheet to your Google Drive from the following links and start modifying. I have added comments at all the locations that you need to change when you are adding new fields.
Link to Google Sheet
(Make a copy to your Drive)
You need to change the Google Sheet ID (Spreadsheet ID) in the Apps Script file as explained below in order to send the data to Google Sheet.
You may not be able to view the Apps Script file from the above link when too many users are viewing the file at the same time. In such a case, you can use the following link which contains the same copy of the above.
The following video demonstrates how to copy these files to your Google Drive and run the code. In this video, from 4:00 onwards, I explain how to add a new field to the form.
If you cannot see the video, please follow this link to watch it on YouTube.
You can get a brief idea of the code by following the below steps. I assume that you have already logged into your Google Account.
Step 01: Make a Copy of the Google Sheets
You can make a copy of the Google Sheets used in this example from the following link.
Link to Google Sheet – Make a copy to your Google Drive
This spreadsheet contains two sheets namely “Data” and “Helpers”. The data you inserted from the web form is saved to the “Data” Sheet. The “Helper” sheet includes a list of countries required for populating the “Country of Origin” drop-down list.
![How to Create an Online Data Entry Form that can Perform CRUD Operations on Google Sheets 7 How to Create an Online Data Entry Form that can Perform CRUD Operations on Google Sheets](https://www.bpwebs.com/wp-content/uploads/2023/04/Google-Sheets-1024x492.png)
Step 02: Make a Copy of the Google Apps Script File
You can also make a copy of the App Script used in this example file from the below link.
Link to Google Apps Script File – Make a copy to your Google Drive
The Apps Script file contains the following files.
- Code.gs
- Index.html
- JavaScript.html
- FormProductDetails.html
- DataTable.html
- CSS.html
- SpinnerModal.html
The Code.gs
file contains the server-side scripts, which include the function that calls Google Sheets API. The other files make up the online form.
I have moved the HTML codes related to our main components to separate files namely, FormProductDetails.html
, DataTable.html
, and SpinnerModal.html
to make the code more readable. These files are included in the Index.html
file using the server-side function include()
.
The JavaScript and CSS are written in the JavaScript.html
and CSS.html
files respectively. Those two files are also included in the Index.html file using the same include()
function mentioned above.
See the Google HTML Service guides on Separating HTML, CSS, and JavaScript
Code Snippets
The following are the codes included in the Google Apps Script file mentioned above.
1. Code.gs
The Code.gs
file includes the server-side functions.
I have declared several variables in the global scope so that we can use them inside other functions without declaring them again and again.
Most of the functions are self-explanatory, and I have added comments to make them easy to understand. The sources of some code sections are also added in the comments.
I will explain how this code works later in this post.
2. Index.html
This file contains the HTML, CSS, and JavaScript code that defines the user interface and functionality of the web app.
The main HTML component such as Form, Data Table, and Spinner are moved to separate HTML pages to improve the readability of the code. And also, the CSS and JavaScript codes also moved to separate HTML pages with the same purpose. The external CSS and JavaScript libraries such as Bootstrap and JQuery are also included in these separate CSS and JavaScript files.
Then, all those separate HTML pages are included in the Index.html file using the include() function, using <?!= include('file_name'); ?>
code.
3. JavaScript.html
This file includes the JavaScript codes which run on the visitor’s browser. It also includes relevant external JavaScript libraries.
4. FormProductDetails.html
This file includes the HTML codes which create the HTML data entry form.
5. DataTable.html
This file includes the HTML code required to generate the data table. The data table is inserted by a JavaScript function inside the id dataTable
.
6. CSS.html
This file contains a CSS class that changes the button size. You can add your custom CSS inside the following file.
7. SpinnerModal.html
This file contains the HTML codes required for the SpinnerModal. It is an animated modal window that appears on top of content and is used to indicate that the content is being loaded or processed.
Step 03: Change the SpreadsheetID in Code.gs file
Copy the spreadsheetID
of the Google Sheet, you copied to your drive in Step 01. Replace the SPREADSHEETID in line 8 of the Code.gs file.
Learn how to find SPREADSHEETID.
Step 04: Enable Google Sheets API
You must enable Google Sheets API in Advance Google Services to run this script. To enable Google Sheets API for your Apps Script,
- Open the Script Editor (the file you copied to Google Drive in Step 02).
- Click on the Plus (+) icon in front of the Services tab.
- Then select Google Sheets API and click Add button.
Step 05: Deploy as a Web App
To deploy this script as a web app.
- Click the Deploy button at the top Right
- Then, chose the New deployment.
- In the New deployment window, click the gear icon and select Web app.
- Then type a description for this deployment in the Description text box (Optional).
- Under the Web App, Execute as option select, Me(Your Email)
- Select Anyone, for the Who has access option to enable everyone who has access to use the web app. You may change this according to your requirement.
- Then click Deploy.
- If you run this for the first time, it will require your authorization to run the code in your Google Account. If so, click Authorize access button.
- In the next window, click on your email address.
- Then click the Advanced link.
- Click the link with the name of your Google Apps Script code.
- Click Allow.
- Then Click on the web app URL to load it.
Read more about Deploying a script as a web app in Google Guide.
How this Script perform CRUD Operations on Google Sheets
Create New Record
- After you correctly fill the form and hit the submit button, the function
handleFormSubmit()
in the JavaScript file is called. - This function calls the function
processForm()
in the Code.gs file and passes theformObject
as the parameter. - The function
processForm()
check whether theformObject
has an ID (recId
) and if exist validate using checkID() function. - If the
formObject
hasrecId
, it means it is an update request. So, it gets the range relevant to the ID usinggetRangeById()
function. Then it calls theupdateRecord()
function with the data informObject
and therange
found earlier. - If the
formObject
does not have a validrecId
, it means it is a request to create a new record. Then it calls the generateUniqueId() function and get a new unique ID. Then it calls thecreateRecord()
functions with the values extracted from theformObject
and the unique ID. - Then the function
processForm()
call the functiongetLastTenRecords()
and it returns the last 10 rows of your data range. The function processForm() also returns the same to thehandleFormSubmit()
mentioned in no 1 above. - Then the JavaScript function
handleFormSubmit()
call the functioncreateTable()
function with the last 10 rows as a parameter. - Then the function
createTable()
update the data table next to the Form.
Update Record
- The user clicks the update button in the row which data need to be updated.
- It calls the
editRecord()
JavaScript function which you can see in the JavaScript file. - Then, the function
editRecord()
calls the serverside functiongetRecordById()
(it is in the Code.gs file) with therecId
as the parameter. - The
getRecordById()
returns the relevant row of data as an array to theeditRecord()
JavaScript function. - Then, the
editRecord()
function calls the JavaScript functionpopulateForm()
with the data array (it is in the JavaScript file). - The function
populateForm()
populates the form fields with the data. - Then the user can make the changes and hit the submit button.
- Hereafter, almost the same process in the above “Create New Record” is followed. Since here form passes a
recId
, in step 4 it calls theupdateRecord()
function. It replaces the row which matches therecId
.
Delete Data
- The user clicks the Delete button in the row which data need to be deleted.
- Browser requests to confirm the action.
- It calls the JavaScript function
deleteRecord()
which you can see in the JavaScript file. - Then, the function
deleteRecord()
calls the serverside functiondeleteRecord()
(the second is in the Code.gs file) with therecId
as the parameter. - The serverside function
deleteRecord()
validate and delete the row that matches therecId
. After deleting the record function returns the last 10 records of the data range. - Then the JavaScript function
deleteRecord()
(the function in the JavaScript file) calls the functioncreateTable()
with the last 10 rows as a parameter. - Then the function
createTable()
updates the data table next to the Form.
Form Validation
Form validation is very important when submitting data to Google Sheets. For form validation, I have used browser defaults. However, depending on the requirements you may need more customization. You can learn more about Bootstrap form validation from this link.
We recently updated this post. If you have been working with our previous post you can access the archived version from this link.
What Next
This form covers most of the common form elements that you need to build a data entry form or any type of online form to perform CRUD operations on Google Sheets. So, you can customize this form to match with your requirements using those elements. You can learn more about this using the links provided in this article as well as from the URLs commented in the code.
When you have data on your hand, you must use data visualization techniques to spot the signals in your data. If you can build an online dashboard for your data, you can make decisions even while your data collection project is ongoing. You can learn more about building a free online dashboard from my previous post, “How to Create an Online Dashboard for free to Share and Visualize Your Data“.
Wrapping Up
Google Apps Scripts has been introduced to increase the power of your favorite Google apps. So, by using Google Apps Script with Google Apps you can build various types of custom solutions to boost your collaboration and productivity.
In this example, I explained to you how to build an Online Data Entry Form that can Perform CRUD Operations on Google Sheets. Where I used Google Sheets APIs with Google Apps Script HTML service. I have added most of the form elements that are required to build most of the forms used in your day-to-day work. So, you can expand this form to meet your requirements even if you do not have much knowledge of coding.
I wonder if an html programmer could help me as admin is not responding.
Line 72 of Code.gs has a line
return getLastTenRecords()
Which does not need any parameters or data from the user.
If I changed that to
return searchRecords(formObject)
What would I use for (formObject) to pick up the original data entered by the user in the search form – DataTable.html
I love this example and have been trying to make it work.
i thought of storing two variables in the spreadsheet for later use.
Can any html programmer please assist, i am a pick basic programmer and this part has me stumped. it fits in the bottom of code.gs in a spot where i know it passes.
Will this work ?
line.number = “2”
line.two = Sheets.Spreadsheets.Values.get(SPREADSHEETID,line.number)
line.two[10] = jText
line.two[11] = kText
Sheets.Spreadsheets.Values.update(line.two,SPREADSHEETID,line.number, {valueInputOption:”RAW”})
Love the app. I use for a demo site. If it has checkbox type with 2-3 options in FormProductDetails, it would really helpful. Thanks! – Ben
I wonder if an html programmer could help me as admin is not responding.
Line 72 of Code.gs has a line
return getLastTenRecords()
Which does not need any parameters or data from the user.
If I changed that to
return searchRecords(formObject)
What would I use for (formObject) to pick up the original data entered by the user in the search form – DataTable.html
Loved your example. and the instructions worked very well.
I am trying to build a small solution for a NFP and they cannot afford much support.
I am a basic programmer but was able to follow your code and alter parts of it.
If i get this working do you mind if i use it (once a year) i will leave your name in the source code.
Two questions if i might be so bold.
This line if (cellValue.toLowerCase().includes(searchText.toLowerCase())) {
How could I change that to be exactly equal and not includes
Also after Submit on the Product Details panel, how can i jump back to the place after searching and not reloading the data table, therefore not have to search every time
meaning… at line 75 in code.gs there is this, after submitting the changes.
//Return the last 10 records
return getLastTenRecords();
}
What i want to do is redisplay my previous search results without re-entering the search criteria
I am now stuck.
I lose my original search variables when Submit the product entry
I tried putting the values from the search in a var but it does not carry through.
How can i keep data from one screen to another ?
the closer i get the further away i feel.
I can hold ‘Search button’ entry data (now two items, not one) in a session storage but i have had no luck trying to include this code, I am not totally sure where this code should be in – javascript or code.gs but i just loop endlessly no matter where i put it.
// Save data to sessionStorage
Function createItem() {
sessionStorage.setItem(‘Judge’, jText);
sessionStorage.setItem(‘Klass’, kText);
}
// Get saved data from sessionStorage
Function readValue() {
var jText = sessionStorage.getItem(‘Judge’);
var kText = sessionStorage.getItem(‘Klass’);
}
Hi Mario,
Apologies for the delayed response. I was occupied with other tasks. I’ve made a few modifications to the Apps Script project (Code.gs file), and you can access the updated code at the following link:
https://script.google.com/d/1dOwG6FzjejIP6Z5vocy2QKK35uXLUBKDfPEHspfnQPwu-F9RREN3qZBS/edit?usp=sharing
For your convenience, here’s a summary of the changes:
* Added a new function: “getLastSearch()” at the end of the code.
* Added the line “CacheService.getUserCache().put(‘searchText’,searchText);” to the “searchRecord()” function.
*In the ‘processForm()’ function, I added the line “return getLastSearch();” inside the if condition, and moved the “return getLastTenRecords();” line inside the “else” condition.
Let me know if you have any questions.
thank you so much for the reply. it seems straightforward and an elegant way of going it.
My question – can i have two cache records ?
I have two search keys and this is the two Search routines but alas modifying my code to be like yours is getting “Data not found” on the second pass.
//SEARCH RECORDS
function searchRecords(formObject) {
let result = [];
try {
if (formObject.searchText) {//Execute if form passes search text
const data = readRecord(DATARANGE);
const jText = formObject.searchText;
const kText = formObject.searchTextk;
const k = 7
// Loop through each row and column to search for matches
for (let i = 0; i < data.length; i++) {
for (let j = 6; j < data[i].length; j++) {
const cellValue = data[i][j];
if (cellValue.toLowerCase().includes(jText.toLowerCase())) {
const kValue = data[i][k];
if (kValue.toLowerCase().includes(kText.toLowerCase())) {
result.push(data[i]);
break; // Stop searching for other matches in this row
}
}
}
}
CacheService.getUserCache().put('searchText',searchText);
CacheService.getUserCache().put('searchTextk',searchTextk);
}
} catch (err) {
console.log('Failed with error %s', err.message);
}
return result;
}
function getLastSearch() {
let jText = CacheService.getUserCache().get('searchText');
let kText = CacheService.getUserCache().get('searchTextk');
let result = [];
try {
if (jText) {//Execute if form passes search text
const data = readRecord(DATARANGE);
// Loop through each row and column to search for matches
for (let i = 0; i < data.length; i++) {
for (let j = 6; j < data[i].length; j++) {
const cellValue = data[i][j];
if (cellValue.toLowerCase().includes(jText.toLowerCase())) {
const kValue = data[i][k];
if (kValue.toLowerCase().includes(kText.toLowerCase())) {
result.push(data[i]);
break; // Stop searching for other matches in this row
}
}
}
}
}
} catch (err) {
console.log('Failed with error %s', err.message);
}
return result;
}
wow oh wow – it works
Thank you so much – i love the result
excuse my bad above, i missed one thing in the conversion
thank you so much BR
Hello
I am trying to implement a CRUD with the help of this work that has been shared.
From already thank you very much.
I am experiencing an error I think in bootstrop, which causes the search engine to not display.
I will appreciate if you help me solve it.
Uncaught TypeError: Cannot read properties of undefined (reading ‘fn’)
at util.js:55:5
at bootstrap.bundle.min.js:6:167
at bootstrap.bundle.min.js:6:204
Hi.
I need a solution similar to this one but i need to have form in a web page and table with results in other. Is possible to do it? Can you explain how i can split it? Thank you.
Hi, nice work here. I am loving it and I see a lot of use case scenarios for this.
How possible is it to create filters for the data?
How to display data using cascading dropdown
Thanks once again.
Reply
How can i replace dropdown with multipleSelect dropdown with search function?
ii have tried to run this webapp but its not running . can I get a copy of googlesheets which contains the apps script to email address :
As I explained in the post, this example uses Standalone Scripts (Ref. https://developers.google.com/apps-script/guides/standalone). To get it working, you need to copy both the Google Sheet and the Apps Script file to your Drive separately. After that, you should replace the SPREADSHEETID (line 8 of Code.gs file) with the copied Spreadsheet ID. Then deploy the web app, and it should start working.
I’m planning to upload a how-to video soon for the updated post, but in the meantime, you may watch the following video that demonstrates our previous post to learn how to get it working. https://www.bpwebs.com/humix/video/67dd54482651c978bf16cb3b98380db04065e63eb79f0bb23c48fce0cd1060a8
This is great. Records are showing up in the Google Sheet on form submission but are not showing in the Data Table. Any ideas?
thank you .. it work good ..
Hi, first of all thanks for everything!
I have added many fields to the form and everything works apart from one small issue. When I edit the entries, all the fields are not populated. would you know why? I have a total of 25 fields. Please let me know if possible. Thanks.
I’m facing the same issue. Have you found the solution? Thanks
first of all thanks for the sharing.
i got error when i try clik edit button
it says “unchaught TypeError : Cannot read property ‘value’ of null’
I’m trying to combine this and the Sidebar/Modal functions. Yet for some reason the HTML and CSS between these two are written vastly differently. When I try to use the Sidebar code here, it ends up not processing the includes correctly.
Is there a combined sample I could start with? I have some pretty advanced apps scripts but really need to add HTML dialogs and was hoping this would help me do that. I need the CRUD features combined with the dialogs. Currently I’m using onEdit on a spreadsheet dashboard but it doesn’t allow for multiple users simultaneously as well.
Hello,
Nice work! It worked fine once I added the Sheets Service.
I tried to Deploy so other users could add their contacts but it doesn’t display the Country of the GetData. It was Deployed as any user with the link.
Its almost as if the Sheets Service is not connected.
Thoughts?
Thanks,
Mike
Never mind! I deployed as “User Accessing the web app”. I changed to “Me” and it worked fine.
Hi, nice work here. I am loving it and I see a lot of use case scenarios for this.
A quick question: How possible is it to create filters for the data?
In a way that multiple drop-down boxes are presented and the data gets filtered based on the data in the drop-down boxes.
Thanks once again.
Can you help me? I have changed the sheet ID in line 15, but the table does not get created for some reason.
I had modified the file to capture material data but in excel math operation is not happening as the form is storing data with ‘. like ’30 for 30.
please help
Hi! Great instruction and tool. I’ve got some additional question. Would that need a many adjustments go get only data only reported by current user using the web app?
How i can check duplicate key a specific COLUMN, I don’t want check uniqeID from ID column, but i want to check and return data depend value on specific column