0

I need to send data from html form to spreadsheet, but I got mistake after clicking button. I tried to copy the steps from this video https://www.youtube.com/watch?v=yiPnkBEHqf0&list=PLRmEk9smitaVGAAhgU0Pdc2sEs7yxDrEk

in js and html I wrote this:

const url = "https://script.google.com/macros/s/AKfycbzZe824lIxa-hNsO71xoFfq5qXbFaDKhHZeACrQgLMCjU_EjvY/exec";

var loginText = document.getElementById("tLogin");
var tableText = document.getElementById("tTable");
var orderText = document.getElementById("tOrder");
//var kommText = document.getElementById("tKomm");

function testGS(){
    var userInfo = {
            login: loginText.value,
            table: tableText.value,
            order: orderText.value,
            tdate: new Date().toLocaleDateString(),
            //komm: kommText.value,
    };

    fetch(url, {
        method: 'POST',
        //mode: 'no-cors', // no-cors, *cors, same-origin
        body: JSON.stringify(userInfo)
      })
      .then((res) => res.text())
      .then((res) => console.log(res));
      console.log(userInfo);
}           

document.getElementById("del").addEventListener("click", testGS);
<!doctype html>
<html lang="en">
<head>
<title>CLR: PACKING</title>
<meta charset = "UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <link rel="stylesheet" href="CSS/main_page_style.css">
    <link rel="icon" href="Image/favicon.png" type="png">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet"
       integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
</head>
<body>
    <div class="conteiner">
        <form novalidate>
                <h6 class="title">PACKING</h6>
                <img src="Image/mainImg.jpg" class="img-fluid" alt="...">
            <div class="dws-input">
                <div class="col-md-3"></div>
                <div>
                    <div>
                        <button id="del" type="button">&lt;======СБРОС</button>
                    </div>
                    <div class="form-floating mb-3 mt-3">
                        <input type="text" class="form-control" novalidate id="tLogin" name= "username" placeholder= "Логин:" autofocus > 
                        <label for="tLogin">Логин:</label>
                    </div>
                    <div class="form-floating mb-3 mt-3">
                        <input type="text" class="form-control" novalidate id="tTable" name= "text" placeholder= "Номер стола:" >
                        <label for="tTable">Номер стола:</label>
                    </div>
                </div>
                <div class="form-floating mb-3 mt-3">
                    <input type="text"  novalidate class="form-control" id="tOrder" name= "text" placeholder= "Заказ:" >
                    <label for="type3">Заказ:</label>
                </div> 
            </div>  
        </form>
    </div>
    <script src="JS/fetchNew.js"></script>

</body>



</html>

in apps script I wrote this:

function doGet() {

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getSheetByName("LOG_history");  
  const data = ws.getRange("A1").getDataRegion().getValues();
  const headers = data.shift();

  const jsonArray = data.map(r => {
    let obj = {};
     headers.forEach((h , i) => {
       obj[h] = r[i];
     });
    return obj;
  })
  const response = [{status: 200, data: jsonArray}];
  return sendJSON_(response);
}

function doPost(e){

  let jsonResponse;

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const ws = ss.getSheetByName("LOG_history");
  const headers = ws.getRange(1,1,1,ws.getLastColumn()).getValues()[0];
  const headersOriginalOrder = headers.slice();
  headersOriginalOrder.shift();
  //remove id columns header
  headers.shift();
  headers.sort();

  const body = e.postData.contents;
  const bodyJSON = JSON.parse(body);
  const headersPassed = Object.keys(bodyJSON).sort();

  if(!compareTwoArray_(headers, headersPassed)){
      jsonResponse = [{status:500, message:"Invalid Arguments Passed"}];
      return sendJSON_(jsonResponse);
  }

  const arrayOfData = headerOriginalOrder.map(h => bodyJSON[h]);
  
  const aoaIds = ws.getRange(2,1,ws.getLastRow()-1,1).getValues();
  const newIDNumber = getMaxFromArrayOfArray_(aoaIds) + 1;
  arrayOfData.unshift(newIDNumber);
  ws.appendRow(arrayOfData);
  
  return ContentService.createTextOutput("ok");
}

//return true if all ites are the same
function compareTwoArray_(arr1, arr2){
  if (arr1.length !== arr2.length) return false;
    for (let i = 0; i < arr1.length; i ++){
      if (arr1[i] !== arr2[i]) return false;
    }
  return true;
}

function sendJSON_(jsonResponse){
  return ContentService
      .createTextOutput(JSON.stringify(jsonResponse))
      .setMimeType(ContentService.MimeType.JSON);
}

//return the highest number / id
function getMaxFromArrayOfArray_(aoa){
  let maxID = 0;
  aoa.forEach(r => {
    if (r[0] > maxID) maxID = r[0];
  });
  return maxID;
}

I aloweed all the permissions I know but I have this mistakes on picture with core and fetch. Help!!! enter image description here

1 Answers1

0

(Important edit at end)

Make sure you are only sending plain text information

Modify your function sendJSON_ to

function sendJSON_(jsonResponse){
  return ContentService
      .createTextOutput(JSON.stringify(jsonResponse))
      // .setMimeType(ContentService.MimeType.JSON); // Remove this line
}

That or set it to .setMimeType(ContentService.MimeType.PLAIN_TEXT)

You can also try setting the header from the client-side JS to "Content-Type": "text/plain"

fetch(url, {
        method: 'POST',
        headers: {"Content-Type": "text/plain"},
        body: JSON.stringify(userInfo)
      })
      .then((res) => res.text())
      .then((res) => console.log(res));

This should then work without issues.

If you are still not getting success, and if you don't need a response from the web app, but just need to send info. You can activate no-cors. The request will get sent, but any response it gives will not be available to the client-side.

fetch(url, {
    method: 'POST',
    mode: 'no-cors',
    body: JSON.stringify(userInfo)
})
.then((res) => res.text())
.then((res) => console.log(res));

Minimal Example:

  1. Start a new project.

  2. Paste this code into Apps Script:

    function doPost(e) {
      return ContentService.createTextOutput("ok"); 
    }
    
  3. Navigate to Deploy > New Deployment

  4. Select type 'Web app'

  5. Execute as: "Me".

  6. Who has Access: "Anyone".

  7. "Deploy"

Take a note of the exec URL.

On a local machine, in a local server or in the browser console execute:

url = "[YOUR_DEPLOYMENT_URL]"

fetch(url, {
        method: 'POST',
        headers: {"Content-Type": "text/plain"},
        body: JSON.stringify({"test":1})
      })
.then(r => r.text())
.then(t => console.log(t))

When I followed these steps, I get on the console:

ok

Reference

Edit

Even after making these changes it seemed that the CORS error persisted on the project.

After some debugging I found that simply by changing the property name in userInfo from tdate to anything else, made it work.

I don't know why tdate as a property in a strigified JSON would cause issues, but it seems to be a reserved word of sorts.

That said, I have tried to reproduce this issue in a new project and can't seem to do so!

iansedano
  • 6,169
  • 2
  • 12
  • 24