I have created a sheet in Google Sheets that is basically a form users fill out. They fill in the blanks, then press a button to run a script based on the data. However, no matter how I warn them, they don't exit the last field before clicking the button, and the script perceives that the last field is empty. I have tried letting the script activate another field on the screen, but it doesn't seal in the value before doing that. Is there another command that can force the value to be written to the field?
As an additional option to what Troy123 mentioned you can try the following script to detect blank values and display an alert if there is one before running the code you are using to submit the form.
Script:
function alertMessage() {
let ss = SpreadsheetApp.getActive().getSheetByName("Sheet2");
let lR = ss.getLastRow();
let lRValues = ss.getRange(lR, 1, 1, 3).getValues();
let x = false;
for(let i=0; i<3; i++) // Used 3 because I am just saving 3 values from code line 4
{
console.log(lRValues[0][i]);
if (lRValues[0][i]=="")
{
x = true;
}
}
if(x == true)
{
SpreadsheetApp.getUi().alert("Make sure there are no blank fields");
}
else
{
/*
Insert the form submission function or script here
*/
}
}
Example:
References:
alert(prompt)
Use a checkbox at the end of your form and have them click it. This checkbox does nothing, but it changes focus from the last field to the checkbox.
As suggested in a previous answer by Troy123, use a checkbox. IMHO this is the simplest option and by adding a very simple statement you could make your script to "reset" the checkbox, so it could "emulate" the button states, checked means pressed, unchecked means unpressed.
If order to make this able to work with scripts that requires more than 30 seconds to run, use an on edit installable trigger to call the a function responsible to responde to check/uncheck events.
function respondToCheckUncheck(e){
// Assing to a1Notation the reference of the cell containing the checkbox
const a1Notation = 'H10';
if(e.range.getA1Notation() === a1Notation && e.range.isChecked()){
// call here your function
myFunction();
// once the funcion finish, uncheck the checkbox
e.range.uncheck();
} else {
// do nothing
}
}
If you would like to take your script to a more sophisticated solution, your script could protect the cell having the checkbox and use the Lock Service to prevent other risks.
Using drawings to trigger Google Apps Script functions have several caveats like the one that was mentioned in this question
having a data entered in a cell and clicking the drawing when the cell is still in edit mode, will make that the value read from the cell doesn't match the value wrote.
While the workaround to check that the cell is not empty (see a previously posted answer by Fernando Lara) might help this still could lead to errors, i.e., if the user entered a value, pressed enter, but before clicking the button, edits the cell...
Considering the above, I suggest using other kind of element of the Google Sheets user interface, i.e. the Recorded Macros menu, a custom menu, a checkbox or cell with other data validation using a drowdown, a sidebar (requires the use of the HtmlService).
Other options to have in mind are to use a dialog for data entering created using the HtmlService, a Google Form or an AppSheet app.
Related
I've posted this question 2 days ago but with no answers. Here's a link to a copy of the file I'm working on:
https://docs.google.com/spreadsheets/d/1TCQ0cWulb8Wm63Hs57ruwEXgpP1swKAi/edit?usp=sharing&ouid=110569351169109673921&rtpof=true&sd=true
Basically, what I've done is: the "effettivo" page is a copy of the "pianificazione" page, with all the cells in "effettivo" that copy its value from its relative. The trouble is: for the checkboxes on the right, the formula I've set (=pianificazione!G3, for example) copies the value but it renders the checkbox itself uneditable manually (= I can't click on the checkbox to change the value of that checkbox). I need to find a way to copy all those checkbox values from "pianificazione" to "effettivo" while mantaining the checkboxes themselves editable. Thanks again guys :)
First of all the document you provided is not Google sheet, but Excel sheets. To make checkboxes (or in my example whole data) two-ways editable from both sheets and show the same values in both sheets everytime. I suggest you save this document as Google sheet and use GAS onEdit() function. With this function you also able to mirror other changes in values, not only checkboxes. I built fast example based on your document here
or you can just take over the function to your document
function onEdit(e) {
var sheet = e.range.getSheet();
var value = e.value;
if (sheet.getName() == 'effettivo') {
e.source.getSheetByName('pianificazione').getRange(e.range.rowStart, e.range.columnStart).setValue(value);
}
if (sheet.getName() == 'pianificazione') {
e.source.getSheetByName('effettivo').getRange(e.range.rowStart, e.range.columnStart).setValue(value);
}
}
Important! delete all formulas, that passes values between sheets, since that will be done by function, you don't need them anyway. Or just delete old 'effettivo' sheet and duplicate the 'pianificazione' and rename it to 'effettivo'. Also very important to authorize script first, best way to do it in Script editor trigger onEdit function manually and authorize it.
I've noticed that a google sheet script doesn't execute properly if an inexperienced user leaves an input cell highlighted after inputting a new value.
That could be manually solved by clicking the ENTER key on the keyboard, or some other key, then running the script; so I thought a way around was to mimic a keyboard input, but I'm unsure if there's any better solution.
As an example, I'd like the script to execute the "ENTER" key, before and after it executes the test multiplying function, as in the following test sheet:
https://docs.google.com/spreadsheets/d/1TMjakai_5b_UHhXHSu3TWJeI7saAeQd64H6WYWDNHfE/edit?usp=sharing
The script I'm using for a test is the following:
function Test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Data");
var y = formS.getRange("A3").getValue();
var z = formS.getRange("B3").getValue();
var x = y * z;
formS.getRange("E3").setValue(x);
}
Anyone can try it on google sheet: just click (once or twice) on either cell A3 or B3, leaving them highlighted, and click the button to execute the script.
Without clicking outside the cell or using ENTER by keyboard, the script won't record the newly inputted value.
Is there a better way to do it?
Although I can't reproduce your issue (see gif attached).
There might be two potential issues.
Either you need to flush the changes:
function Test() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var formS = ss.getSheetByName("Data");
var y = formS.getRange("A3").getValue();
var z = formS.getRange("B3").getValue();
var x = y * z;
SpreadsheetApp.flush();
formS.getRange("E3").setValue(x);
}
or you misunderstood the output of the script.
Namely, after you click on the button once, 5*44 gives 220. Therefore, if you press it again the result (220) simply won't change because the result of 5*44 will always be the same.
Illustration based on your code:
A cell value won't get updated until you press enter or click another cell (see Edit & format a spreadsheet):
Edit data in a cell:
Open a spreadsheet in Google Sheets.
Click a cell that’s empty, or double-click a cell that isn’t empty.
Start typing.
Optional: To add another line within a cell, press ⌘ + Enter on a Mac or Ctrl + Enter on Windows.
When you’re done, press Enter.
An attached button cannot be used to force this cell update, so a script called via clickable image/drawing won't have this information.
Therefore, I'd suggest not firing your function via an attached button, but using one of the following:
Call this via an onEdit trigger (it won't get called until the user presses enter or clicks another cell, updating the cell).
Call this via a custom menu (the cell will be updated when the menu item is clicked).
This way, you would make sure that the executed function works with the updated value.
Related:
How to force flush a user's input?
I am attempting to make many buttons on a Google Sheets spreadsheet that will record my cryptocurrency trades in a format that is specific to my trade strategy. The details of that strategy are not important for this issue. I only want to run a relative script whenever the (Trade!) button is clicked. I want to copy a lot of them, so it wouldn't make sense to make an individual macro for each buy/sell range. Two possible directions for a solution are clear to me, but I can't find information on either.
Possible solution 1: Assign a macro to a cell when it is selected and put the button inside the cell. I can do this with VBA, but cannot find instructions on how to do this for Google Sheets Script.
Possible solution 2: Have the function select the relative cell beneath the button that was clicked. Targeting cells relative to other cells is easy enough, but I can't seem to find a command for targeting a cell relative to an image. Again, this is doable in Excel with VBA, but I can't find the same function for Google Sheets Script.
Any help is appreciated.
You can use checkboxes and this onEdit() code to call whatever function you wish.
function onEdit(e) {
//e.source.toast('Entry');
//Logger.log(JSON.stringify(e));
var sh=e.range.getSheet();
if(sh.getName()=='Trades' && e.range.columnStart==7 && e.range.rowStart>2 && e.value=="TRUE") {
e.range.setValue('FALSE');
e.source.toast('You clicked cell ' + e.range.getA1Notation());
//call whatever function you wish to call
}
}
Animation:
How to Get the currently selected cell/range? was asked 3.5 years ago, but I'm hoping maybe some progress was made since then.
I'd like to make an interactive spreadsheet where there's a boolean grid that will display more information about the status of the currently selected cell in a static location, allowing users to quickly navigate using the arrow keys.
Referencing the previous instance of this question, I tried using the custom function below to get the cell address, although this isn't very dynamic.
function currentCell() {
return SpreadsheetApp.getActive().getActiveRange().getA1Notation();
}
When testing, this function returns the address of the cell the function is called from. I've tried pressing F5 while highlighting another cell and nothing happened. I've also dragged the formula across a selection and each cell only contains its own address (according to the documentation, it should contain the range).
I've also read Henrique's post on caching from 2012, and while I don't completely understand it, I get that we could not get scripts which update without edits being made or manual formula updates.
I would ideally like for the current cell to be tracked without any extra prompts from the user besides arrow key navigation or clicking to select a cell, but if pressing a non-altering key (like Enter) would allow for tracking, that would be fine. I also only need the selected cell, rather than a range, if that makes things easier.
Explicit Question: Is it possible to track the position of the currently selected cell in Google Sheets and store that position in a separate cell? If not, is there a way to do this without altering cell values?
EDIT: Adding an example for clarity. In this conceptual example, A2 =currentCell() as described above. If I were to hit the right arrow key, A2 would update to display I4, since it is now the current selection.
EDIT2: Jason Allshorn's response to Google app script monitor spreadsheet selected ranges appears to give a way of displaying the current selection (range) on the HTML input text. I'd like to do this, but store the value in a static cell on the sheet rather than input text. I'm new to scripting in Sheets and really only know what I've found for resolving this issue, so if I'm overlooking something, please let me know. I did look at Jason's example sheet and it wasn't clear to me what was actually happening there.
You will have to apply the technique suggested on How do I make a Sidebar display values from cells?. This consist on using using client-side code to constantly pulling values from the spreadsheet and then do the corresponding task.
One approach is to use a side-panel with an input field to set the cells to be tracked and another input field to set the destination cell.
You will have to use the onSelectionChange event in the app script to capture any selection change and then get the range name and put it in desired cell.
Something like the below:
function onSelectionChange(e) {
const range = e.range;
//Return in case of multi cell selection
if(range.getNumRows() !== 1 || range.getNumColumns() !== 1) return;
SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getRange("A2").setValue(range.getA1Notation());
}
You can see the official documentation here
I am using a Goofle form that receives applications from users, once the form is submitted I am using Google form submission trigger to notify. It has some questions like (facebook profile link)
But while sending a notification I don't want those links to be appeared just the same way user enters, instead something like Facebook, twitter (text as hyperlinked.) should appear
I already know about onFormsubmit() function, but not sure how to use, help me out please.
For example:
Cell A2 has user submitted facebook profile link using the form.
I want Column B2 to automatically generated as =hyperlink(A2, "Facebook")
The same thing should happen like A3 to B3 whenever user submits a form.
Ok after a bit of digging and testing, I believe I got a solution for you since you use the "Yet Another Mail Merge" (aka YAMM) add-on. Here it goes:
Firstly make sure your Form is setup properly and linked to a Google Sheet. After all questions have been created, add another column to your sheet, and call it 'Hyperlink' or whatever you please (just remember it for later). We will make use of the form submit trigger in the script editor along with some code.
Here's the code:
function onFormSubmit(e)
{
var r = e.range;
var v = e.namedValues;
var link = v['Link'];
// For testing purposes, this part was apart of my form,
// I'd assume you'd want to change it to something more
// usable in your case. Notice that I refer to the values
// by the name of the question they preside in.
var friendlyName = v['Friendly Name'];
var rngHyper = getCellRngByCol(r, 'Hyperlink');
// See below for the meaning of the boolean
addHyperlink(rngHyper, link, friendlyName, true);
}
// Will only return one cell no matter the range size.
// Perfect for onFormSubmit(e) use case.
function getCellRngByCol(rng, col)
{
var aRng = SpreadsheetApp.getActiveSheet().getDataRange();
var hRng = aRng.offset(0, 0, 1, aRng.getNumColumns()).getValues();
var colIndex = hRng[0].indexOf(col);
return SpreadsheetApp.getActiveSheet().getRange(rng.getRow(), colIndex + 1);
}
// Add some form of hyperlink reference to one particular
// cell, passed as a range object
function addHyperlink(rng, link, name, useFormula)
{
if (useFormula)
{
// If useFormula is TRUE, use Google Sheet HYPERLINK formula,
// only if you are sure all URL's are formated properly,
// and include HTTPS/HTTP/WWW. Also looks more pleasing in Google Sheet.
var formula = '=HYPERLINK("<<URL>>", "<<NAME>>")';
formula = formula.replace('<<URL>>', link).replace('<<NAME>>', name);
rng.setFormula(formula);
}
else
{
// Else use HTML <a> tag with hyperlink referencing, which should transform
// any URL passed as a clickable hyperlink within email. Not very visually
// appealing in Google Sheet.
var value = '<<NAME>>';
value = value.replace('<<URL>>', link).replace('<<NAME>>', name);
rng.setValue(value);
}
}
Then set the trigger, which will probably ask for authorization after saving:
Next, save the script and then put in a test submission through your form to see that the link is created properly, or as desired. Afterwards clear the rows of the spreadsheet (not the header) and remove all responses of the Form itself (not necessary, but keeps things organized for testing purposes).
Now, install the YAMM add-on. It should then add a new column at the end of your sheet called 'Merge satus'. Before setting up the email notification on submit, we need to create your email template. Open up GMAIL, create an email with the desired fields and layout and save it as a draft. Here's what I did as an example:
I'm sure you're familiar with how this add-on, works so I shouldn't need to explain too much here.
After the draft has been created and saved, go back to the Google Sheet attached to the Form. Go to Add-ons > YAMM > Configure form submission notifications. I chose the 'Notify one or more addresses of all responses' option which are tied to the 'To:' emails preset in the draft. Select your draft from the drop down, fill in sender name if needed, AND (very important!!) check the 'Wait until a specific column is filled before sending the email' check box. Make sure to select the Hyperlink column (or whatever you chose to name it earlier). Here's my setup for reference:
Save it, test it, and ta-da. This simple formatting for hyperlinks has been resolved! :D