I'm working to send form data from a dynamic user form to a google sheets page. There is a corpus of 140 potential forms, users are shown 20 at random. I'm not getting any errors in the console but the google sheet is not populating. I know that the sheets gs script is OK because the connection worked alright under simpler use cases.

I've included the html and js code that I have below. The website is being rendered fine on my local machine. The images and form substance is working as well.

<!DOCTYPE html>

<body>
<!-- Required JS packages for this project-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
</script>
<script src="jquery-3.3.1.min.js"></script>
<script src="require.js"></script>
    
<!--Create empty form element  -->
<div id = "form_submit"></div>

<!-- JS function to fill form element with 20 hold type questions forms -->
<script>
        // Establish file name to hold mapping with two lists and a dict to link elements
        var files = ['1.png', '10.png', ..., '98.png', '99.png']
        var numWords = ["one", "two", "three",.., "one_hundred_and_fifty"]
        var numWordDict = { 1: 'one', ..., 150: 'one_hundred_and_fifty' }        // Generate list of 20 random digits that will select holds to be classified
       
        // Create array of twenty random holds
        var idx = []
        for (var j = 0; j < 20; j++) {
            idx.push(Math.floor(Math.random() * 140) + 0)
        }
        console.log(idx)

        // Loop over array and make a form element for each hold within the div element
        $(document).ready(function (list) {
            for (var i = 0; i < idx.length; i++) {
                // retrieve mapped index 
                var randHoldIdx = idx[i]
                // build path to hold image
                var holdPath = files[randHoldIdx]
                var numb = holdPath.match(/\d/g);
                numb = numb.join("");
                var colName = numWordDict[numb]
                var form_name = 'submit-to-google-sheet' + numb
                const scriptURL = 'https://script.google.com/macros/s/AKfycbyhMLuTGNkaNOxeNCOx_t1ERThZT8VEYDcMmiQhj773kIrUuRA/exec'

                // Form element contents will be appended into the div element with id = form_submit
                $("#form_submit").append(
                    //  html form skeleton for users to select jug,pinch, crimp, pocket or undercling from radio button
                    //  options
                    "<form name = " + form_name + ">"+
                    "<input type='radio' name = " +colName + " class=" + String(colName) +" value=1>Jug<br>" +
                    "<input type='radio' name = " + colName + " class=" + String(colName) +" value=2>Pinch<br>" +
                    "<input type='radio'name = " +colName + " class=" + String(colName) +" value=3>Crimp<br>"+
                    "<input type='radio' name = " +colName + " class=" + String(colName) +" value=4>Pocket<br>"+
                    "<input type='radio' name = " +colName + " class=" + String(colName) +" value=5>Undercling"+
                    // Submit button for form, close form
                    "<button type='submit'>Submit!</button></form>"+
                    // image of climbing hold in question with coordinates to position on moonboard
                    "<div><img src=labelled_imgs/" +String(holdPath) +" alt='selected hold'></div>");

                    var form = document.forms[form_name]
    
                    window.onload=function(){
                        form.addEventListener('submit', e => {
                        e.preventDefault()
                        fetch(scriptURL, { method: 'POST', body: new FormData(form) })
                            .then(response => console.log('Success!', response))
                            .catch(error => console.error('Error!', error.message))
        })
    }
                }
            });



    </script>


</body>
I suspect that there is something wrong with the event listener. It may be something simple, but I would welcome any suggestions for alternate solutions to this problem! This is a little different than just sending user input from a form to a google sheet as the form contents are changed each time the page is rendered. For context, this is a portion of a custom crowd-sourcing platform. Thanks for any help!

2 Answers

0
Community On

I was able to solve the problem by changing the architecture of the page. Instead of using many different forms for each classification task, I used one form that was submitted as a whole.

I have posted the new code below. Feel free to reach out for clarification!

<!DOCTYPE html>

<body>
  <!-- Required JS packages for this project-->
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js">
  </script>
  <script src="jquery-3.3.1.min.js"></script>
  <script src="require.js"></script>

  <!--Create empty form element  -->
  <div id="form_submit1">
    <form id="form_submit" , name="submit_to_sheets">

    </form>
  </div>

  <!-- JS function to fill form element with 20 hold type questions forms -->
  <script>
    // Establish file name to hold mapping with two lists and a dict to link elements
    var files = ['1.png', '10.png',...,'99.png']
    var numWords = ["one", "two",...,"one_hundred_and_fifty"]
    var numWordDict = {
      1: 'one',
      2: 'two',
      ...
      150: 'one_hundred_and_fifty'
    } // Generate list of 20 random digits that will select holds to be classified

    // Create array of twenty random holds
    var idx = []
    for (var j = 0; j < 20; j++) {
      idx.push(Math.floor(Math.random() * 140) + 0)
    }
    console.log(idx)


    // Loop over array and make a form element for each hold within the div element
    $(document).ready(function(list) {
      for (var i = 0; i < idx.length; i++) {
        // retrieve mapped index 
        var randHoldIdx = idx[i]
        // build path to hold image
        var holdPath = files[randHoldIdx]
        var numb = holdPath.match(/\d/g);
        numb = numb.join("");
        var colName = numWordDict[numb]


        // Form element contents will be appended into the div element with id = form_submit
        $("#form_submit").append(
          //  html form skeleton for users to select jug,pinch, crimp, pocket or undercling from radio button
          //  options
          "<input type='radio' name = " + colName + " class=" + String(colName) + " value=1>Jug<br>" +
          "<input type='radio' name = " + colName + " class=" + String(colName) + " value=2>Pinch<br>" +
          "<input type='radio'name = " + colName + " class=" + String(colName) + " value=3>Crimp<br>" +
          "<input type='radio' name = " + colName + " class=" + String(colName) + " value=4>Pocket<br>" +
          "<input type='radio' name = " + colName + " class=" + String(colName) + " value=5>Undercling" +

          // image of climbing hold in question with coordinates to position on moonboard
          "<div><img src=labelled_imgs/" + String(holdPath) + " alt='selected hold'></div>");
      }

      // prepend form begining to html outside of for loop
      // append end of form to html outside of for loop


    });
    $("#form_submit").append("<button type='submit'>Submit!</button>");
  </script>

  <script>
    const form = document.forms["submit_to_sheets"]
    const scriptURL = 'https://script.google.com/macros/s/AKfycbyhMLuTGNkaNOxeNCOx_t1ERThZT8VEYDcMmiQhj773kIrUuRA/exec'
    console.log(form)
    console.log("loop")
    form.addEventListener('submit', e => {
      e.preventDefault()
      fetch(scriptURL, {
          method: 'POST',
          body: new FormData(form)
        })
        .then(response => console.log('Success!', response))
        .catch(error => console.error('Error!', error.message))
    })
  </script>


</body>

</html>

1
TheMaster On

Issues:

  • You're rewriting the window.onload function each time in the loop for each form. Only the last form's submit event will be disabled onload and be submitted to server.

  • When you're creating a random array of numbers, there is no guarantee that it will be unique. If two forms end up with the same name, only the first form's submit event will be prevented.

Solution:

  • Since the form is already appended, directly run the function for each form inside the loop without writing window.onload

    var form = document.forms[form_name]
    form.addEventListener('submit', e => {
         e.preventDefault();
         fetch(scriptURL, { method: 'POST'.....
    
  • Make Idx unique:

    idx = [...new Set(idx)]