-2

I'm very new to Google Sheets, although I have some previous experience in Excel and Access with VBA. My issue is that I have a google sheets spreadsheet, with 2 sheets, Data that contains all the information, and Form which displays searched data and allows the input of new data. On the form there are 5 entry boxes, Fleet Number (dropdown), Date, Invoice No, Job No and Operation. The user selects a Fleet Number from the drop down list, enters date, Invoice Number, Job Number and Operation. To save the details the user then selects an Add Data button which runs the script to write the details to the Data sheet. The problem is that if the user does not tab out of the last field, ie the Operations field, then the text in the field is not written back to the Data sheet and remains on the form. The script is very simple, but it appears that the text is not saved into the cell until the user tabs out to another cell. Using Debug, the Array shows blank for the 5th entry. My thought was to provide a save for all 5 cells when the Add Data button is selected before writing to the Data sheet, but I cannot find a way of forcing a save of the data in the final cell, and I am going round in circles. Im sure theres a straight forward solution, and it is my ignorance, but I cannot see it, so I would greatly appreciate any help offered.

The script in use is

function Adddataform() {
  var ActiveSheet = SpreadsheetApp.getActiveSpreadsheet();
  var FormSheet  = ActiveSheet.getSheetByName("Form"); //Form Sheet
  var DataSheet = ActiveSheet.getSheetByName("Data"); //Data Sheet
    saveData()
  //Input Values
  var values = [[FormSheet.getRange("B4").getValue(),
                 FormSheet.getRange("B5").getValue(),
                 FormSheet.getRange("B6").getValue(),
                 FormSheet.getRange("B7").getValue(),
                 FormSheet.getRange("B8").getValue())]]; 
 
  DataSheet.getRange(DataSheet.getLastRow()+1, 1, 1, 5).setValues(values);
SpreadsheetApp.getUi().alert("Data add successfull")
ResetForm ()
}
// function resetByRangeList_(FormSheet,Formcells){
// FormSheet.getRangeList(Formcells).clearContent() 
// }
//............................
//Clear Form
function ResetForm() {
var ActiveSheet = SpreadsheetApp.getActiveSpreadsheet();
var FormSheet  = ActiveSheet.getSheetByName("Form"); //Form Sheet
var Formcells = ["B4","B5","B6","B7","B8"];
resetByRangeList_(FormSheet,Formcells);
}
function resetByRangeList_(FormSheet,Formcells){
FormSheet.getRangeList(Formcells).clearContent() 
}   
BigBen
  • 46,229
  • 7
  • 24
  • 40
GarryF
  • 3
  • 1
  • try putting SpreadsheetApp.flush() at the end of saveData(); – Cooper Mar 15 '21 at 20:20
  • you use use `let values=FormSheet.getRange(4,2,5,1).getValues().flat()` and then `DataSheet.getRange(DataSheet.getLastRow()+1, 1,1,5).setValues(values);` – Cooper Mar 15 '21 at 20:24

1 Answers1

0

It is not possible for apps script to read the value of a cell that is still currently being edited. You might want to consider the following workarounds.

(Option 1)

Replace your Add Data button with a checkbox and use onEdit(e) simple trigger to call your function. When a checkbox is being checked/unchecked, it makes its cell active. Hence your 5th data entry can be read successfully.

Sample Code:

function onEdit(e){
  var ss = e.source;
  var cell = e.range

  if(ss.getActiveSheet().getName() == "Form" && cell.getA1Notation() == "B9" && cell.isChecked() == true){
    //Add data to form
    Adddataform();
  }
}
function Adddataform() {
  var ActiveSheet = SpreadsheetApp.getActiveSpreadsheet();
  var FormSheet  = ActiveSheet.getSheetByName("Form"); //Form Sheet
  var DataSheet = ActiveSheet.getSheetByName("Data"); //Data Sheet
  //Input Values
  var values = [[FormSheet.getRange("B4").getValue(),
                 FormSheet.getRange("B5").getValue(),
                 FormSheet.getRange("B6").getValue(),
                 FormSheet.getRange("B7").getValue(),
                 FormSheet.getRange("B8").getValue()]]; 
 
  DataSheet.getRange(DataSheet.getLastRow()+1, 1, 1, 5).setValues(values);
  SpreadsheetApp.getUi().alert("Data add successfull")
  ResetForm ()
}
// function resetByRangeList_(FormSheet,Formcells){
// FormSheet.getRangeList(Formcells).clearContent() 
// }
//............................
//Clear Form
function ResetForm() {
  var ActiveSheet = SpreadsheetApp.getActiveSpreadsheet();
  var FormSheet  = ActiveSheet.getSheetByName("Form"); //Form Sheet
  var Formcells = ["B4","B5","B6","B7","B8","B9"];
  resetByRangeList_(FormSheet,Formcells);
}
function resetByRangeList_(FormSheet,Formcells){
  FormSheet.getRangeList(Formcells).clearContent(); 
} 

What it does?

  1. Whenever a cell is being modified in your spreadsheet, onEdit() will be called. Check if the modified cell is Form!B9 and if the checkbox was checked.
  2. If the checkbox was checked, Add the data to the Data sheet by calling Adddataform()

Note:

  • Removed the undefined saveData() inside Adddataform()
  • Include Cell B9 in the resetByRangeList to reset the checkbox

Output:

enter image description here


(Option 2)

You can use Custom sidebars or Custom dialogs as your form.

Sample Code:

(Code.gs)

//CREATE CUSTOM MENU
function onOpen() { 
  var ui = SpreadsheetApp.getUi();
  ui.createMenu("My Menu")
    .addItem("Sidebar Form","showFormInSidebar")
    .addItem("Modal Dialog Form","showFormInModalDialog")
    .addToUi();
}
 
//OPEN THE FORM IN SIDEBAR 
function showFormInSidebar() {      
  var form = HtmlService.createTemplateFromFile('form').evaluate().setTitle('Form');
  SpreadsheetApp.getUi().showSidebar(form);
}
 
 
//OPEN THE FORM IN MODAL DIALOG
function showFormInModalDialog() {
  var form = HtmlService.createTemplateFromFile('form').evaluate();
  SpreadsheetApp.getUi().showModalDialog(form, "Form");
}

 
//PROCESS FORM
function processForm(formObject){ 
  Logger.log(formObject);
  var ActiveSheet = SpreadsheetApp.getActiveSpreadsheet();
  var DataSheet = ActiveSheet.getSheetByName("Data");
  Logger.log(formObject.invoiceNumber);
  Logger.log(typeof formObject.invoiceNumber);
  var values = [[formObject.fleetNumber,
                formObject.date,
                formObject.invoiceNumber,
                formObject.jobNumber,
                formObject.operation
                ]];
  
  DataSheet.getRange(DataSheet.getLastRow()+1, 1, 1, 5).setValues(values);
  SpreadsheetApp.getUi().alert("Data add successfull");
}

(form.html)

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">

    <title>Sample Form</title>
  </head>
  <body>
    <!-- Option 1: jQuery and Bootstrap Bundle (includes Popper) -->
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ/JpcUGGOn+Y7RsweNrtN/tE3MoK7ZeZDyx" crossorigin="anonymous"></script>

    <form id="myForm" onsubmit="handleFormSubmit(this)">
      <div class="form-group">
        <label for="fleetNumber">Fleet Number</label>
        <select class="form-control form-control-sm" id="fleetNumber" name="fleetNumber" required>
          <option value="" selected>Choose...</option>
          <option value="Number1">Number 1</option>
          <option value="Number1">Number 2</option>
        </select>
      </div>
      <div class="form-group">
        <label for="date">Date</label>
        <input class="form-control form-control-sm" type="text" class="form-control" id="date" name="date" placeholder="mm/dd/yyyy">
      </div>
      <div class="form-group">
        <label for="invoiceNumber">Invoice Number</label>
        <input class="form-control form-control-sm" type="text" class="form-control" id="invoiceNumber" name="invoiceNumber">
      </div>
      <div class="form-group">
        <label for="jobNumber">Job Number</label>
        <input class="form-control form-control-sm" type="text" class="form-control" id="jobNumber" name="jobNumber">
      </div>
      <div class="form-group">
        <label for="operation">Operation</label>
        <input class="form-control form-control-sm" type="text" class="form-control" id="operation" name="operation">
      </div>
      <button type="submit" class="btn btn-primary">Submit</button>
    </form>

    <script>
    // Prevent forms from submitting.
    function preventFormSubmit() {
      var forms = document.querySelectorAll('form');
      for (var i = 0; i < forms.length; i++) {
        forms[i].addEventListener('submit', function(event) {
        event.preventDefault();
        });
      }
    }
    window.addEventListener('load', preventFormSubmit);    
        
        
    function handleFormSubmit(formObject) {
      google.script.run.processForm(formObject);
      document.getElementById("myForm").reset();
    }
  </script>
  </body>
</html>

What it does?

  1. Create a custom menu which will be displayed whenever you open your Google Sheets

enter image description here

  1. Create an html form, use google.script.run to allow HTML-service pages to call server-side Apps Script functions. In this example we will call processForm(formObject) using this google.script.run.processForm(formObject); syntax once the form was submitted.

  2. Add new row data based on the parameters provided during form submission.

Output:

enter image description here

enter image description here

Additional Reference:

Ron M
  • 5,791
  • 1
  • 4
  • 16
  • Hi, many thanks for the speedy response, and Option 1 looks exactly what I'm after, however when I copy the script for the onEdit function, and then try to run using Debug, I get "TypeError: Cannot read property 'source' of undefined onEdit @ Code.gs:2" – GarryF Mar 17 '21 at 12:26
  • I have tried pasting the complete script you supplied for Option 1, but still get the issue. I'm running on a MacOS Hi Sierra 10.13.6. If I rekey the line var ss = e.source;, I get a list of properties associated with e, but source is not amongst them . Are there any upgrades I should be looking at. Thanks again for your help on this. – GarryF Mar 17 '21 at 12:31
  • If I set up a test for the onEdit, ie as per details shown in https://stackoverflow.com/questions/16089041/how-can-i-test-a-trigger-function-in-gas/16089067#16089067 then I can step through the code without any issues, but the script does not trigger automatically when I edit the tick box. If I remove the test script, then I get the error mentioned above. Do I need a setting in sheets to activate the Triggers. Apologies for being a little dim on this, but it appears that the internal onEdit(e) trigger is not actually being triggered. – GarryF Mar 17 '21 at 14:36
  • The script is now working, but only if you check, uncheck and then check the tick box, so I have a solution, albeit a little clunky. It would be nice to know why a single click doesnt work, but I can live with it. Again a massive thanks for pointing me in the right direction, and pointing out my initial script was not possible. Your help was very much appreciated cheers – GarryF Mar 17 '21 at 14:49
  • Hi @GarryF, You cannot run an onEdit() in the apps script editor since the event object e will be undefined. To debug the onEdit() you just need to add Log prints in your code and try to modify/edit cells in your sheet then check the execution tab in the apps script. The function should be triggered every time you check/uncheck the checkbox with a single click. You can add your modified function so I could check on my side – Ron M Mar 17 '21 at 15:03
  • Hi Ron M, thanks for the update, and that makes sense ;-), OK so I have tried using both Logger.log and console.log, after the fuction call to save, ie after the user selects the check box, but again nothing is written to the logs until I hit the checkbox twice. I'm obviously being dumb here. The code I used is – GarryF Mar 18 '21 at 12:29
  • OK I understand your concern. I copied the exact code that you provided and it is working as expected from my side. What you are doing incorrect is you checked the checkbox first before populating the data to be copied. Your checkbox should act as your submit button. Hence you need to populate first the data before checking the checkbox – Ron M Mar 18 '21 at 14:41
  • Hi Ron M, thanks for taking time to look at this, but unfortunately that is not the reason, I have tried closing everything down, re-opening and I always enter data into all the fields before selecting the checkbox. Just to make sure, I have just run through the process again, with exactly the same results. I get the feeling that I may have some obscure setting active somewhere, but I cant find it. If I step through the script from the test onEdit function, then everything runs and the data is written away. – GarryF Mar 18 '21 at 16:20
  • If I go to the spreadsheet, fill out the cells from B3 to B7 then select the checkbox it just sits there. Also I have tried selecting each cell using the return key, arrow down key and the mouse, but no difference. It works for me using double click, so I'll run with that for now, and continue to investigate. Thanks again for all your help and suggestions, I now have a better understanding thanks to you. – GarryF Mar 18 '21 at 16:20
  • Is it possible to share your sheet so I could check it further? [Share a test sheet](https://webapps.stackexchange.com/a/138383) – Ron M Mar 18 '21 at 16:22
  • Hi RonM, Of course, that would be most helpful. Followed the instructions and here is the link https://docs.google.com/spreadsheets/d/1G7V2oP77WJZ0cXy97czMCm2GFz13H9Ox-3PoQ-F6zeo/edit?usp=sharing Good luck – GarryF Mar 19 '21 at 17:31
  • Hi @GarryF, I gave my best but I also encountered similar problem. I already tried it on a new sheet but the same behavior occurred. It's like when I edit B7 and directly check B8 (B8 is still in edit mode), based on the execution log the last edited cell is still on B7 even though i already checked B8. – Ron M Mar 19 '21 at 18:46
  • Hey RonM, no worries, thanks for the time spent trying to resolve it and your guidance to me. I can live with the double click for now, and in some ways I'm glad that it wasnt something too stupid that I had missed. Thanks again :-) – GarryF Mar 20 '21 at 12:50