{"id":6043,"date":"2025-01-22T03:58:48","date_gmt":"2025-01-22T03:58:48","guid":{"rendered":"https:\/\/obsidiansofteducation.com\/?page_id=6043"},"modified":"2025-01-22T04:02:49","modified_gmt":"2025-01-22T04:02:49","slug":"update-google-sheet-mit-app-inventor","status":"publish","type":"page","link":"https:\/\/obsidiansofteducation.com\/index.php\/update-google-sheet-mit-app-inventor\/","title":{"rendered":"Create, Read, Update and Delete Google Sheet in MIT App Inventor"},"content":{"rendered":"\n<p class=\"has-medium-font-size\">Hello friends and welcome to Obsidian Soft<\/p>\n\n\n\n<p class=\"has-medium-font-size\">In my previous tutorials on Google Sheets, I showed you how to easily write to a Google sheet using forms and also read the entire sheet into the MIT App Inventor app. This was a simple and easy approach that came with limitations. We couldn\u2019t update the rows or delete rows programmatically. We also couldn\u2019t differentiate between different sheets in our spreadsheet. In this tutorial, which I will try my best to simplify, we will not just create rows in Google Sheets but also delete or update a particular row through our MIT App Inventor app. We will also use sheet names so that if our spreadsheet has multiple sheets, we can do our operations on a particular sheet.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">So, let\u2019s begin. First of all, let\u2019s make a google sheet:<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><a href=\"https:\/\/docs.google.com\/spreadsheets\/u\/0\" target=\"_blank\" rel=\"noopener\"><strong>https:\/\/docs.google.com\/spreadsheets\/u\/0<\/strong><\/a><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Make sure that you are logged in using your Gmail account. Click on the + button to create a blank spreadsheet.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Add some headers in the first row of the sheet: <strong>ID<\/strong>, <strong>Name<\/strong>, <strong>City<\/strong><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Also, rename the sheet1 to <strong>Customers<\/strong>. Add some sample data to it too.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdfopeWYXdI-O8gXAw4GIHgyhFQpQDW51N17jHtkPkxXB5WaFTUd_4wn-kbux-ra6teUol7qWXmjKuoCJ-dzGj1QIaoJa_2agU_rwTlFlLzsrhWp7xVhu2cxZZdKG9YaJ6eItlymAkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:317px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, look at the address bar in your browser. You will have the spreadsheet\u2019s URL there:<\/p>\n\n\n\n<p class=\"has-vivid-cyan-blue-color has-text-color has-link-color has-medium-font-size wp-elements-a47341221c17707f8bbbb7e6ead0f906\">https:\/\/docs.google.com\/spreadsheets\/d\/<strong>1n5kGHrAhhIhYph0c-tRedRtlILqv8aRCEyYtDeDnBJ<\/strong>\/edit?gid=0#gid=0<\/p>\n\n\n\n<p class=\"has-medium-font-size\">The highlighted part between d\/ and \/edit is the id of your spreadsheet. Please don\u2019t use mine. You have to create your own spreadsheet. Copy and paste this URL in some text editor like notepad as this is our spreadsheet id.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Now, navigate to <strong>Extensions &gt; Apps Script<\/strong> in the spreadsheet menu. A new browser window will open up.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdcf4vDNCTSe6WPqtAAmDGj4fzPn1fme8uHaxVK9Fq_JaGWUPnxEu-hrxUudYCwZHYcaPYPKLX_YZHRL7Nt_fMXzBg4LkG_f8M_AhJTCazjWxSYHREkX0Bacyj0EkfiZMmthlWbkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:668px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Remove the code from it. Copy and paste the following code in it but remember to update your spreadsheet id with the one that you got from the browser URL and that you had copied and pasted in Notepad. You have to do it for both doGet and doPost functions in this script. Also, you will have to update the script for your parameters. For example, I have id, name, and city but if you have different parameters, change it accordingly. I will explain more about this change later.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Don\u2019t forget to update the spreadsheet id for both doGet and doPost functions.<\/p>\n\n\n\n<pre class=\"wp-block-code has-text-color has-link-color wp-elements-8c53fd790358ce364a2be1a15cfed782\" style=\"color:#8e1a1a\"><code>function doGet(e) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;const sheetName = e.parameter.sheetName || \"DataSheet\";\n\n&nbsp;&nbsp;&nbsp;&nbsp;const spreadsheet = SpreadsheetApp.openById(\"your-spreadsheet-id\"); \/\/ Use your sheet ID\n\n&nbsp;&nbsp;&nbsp;&nbsp;const sheet = spreadsheet.getSheetByName(sheetName);\n\n&nbsp;&nbsp;&nbsp;&nbsp;if (!sheet) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"error\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"read\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Sheet not found\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;const range = sheet.getDataRange();\n\n&nbsp;&nbsp;&nbsp;&nbsp;const values = range.getValues();\n\n&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"success\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"read\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;data: values\n\n&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n}\n\nfunction doPost(e) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;const data = JSON.parse(e.postData.contents);\n\n&nbsp;&nbsp;&nbsp;&nbsp;const sheetName = data.sheetName || \"DataSheet\";\n\n&nbsp;&nbsp;&nbsp;&nbsp;const spreadsheet = SpreadsheetApp.openById(\"your-spreadsheet-id\"); \/\/ Use your sheet ID\n\n&nbsp;&nbsp;&nbsp;&nbsp;const sheet = spreadsheet.getSheetByName(sheetName);\n\n&nbsp;&nbsp;&nbsp;&nbsp;if (!sheet) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"error\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: data.action,\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Sheet not found\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;if (data.action === \"add\") {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sheet.appendRow(&#91;data.id, data.name, data.city]);\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"success\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"add\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Row added successfully\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;} else if (data.action === \"update\") {\n\n&nbsp;&nbsp;&nbsp;&nbsp;const range = sheet.getDataRange();\n\n&nbsp;&nbsp;&nbsp;&nbsp;const values = range.getValues();\n\n&nbsp;&nbsp;&nbsp;&nbsp;let rowFound = false;&nbsp; \/\/ To track if the row is found\n\n&nbsp;&nbsp;&nbsp;&nbsp;for (let i = 1; i &lt; values.length; i++) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (String(values&#91;i]&#91;0]).trim() === String(data.id).trim()){\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\/\/ Update the name and city\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sheet.getRange(i + 1, 2, 1, 2).setValues(&#91;&#91;data.name, data.city]]);\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rowFound = true;\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"success\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"update\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Row updated successfully\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;\/\/ If no matching row is found\n\n&nbsp;&nbsp;&nbsp;&nbsp;if (!rowFound) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"error\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"update\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Row not found\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n}\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (data.action === \"delete\") {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const range = sheet.getDataRange();\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const values = range.getValues();\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (let i = 1; i &lt; values.length; i++) {\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (String(values&#91;i]&#91;0]).trim() === String(data.id).trim()){\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sheet.deleteRow(i + 1);\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"success\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"delete\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Row deleted successfully\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"error\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: \"delete\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Row not found\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}));\n\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;return ContentService.createTextOutput(JSON.stringify({\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;status: \"error\",\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;action: data.action,\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;message: \"Invalid action\"\n\n&nbsp;&nbsp;&nbsp;&nbsp;}))\n\n}<\/code><\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-medium-font-size\">You can see in the following screenshot that I have copied pasted the code and updated the spreadsheet id. I have also renamed the project to Web App for MIT App Inventor.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdsWW1VhM9m30e5QVGQK18dnXU4G1o-hxbwa52U2WDOo1TE6WIErswLbqIXK2iVOd8TQYTXIN_rDTR2gFqG73FVnS1yDloPr3Wutb8PgxnpfgzhZeMqidJhg03rMATvW5bUp0CBkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:636px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, click on the deploy button.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Choose<strong> New deployment<\/strong>.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Choose <strong>Web app<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXe7hrLFVZByUP2QK2qYgtKQCxnOUtX3MPySO-ayMqzktzR0ZjFtWG0ueBkZWYOpwFCoxfPBeNlaqkVZCZneadS8MLFQ6NVh0Dkv9iCG6VGPc4dMdtn-DEs8GZgMfRCR39SemKUdkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:614px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Set the <strong>Execute as<\/strong> field to <strong>Me<\/strong>.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Set the <strong>Who has access<\/strong> field to <strong>Anyone <\/strong>and click on <strong>Deploy <\/strong>button on the dialog.<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdEFvS2p4iVIbsqiLaRchmaQjqFAfExBInJJrB8KHsUq0mukE2mtv__0TtgMLmlE4on5_VCNduOZvc8kxXvVMmFbtn2J8AmCZS5AecEaXGHUT7o3C2WdKBDxreLl4M1gSshQaiKegkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" width=\"602\" height=\"339\"><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Since it is a new deployment, a new authorization dialog will pop up. Click on the <strong>Authorize access<\/strong> button.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcsn-v_Lf3Qf1kUgtTfsptCcwy_kgtJgg8iNnww4wgBfc55ivp6l7gP6JiZPrObc7sFXFch1BpbHgNaKPYdU1TS73LDYSenHODLUmOfrXZ0XWfKH1UP_UO8cB1d9pLsz3XLyO9skeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:604px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">You will be asked to choose a Google Account. Choose it and click on the Advanced link on the dialog that pops up.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcl1yr-L5wHFr94gLqTwzVbnVXOdWmstilZfumMzAphu184N_yCWkIOZJdWVl2G5zScrj6X7ajHE-wPvwEz7dJJgOzJEdbPEvGh-lCzaCwZPz33Tx3G8gmq4LCPL3zgZO228IlDagkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:603px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Click on the Go to \u201cproject name of your web app\u201d. I had renamed it to \u201cWeb App for MIT App Inventor\u201d. If you haven\u2019t renamed it, it will say \u201cUntitled Project\u201d.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcYMNrG6k8JgyHSnIHK47eADOrMqv19lpCCs5FiQaALZXh5ci0YrWZ0GafEkLRneI-cvV4OJJdKloFFW08TlgDif4YpsDIRvIfUC7v54uhVfxJVnYkC3eat0gBkLgvB82RbklJJNQkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:501px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Another dialog will pop up. Scroll down and click on Allow button.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXecrQ5SHS5s5nG3DPbDy3NiqhaZHe02HnmbIlAofiszsJ8Ox3SwzFz9qaNKo-Kgl9tb3VOcd4SaJ8eyfwswyQ9V_XRIweDI4BuKgSt26K5hzCAvmixIkrEQJZmvJLVEiIv-DooZeQkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:627px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Copy and paste the web app URL into a text editor like notepad as we will need it later.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXfxYBkKDNvohoNJ6CzfAt9fFt_TczZtSppZT-8InK3BYl7YFESoLjMAnI8JX4hWoP9x-SfAwQqwYuEJHA2PvA5x4yd3Vq80MZHypQBgDkrOwKVbFfoUd1m8DjO7dfwjYRuzrfxjMgkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:628px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">(At any time, if you make a change to the web app script, you have to click on deploy button again and and choose manage deployments and save changes)&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Now, Open up MIT App Inventor and start a new project. Name it CRUDGoogleSheet.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Drag and drop a vertical arrangement from the Layouts palette onto the viewer. Rename this arrangement to mainScreen. Make width and height both fill parent.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Drag a listview from the user interface palette onto this mainScreen vertical arrangement and in its properties, make width: fill parent.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Add a horizontal arrangement from layouts below it. Make align horizontal and align vertical both center. Make height 15% and width fill parent. Drag and drop a button from the user interface palette inside this horizontal arrangement. Rename to addBtn. Make the background color blue, font bold, font size 20, width 30%, shape rounded and text: Add. Select the button and duplicate it by pressing Ctrl + C and Ctrl + V on the keyboard for windows OR Command + C and Command + V on the keyboard for MacOS. Rename it to updateBtn and change text to \u201cUpdate\u201d. Duplicate again and rename it to deleteBtn and change text to \u201cDelete\u201d. Now, select the mainScreen vertical arrangement and in its properties, uncheck the \u201cVisible\u201d checkbox.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Now, add another vertical arrangement onto the viewer. Rename it to addScreen. Make width and height fill parent. This is the concept of virtual screens. There is no need to pass data between two screens as we are technically still on the same screen.&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Drag and drop a horizontal arrangement onto this addScreen vertical arrangement. Make align horizontal and align vertical both center. Make height 15% and width: fill parents.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Add a label from user interface to this horizontal arrangement. Rename it to idLbl. And change text to \u201cID:\u201d.&nbsp; Add a textbox from the user interface on the right of the label. Rename it to idTxt.&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Select the horizontal arrangement, duplicate it and update it for Name. Do the same thing for city<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Duplicate horizontal arrangement again and remove the label and textbox from it. Add a button. Rename it to saveBtn. Give it the same properties as the ones that you gave to the addBtn. Change the text to \u201cSave\u201d. Select the button. Duplicate it and rename it to cancelBtn and change the text to \u201cCancel\u201d.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Drag a web component from the Connectivity palette onto the viewer. Also, drag a notifier from the user interface onto the viewer.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Now, select the addScreen arrangement and make it invisible by unchecking the visible checkbox.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Make the mainScreen visible by checking the visible checkbox.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Our screen design is done so let\u2019s go to the blocks section.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Make a global variable for sheetData (an empty list in the beginning)<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Another variable sheetName and set it to your sheetName (in my case, it is \u201cCustomers\u201d).<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Add a status variable called action (this will play a role in updating, adding, and deleting). Also, add a global variable for webAppURL and set it to your webAppURL that you had copied earlier.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXfTHWDw2hVkf6s5xCIBOEI-3bQSPjksbBinBiMqze84AtZNQbLD_IqbTuZLkH7cuEcVjFfPVW0XmDb9H2CCFD7xHwVhDIogCax18LMPoX5OZ3erOOzKLo5MUV37tff4LAKV04-pyQkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Get the screen1\u2019s initialize event.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Make addScreen visible to false and mainScreen visible to true. This is an extra step to make sure that the correct screen is visible when the app is started.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Click on the web1 component and get its setUrl block.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Set it to a join block with 3 slots. You can click on the cog wheel to add more slots.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Put the get block for webAppURL in the first slot. In the second slot, add a text block with this:&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>?sheetName=<\/strong><\/p>\n\n\n\n<p class=\"has-medium-font-size\">In the third slot, plug in the get block for the global variable sheetName. After this call Web1.Get.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdBxHqhw92-Jj1RWXUjXwqFzBoTo6FIkBGtlKsqyOca-bqDjBBeYYrFGF4NoR2Twy9Z5g8jW4t9-OBULGurgoiFvDxFyNb1L7YL_v4_euaJQiDtKzEsEpRpcdcDuilBRQNALb5_YQkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">In web1. gotText event, responseContent contains the response returned by the Web app. Make one local variable for responseDict. Use Web1\u2019s procedure JsonTextDecodeWithDictionaries to decode the ResponseContent and store it inside the local variable responseDict.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Web1.gotText event is triggered after get or post call to the web app so we need to differentiate between reading sheet data and updating\/adding\/deleting. Use an if\/else block from control to check if the value for key \u201caction\u201d inside responseDict is \u201cread\u201d.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXfy6bZIzv9OpsFZPQcw6l3M_Y0J08TqhcBhkBt4b9UnYd3ACnngbts_xFwfclpeN5eLeKp94R3-CabfWVmau9nt-dfe-YKzrH1rVr4Lu8sEC9Pq0qhZBZhwolS3bFVicg5DyDkjkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">&nbsp;If it is \u201cread\u201d then use a for each item loop from control to go through the value returned against key: \u201cdata\u201d inside our responseDict which is actually a list of lists. For each item (row) in this data, get cell data and join it all using \u201c-\u201d to make one long text item and add that item to the sheetData list.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXfCxEj_AbZ1rZmY0dhO1hNKbxpMhgBpUOBCLaiW9x2tu8QNiY6l39HZfVILmhx2JizW9pFa1_h636-ck6RSikQBhixqQ1wOKhNCsL03IN32gf0GLanGi5jP0B60pptAG195ZFjqkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">After the for loop, check if sheetData isn\u2019t empty. It will be empty if the sheet is completely blank (not even column names) or if there is some error. If it isn\u2019t empty, remove the first item from SheetData as these are the column names from the sheet i.e. ID, Name, and City. Then, provide this updated SheetData list to the listview\u2019s elements.&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcvnHI7w2wRX4Dy8Mfc5HJhSwb6E4YOLRH16tyaRM-6TX356ZrzVp2EDXH0aRVD1YGmMqYZAsMn1QYELSuJJ2zUAkH8u4ljlsQKFxM5nMjDhBZhiE-YglAiebPw3MGEgU9qPhEYkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">At the end of the if\/else block, add another if for checking for any message from the web app, and if there is any, use the notifier to show this message. So, our web1.gotText looks like this now:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXc-S60GvBVO_vQrN6cBqaAlQCpUxUvrNxTqNW6EBO4MBbcsyzNknChsM38Tz36Cb0Rkc6y79OEyJjBQeTdsPm9-dCf-4iGtVwkS6mom75Or8o7zretIqGzCx_pupaQXB2xjs4zOUwkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Try the app now and it should read the sample data from Google spreadsheet and show an error if we provide the wrong sheetName.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Before working on our add, update and delete, let\u2019s look at our web app script again. You can open it again by navigating to <strong>Extensions &gt; Apps Script<\/strong> in the spreadsheet menu.<\/p>\n\n\n\n<script async src=\"https:\/\/pagead2.googlesyndication.com\/pagead\/js\/adsbygoogle.js?client=ca-pub-6094106103908730\"\n     crossorigin=\"anonymous\"><\/script>\n<!-- Tutorial Custom WP Ad -->\n<ins class=\"adsbygoogle\"\n     style=\"display:block\"\n     data-ad-client=\"ca-pub-6094106103908730\"\n     data-ad-slot=\"5828030452\"\n     data-ad-format=\"auto\"\n     data-full-width-responsive=\"true\"><\/ins>\n<script>\n     (adsbygoogle = window.adsbygoogle || []).push({});\n<\/script>\n\n\n\n<p class=\"has-medium-font-size\">We will call the function doPost from our MIT App Inventor app when we do any kind of updating in our Google sheet.&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Hence, you need to edit this if your column numbers in the Google Sheets are different from the ones that I have used.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Let me reiterate:<\/p>\n\n\n\n<p class=\"has-medium-font-size\">We have 3 columns: ID, Name, City. When we update, we don\u2019t update the ID, we just update the name and city.&nbsp;<\/p>\n\n\n\n<p class=\"has-medium-font-size\">So, let\u2019s look at the script:<\/p>\n\n\n\n<p class=\"has-medium-font-size\">In our update, we look for the row in the sheet where the ID is the same as the ID sent by our app. Then, we update the values in the following way:<\/p>\n\n\n\n<p class=\"has-medium-font-size\">&nbsp;\/\/ Update the name and city<\/p>\n\n\n\n<p class=\"has-medium-font-size\">sheet.getRange(i + 1, 2, 1, 2).setValues([[data.name, data.city]]);<\/p>\n\n\n\n<p class=\"has-medium-font-size\">This is what each value means:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>sheet.getRange(row, column, numRows, numColumns)<\/strong><\/h3>\n\n\n\n<p>This method selects a range of cells in the Google Sheet based on:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li class=\"has-medium-font-size\"><strong>row<\/strong>: The starting row number of the range.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>column<\/strong>: The starting column number of the range.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>numRows<\/strong>: The number of rows in the range.<\/li>\n\n\n\n<li class=\"has-medium-font-size\"><strong>numColumns<\/strong>: The number of columns in the range.<\/li>\n<\/ul>\n\n\n\n<p class=\"has-medium-font-size\">Our update starts from the second column so this is why the second value is 2:<\/p>\n\n\n\n<p class=\"has-medium-font-size\">sheet.getRange(i + 1, 2, 1, 2).setValues([[data.name, data.city]]);<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Our update updates a total of 2 columns i.e. name and city, this is why the last value is also 2.<\/p>\n\n\n\n<h2 class=\"wp-block-heading has-medium-font-size\"><strong>A different scenario:<\/strong><\/h2>\n\n\n\n<p class=\"has-medium-font-size\">If I have a fourth column in my sheet such as age, my code would change to:<\/p>\n\n\n\n<p class=\"has-medium-font-size\">sheet.getRange(i + 1, 2, 1, 3).setValues([[data.name, data.city, data.age]]);<\/p>\n\n\n\n<p class=\"has-medium-font-size\">We start updating from the second column, updating one row and a total of 3 columns.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">If I had a column besides the ID that doesn\u2019t have to be updated. For example, I want to update only city and age so then, my code will change like this:<\/p>\n\n\n\n<p class=\"has-medium-font-size\">sheet.getRange(i + 1, 3, 1, 2).setValues([[ data.city, data.age]]);<\/p>\n\n\n\n<p class=\"has-medium-font-size\">We start updating from column no. 3, updating one row and a total of two columns.<\/p>\n\n\n\n<p class=\"has-medium-font-size\"><strong>If you make any changes to the app script, remember to deploy it again.<\/strong><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Get addBtn click event. Make mainScreen invisible and addScreen visible. Set action to \u201cadd\u201d to differentiate between adding and updating. Also, empty the 3 textboxes so that if we come to this screen again, the old data isn\u2019t there anymore. Moreover, enable the idTxt as we will be disabling it when we use this screen for update.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcU4k0tT8pRmAUtlq3m8EaxxyYSxuMhkqtb-saMhaQqBFrww6_pMhT1ck6v_HS1-F-mc_U9P4x1A3tSP-3qkTH9ACaUzcVEg7-Z6c2LdpZW4a9xs1FjrvchURcdIAM1jCo-dVRqGwkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:567px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Get saveBtn click event. And set Web1.url to the webURL global variable.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdktzGrBWkBp7nQIkC25mQIvQ5jz0zRyxYw-CWLm6HM3cOOeAg5yrlsmpx5QM46m6o_K-0BNR5I4TR2BH-O3av4XOsf4yCjYcwfmP_i3p7JdXLZYuMk6CyRl7ES8VXGUErABQYK6wkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:624px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, call Web1.postText procedure and we will provide it a join of 11 things that you have to construct very carefully to avoid errors.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li class=\"has-medium-font-size\">{&#8220;action&#8221;:&#8221;<\/li>\n\n\n\n<li class=\"has-medium-font-size\">getaction block<\/li>\n\n\n\n<li class=\"has-medium-font-size\">&#8220;,&#8221;sheetName&#8221;:&#8221;<\/li>\n\n\n\n<li class=\"has-medium-font-size\">getSheetName block<\/li>\n\n\n\n<li class=\"has-medium-font-size\">&#8220;,&#8221;id&#8221;:&#8221;<\/li>\n\n\n\n<li class=\"has-medium-font-size\">idTxt.Text<\/li>\n\n\n\n<li class=\"has-medium-font-size\">&#8220;,&#8221;name&#8221;:&#8221;<\/li>\n\n\n\n<li class=\"has-medium-font-size\">nameTxt.Text<\/li>\n\n\n\n<li class=\"has-medium-font-size\">&#8220;,&#8221;city&#8221;:&#8221;<\/li>\n\n\n\n<li class=\"has-medium-font-size\">cityTxt.Text<\/li>\n\n\n\n<li class=\"has-medium-font-size\">&#8220;}<\/li>\n<\/ol>\n\n\n\n<p class=\"has-medium-font-size\">Our final saveBtn click event looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXeFg-jF4TI7g1Vs1jRriQ6imPqwNKDbX6dmERGNVJzRKMu3stSKABOKXPU_dnaAp5R_BpFkIRr3rRQwmhi13m1VZ4peq-LqL0NERWNsdjo8_wHqqhwb99IMKAHKIewLq8xhbLRs1QkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:620px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, let\u2019s go back to our Web1.gotText event. The event is triggered whenever we get any response from the Web app after a call such as Web1.get or Web1.postText.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">So, it will also be triggered after the save button is clicked.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Click on the cog wheel for the first if\/else block in Web1.gotText event, add 4 else if to it, and remove the else.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXf6EiAC5WHD0mrDQ-NiGr0MEOKn4cgCtNdv5GwqgE1JPJPGiBqt2M7cs7azBaj4wkdCEnbygEZuwYOqpOVIKer8s7BFHuqa7eNUydk6EKEeghnZ5l521adC8sqsBeZPNGOL3H36NAkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:640px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, in the first else\/if, we will check if our value for the action key is \u201cadd\u201d and the status key&#8217;s value is \u201csuccess\u201d in our responseDict.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXeHamhfgdwE598W3rgtQ7jyOATW54pCdW2ONbtFwEGNqfoTTN4Is5uwDf6TPh1q5oIIX08IgeEbU31I-_eA9OHk2LfYOT5ozQt5AKT1apDUbnTZeQfFHqTaET3keRlyB3JXTP2F5gkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:644px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">This means the add was successful, so we will add the item to our sheetData, update our list view\u2019s elements, hide addScreen, and make mainScreen visible..<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdcYUsoixQjVu2XwBMjKOS-ZbqeY6Iksc0t4waJW5MhHOn_hQUrZLSScMQVodsmBhjeEA-uDG4rUq-Cj6NAVkMVaoa-FEV5ZTsNX4S2cbLwLnpCACi6mQ2EFEpHwQ-TFjErNphdCgkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:643px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, let\u2019s work on updateBtn click event. In this case, we have to first check that the user did select an item on Listview before pressing update button. If he did choose then the selection index will not be 0. After that make the update screen visible while hiding the mains screen. Disable the idTxt so that the user isn\u2019t able to update the id and set the action variable to \u201cupdate\u201d so that our web app can differentiate. And most importantly, populate all the text boxes with the selected item\u2019s data. Remember that we had joined everything with \u201c &#8211; \u201c so have to split the text using it to get all individual cell items back.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdGxRCC0_22eCD65G4XeckBAZl4vL1BCXzsgnUvum5yyPrMxUHM6bchw3o9462NKAqd_Xkp_5hPsOWfbFCka1JTXzW1HOsHU0Bk2zCm0MjF8bnAxXseWS5Z04fJdzL52tuW9V397gkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:607px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">The save button code will stay the same but remember the cancel button. If the user cancels, just go back to the previous state of hiding addScreen and showing the main Screen.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdeYyH-pPhBybkLPEQbo0_-vrwsoGJsiJLe-cb_KEZwPMwoPllbmG14JaovhOpf2GNnpWDef2Gmhu1OV_pkgBN5IhrNEXJZ-s-eY1T7QLr4AkVlZSmJJ1vM5SE7cvsyyT1NsZLukeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:585px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">In our web1.gotText event, let\u2019s handle the update scenario.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">For the next else if, do the following. Here, instead of adding to SheetData, we just replace it with updated data.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcOI0Re5rnta1Ytnn2osLuzizXhVfrOA2kl5Ndy7OuUGNSwXPgTHvbb5Ku_alnTRvVKE-8JP63kTjCVxqBxF0P_VFIFAYZ1iw5KJSdGDO_8Ss1K9THMaHRnxo_FR8sMklOXtXDrYwkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:746px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">Now, let\u2019s come to the delete button click event.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Again, we need to check that something was selected from the listview before pressing the delete button. We set the action to \u201cdelete\u201d to inform our web app and we also again get individual cell items back and we call Web1.postText but this time we don\u2019t send the name and city but just the ID.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXf3FSwfx8MFbS1XxgBpzShUz6OZUpscB8F1d5jYNIXz4bSg6IFYnox94fpa_qQjqxtkKgl4M9-J5Zq6UXhtdqI9VP1Beto9fsM9fcEebpFXRDS8KHVwiwpJD548pYbtrEJzjJ-FiwkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:627px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">In our web1.gotText event, let\u2019s handle the delete scenario.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">For the next else if, do the following i.e. delete the data for selection index from sheetData and update listview\u2019s elements.<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXcln0W4-gYJqRYJ4Lmc0sMu5m-ntYbcxjMoc17HqG0umjMmXE6eobVpVH5ZSJXAClCRhaYCR9ibLuZwplE6-Oodr6tHCcGijWjce2jGWKokejVKhlGeS5ubJkF_0D50Trx8nME2keyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:657px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">The last else if is for the situation when there is any error:<\/p>\n\n\n\n<figure class=\"wp-block-image is-resized\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXf6aG-HVTmGgvVMl-_PGID89P_LzuMzsE0S3nurlbvyfu8EO2OAUnkH4TsjbP8PC8NAoYxEvxH25aEusE_9Sd8XhmmmmMYBZJdmy7u9Z7mDqgP93vptOJliczqnDkXuyHz4Fn7vcgkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\" style=\"width:616px;height:auto\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">In this situation, just make the default mainScreen visible and hide addScreen.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">So, our final Web1.gotText event looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2025\/01\/AD_4nXdlT9pYCSOFfab5V_3AMUx0y0cVwcLpiUUv7AtTJ2ffF_1P9aGqV_2Z3x2VhVXnq3GFT8I2gG718PEGY4Mz9UrjI0Xg_LjODoz0RD_HkUau38Ba3k4PRK4IGWdhfdnSDYIfIHuQkeyKEzxRLdkJSQ2v3NKxoPMfSPG.png\" alt=\"\"\/><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">By the way, while making this tutorial, I thought that I should cover automatic ID generations similar to SQL databases to avoid duplication of IDs. If you are interested, do comment to let me know.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">So, this is done. You can check out the two video tutorials for updating and deleting google sheets in MIT App Inventor below:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<p class=\"responsive-video-wrap clr\"><iframe loading=\"lazy\" title=\"App Inventor Google Sheet Tutorial  P1 - Read and Update Google Sheet MIT App Inventor #appinventor\" width=\"1200\" height=\"675\" src=\"https:\/\/www.youtube.com\/embed\/4HACaophVto?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<\/div><\/figure>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<p class=\"responsive-video-wrap clr\"><iframe loading=\"lazy\" title=\"App Inventor Google Sheet Tutorial  P2 - Read and Update Google Sheet MIT App Inventor #appinventor\" width=\"1200\" height=\"675\" src=\"https:\/\/www.youtube.com\/embed\/PLZoJWz5Ykg?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<\/div><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">If you like my tutorials, consider supporting me:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter is-resized\"><a href=\"https:\/\/obsidiansoft.gumroad.com\/l\/cxdft\" target=\"_blank\" rel=\"noopener\"><img loading=\"lazy\" decoding=\"async\" width=\"372\" height=\"196\" src=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2024\/12\/donate-button-1.png\" alt=\"\" class=\"wp-image-5381\" style=\"width:270px;height:auto\" srcset=\"https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2024\/12\/donate-button-1.png 372w, https:\/\/obsidiansofteducation.com\/wp-content\/uploads\/2024\/12\/donate-button-1-300x158.png 300w\" sizes=\"auto, (max-width: 372px) 100vw, 372px\" \/><\/a><\/figure>\n<\/div>\n\n\n<p class=\"has-medium-font-size\">Don\u2019t forget to subscribe to my channel if you like my work so that you don\u2019t miss the great projects that I have planned for you. Thank you for watching. Have a good day and goodbye.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Check out my other written tutorials for MIT App Inventor&nbsp;<a href=\"https:\/\/obsidiansofteducation.com\/index.php\/mit-app-inventor-projects\/\"><strong>here<\/strong><\/a>.<\/p>\n\n\n\n<p class=\"has-medium-font-size\">Please like my social media pages for more educational resources and tips.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Facebook:<a href=\"https:\/\/www.blogger.com\/blog\/page\/edit\/4947000819484484884\/7140650632339107612#\" target=\"_blank\" rel=\"noopener\">&nbsp;https:\/\/www.facebook.com\/ObsidianSoftClasses<\/a><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Instagram:<a href=\"https:\/\/www.blogger.com\/blog\/page\/edit\/4947000819484484884\/7140650632339107612#\" target=\"_blank\" rel=\"noopener\">&nbsp;https:\/\/www.instagram.com\/obsidiansoftapps\/<\/a><\/p>\n\n\n\n<p class=\"has-medium-font-size\">Pinterest:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-rich is-provider-pinterest wp-block-embed-pinterest\"><div class=\"wp-block-embed__wrapper\">\n<div class=\"oceanwp-oembed-wrap clr\"><iframe loading=\"lazy\" title=\"Obsidian Soft\" src=\"https:\/\/assets.pinterest.com\/ext\/embed.html?grid=obsidiansoft&#038;src=oembed\" height=\"900\" width=\"450\" frameborder=\"0\" scrolling=\"no\" ><\/iframe><\/div>\n<\/div><\/figure>\n\n\n\n<p class=\"has-medium-font-size\">For links to free educational apps, have a look at the&nbsp;<a href=\"https:\/\/obsidiansofteducation.com\/index.php\/mobile-apps\/\">educational apps page<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hello friends and welcome to Obsidian Soft In my previous tutorials on Google Sheets, I showed you how to easily write to a Google sheet using forms and also read the entire sheet into the MIT App Inventor app. This was a simple and easy approach that came with limitations. We couldn\u2019t update the rows [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-6043","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/pages\/6043","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/comments?post=6043"}],"version-history":[{"count":2,"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/pages\/6043\/revisions"}],"predecessor-version":[{"id":6074,"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/pages\/6043\/revisions\/6074"}],"wp:attachment":[{"href":"https:\/\/obsidiansofteducation.com\/index.php\/wp-json\/wp\/v2\/media?parent=6043"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}