0
votes

I have the problem in html page.

User enters data in html inputs and clicks enter. After this it must start checking by the function "keyPressFunction" throw withSuccessHandler(onSuccess) to the Google-apps script function "searchData" in 3 tables on spreadsheet and result must return to var "findData" with true/false. If it true, then focus goes to next input. After third input the data writes to table.

But answer from apps-script returns slowly, near 5 seconds, but the focus is already goes out, when the data is really uncorrect. Can you help me this timer between requests?

For understanding the test project is here https://docs.google.com/spreadsheets/d/1FqUmJcTipwKX9Q5m-4dlmXIChp5k1Z98xR2m42GpIT0/edit#gid=0

and last deployed link of web app is here https://script.google.com/a/fmlogistic.com/macros/s/AKfycbwAcfIVGrbcu24t_6OxtR2gvltG3ojbh1_pNxLed1O8/dev

<script>

  const inputs = document.querySelector('.dws-input');
  const formControl = document.querySelectorAll('.form-control');

  let findData;
  let curInpID;
  let firstValid, secValid, thirdValid, allValid;

  formControl[0].focus();

  function keyPressFunction(ev) {

    let userInfo = {};
    userInfo.login = document.getElementById("tLogin").value;
    userInfo.table = document.getElementById("tTable").value;
    userInfo.order = document.getElementById("tOrder").value;

    let inputData = ev.target.value
    let btnReset = document.getElementById("del");

    if (ev.code !== 'Enter') return;
    if (ev.target.classList.contains("is-valid")) ev.target.classList.remove("is-valid");
    if (ev.target.classList.contains("is-invalid")) ev.target.classList.remove("is-invalid");

    curInpID = ev.target.id;
   
google.script.run.withSuccessHandler(onSuccess).searchData(inputData, curInpID);
//the true/false returns here in findData: 

    console.log(findData);

    if (!findData) {   
      ev.target.classList.add("is-invalid");
      ev.target.focus();
      return;
    } else {
      ev.target.classList.add("is-valid");
    };

    btnReset.disabled = (!firstValid == true);

    allValid = (firstValid == true && secValid == true && thirdValid == true) ? true : false;

    for (const i of formControl) {
      if (i.value === '') {
        i.nextElementSibling.focus();
        break;
      }
    }
    
    if (allValid){
      google.script.run.userClicked(userInfo);
      document.getElementById("tTable").value = '';
      document.getElementById("tOrder").value = '';
      secValid = false;
      thirdValid = false;
      document.getElementById("tTable").focus();
    }
  }

  function onSuccess(_findData) {
    findData = _findData;
    if (!firstValid) firstValid = (findData && curInpID == "tLogin") ? true : false;
    if (!secValid) secValid = (findData && firstValid && curInpID == "tTable") ? true : false;
    if (!thirdValid) thirdValid = (findData && firstValid && secValid && curInpID == "tOrder") ? true : false;
    allValid = (firstValid && secValid && thirdValid) ? true : false;
  }
  
  inputs.addEventListener('keydown', keyPressFunction);

</script>
<!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 href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
       integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
    <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
    <link rel="stylesheet" href="/resources/demos/style.css">
    <script src="https://code.jquery.com/jquery-1.12.4.js"></script>
    <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>      
</head>
<body>
    <div class="conteiner">
        <form novalidate>
            <h6 class="title">PACKING</h6>
            <div class="dws-input">
                <div class="col-md-3"></div>
                <div>
                    <div class="form-floating mb-3 mt-3">
                        <input type="text" class="form-control" novalidate id="tLogin" name= "username" placeholder= "Login:" autofocus > 
                        <label for="tLogin">Login:</label>
                    </div>
                    <div class="form-floating mb-3 mt-3">
                        <input type="text" class="form-control"  novalidate id="tTable" name= "text" placeholder= "Table:" >
                        <label for="tTable">Table:</label>
                    </div>
                </div>
                <div class="form-floating mb-3 mt-3">
                    <input type="text"  novalidate class="form-control" id="tOrder" name= "text" placeholder= "Order:" >
                    <label for="tOrder">Order:</label>
                </div> 
            </div>  
        </form>
    </div>
    
    <?!= include("index-js"); ?>

</body>



</html>

at Apps script I have next script:

const url = SpreadsheetApp.getActiveSpreadsheet().getUrl();
  let ss = SpreadsheetApp.openByUrl(url);
  let sheetTo = ss.getSheetByName("@sistem");
  let sheetIn = ss.getSheetByName("@packing");
  
function doGet(e){

    var htmlServ = HtmlService.createTemplateFromFile("index");
    return htmlServ.evaluate();

}

function userClicked(userInfo){

  sheetIn.appendRow([userInfo.login, userInfo.table, userInfo.order, new Date()]);
  Logger.login(userInfo.name + "clicked the button");
}

function include(filename){
  return HtmlService.createHtmlOutputFromFile(filename).getContent();
}

function searchData(inputData, curInpID){

  var result;
  
  var lrLogins = sheetTo.getRange("A:A").getValues().filter(String).length;
  var arrLogins = sheetTo.getRange(1, 1, lrLogins, 1).getValues().flat();
  
  var lrTMPLORDS = sheetTo.getRange("K:K").getValues().filter(String).length;
  var curTMPLORDS = sheetTo.getRange(1, 11, lrTMPLORDS, 1).getValues();
  
  var lrTABLES = sheetTo.getRange("R:R").getValues().filter(String).length;
  var curTABLES = sheetTo.getRange(1, 18, lrTABLES, 1).getValues().flat();

  if (curInpID == "tLogin"){
    result = (arrLogins.indexOf(inputData) !== -1) ? true : false;
  }
  else if (curInpID == "tTable"){
    result = (curTABLES.indexOf(inputData) !== -1) ? true : false;
  }  
  else if (curInpID == "tOrder"){
    for (i = 0 ; i < curTMPLORDS.length; i ++){
      var regexstring = curTMPLORDS[i];
      var regexp = new RegExp(regexstring, "i");
      var result = regexp.test(inputData);
      if (result) break;
    }
  }
    return result;
  }
1
If I understand you correctly, you look for a way to prevent the user from clicking anything until keyPress Function is return? - Elchanan shuky Shukrun
@ Elchanan shuky Shukrun may be, but I don't know, is it really help me? - Dmitriy Rudakov
@Cooper thank you, can you show me examples? I'm newbe at this...(( - Dmitriy Rudakov
@ Cooper I need set timeout for disabling inputs while returning answer from server. I had the recommendation from here stackoverflow.com/questions/68846957/… to create new topic with question about timer or something like this. - Dmitriy Rudakov
@Cooper sorry, but pushing me from one way to way on this site is incredible issue for me. I have brainstorm about this... - Dmitriy Rudakov

1 Answers

0
votes

Issue:

If I understand you correctly, you want to avoid the keydown events to execute keyPressFunction while the server-side function searchData hasn't still returned the data.

Solution:

If that's the case, I'd suggest you to use removeEventListener at the start of the keyPressFunction (in order to avoid successive keydown event to trigger more executions of this function), and add it again via addEventListener when executing you success handler function (onSuccess).

It could be something along the following lines:

function keyPressFunction(ev) {
  inputs.removeEventListener('keydown', keyPressFunction);
  // ... REST OF YOUR FUNCTION
}

function onSuccess(_findData) {
  // ... REST OF YOUR FUNCTION
  inputs.addEventListener('keydown', keyPressFunction);
}

Update:

keyPressFunction finishes execution without calling the server-function searchData if the pressed key is not Enter. Since the event will only be reactivated after searchData returns and onSuccess runs, it will not be reactivated if the pressed key is not Enter. Because of this, keyPressFunction will only run once (if the pressed key is not Enter).

In order to avoid this, move the removeEventListener line to just before calling searchData:

function keyPressFunction(ev) {
  // ... REST OF YOUR FUNCTION
  inputs.removeEventListener('keydown', keyPressFunction);
  google.script.run.withSuccessHandler(onSuccess).searchData(inputData, curInpID);
}

Sidenote: Please note that everything that is written in keyPressFunction after calling searchData will never be executed, since the execution will be moved to the failure or success handlers (onSuccess in your case). So move that on top of the mentioned line (starting with google.script.run) if you want it to run.

Reference: