Home > Mobile >  Javascript: How to populate text field with async value before submitting form?
Javascript: How to populate text field with async value before submitting form?

Time:03-15

I want to submit a transaction from the client to Ethereum blockchain, get back a transaction hash, and then submit this hash to my backend.

On the front-end I have a form like this:

<form id="formConfirm" method="POST" action="/step2" onSubmit="processStep1">
  <input id="textWalletAddress" name="walletAddress" type="text" readonly />
  <input id="textEncodedFunctionCall" th:value="${encodedFunctionCall}" readonly />
  <input type="text" id="textTxHash" readonly />
  <input type="submit" value="Submit" />
</form>

Inside the function, I want to submit the transaction, get back the corresponding hash, and populate a field with it so that I can push it to my backend.

async function processStep1(e) {
  // edit1: trying out preventDefault
  alert('Before preventDefault');
  e.preventDefault();
  alert('After preventDefault');

  let efc = document.getElementById('textEncodedFunctionCall').value;
  let walletAddress = document.getElementById('textWalletAddress').value;
  const txParams = {
    to: CONTRACT,
    from: walletAddress,
    'data': efc
  };
  
  if (window.ethereum) {
    try {
      const txHash = await window.ethereum.request({
        method: "eth_sendTransaction",
        params: [txParams]
      });
      document.getElementById('textTxHash').value = txHash;
      // how/where do I preventDefault()?
    } catch (err) {
      alert('ERROR! '   err);
    }
  } else {
    alert('MetaMask is not installed!');
  }
}

The problem I encounter is that the form goes ahead with the submission without the hash. The transaction does go through (with MetaMask prompts and all) but on my backend I get an error.

I read that I am supposed to preventDefault() but I am not sure how to apply it. Can someone guide me on how to do this? Plain JavaScript would be the most ideal as I am trying to reduce dependencies on external libraries.


Edit1: I tried preventDefault at the beginning but I don't even see any alerts.

Edit2: Added the fields that were missing in my question

CodePudding user response:

Well I'd go with:

  1. Removing onSubmit="processStep1()" and replacing it with javascript: document.getElementById('formConfirm').onsubmit = processStep1;. Note the lack of () here! EDIT: as someone already pointed out, removing () in onSubmit="processStep1()" should also do the trick
  2. Then, your function gets an event as parameter, co you can do async function processStep1(event) { ... }
  3. Now the last thing is to call event.preventDefault() somewhere at the beginning. Remember that you are preventing default action, so you are not submitting the form - you probably want to use fetch() to submit the form manually.

Other than that you can replace input type="submit" with a custom button with your function on click, so you don't have to call event.preventDefault(). But imo no big difference.

CodePudding user response:

Some errors:

  1. onSubmit takes a function and not a function call so it should be:
<form ... onSubmit="processStep1"> ...
  1. If you want to stop the form action you need to call the preventDefault method of the event, which stops the browser to contacting the form action at first place:
async function processStep1(event) {
   // I suggest as first row so you are sure
   // the form will stop before any other operation/error
   // made by this function
   event.preventDefault();
   ...
  1. You then need to call your backend with a XHR (XMLHttpRequest - MDN) because you stopped the normal call that your browser would have done (by preventing the default of the event):
function sendForm(form) {
   var formData = new FormData();
   var inputs = form.querySelectorAll('input');

   inputs.forEach(function(input) {
      var data;
      // simplified version for files (since it seems you don't need it)
      if (input.type === 'file') { data = input.files[0]; }
      else { data = input.value; }
      formData.append(input.name, data);
   });

   return new Promise(function(y, n) {
      var xhr= new XMLHttpRequest();
      xhr.onreadystatechange = function () {
          if (xhr.readyState === XMLHttpRequest.DONE) {
             if (status === 0 || (status >= 200 && status < 400)) { 
                y(xhr.responseText);
          }
          else { n(xhr); }
      };
      xhr.open(form.method, form.action);
      xhr.send(formData);
   });
}

async function processStep1(event) {
   ...
   // at the end of your function
   try {
     var response = await sendForm(this);
     // threat response
   } catch(ex) {
     /// threat exceptions
   }
}

For more info on FormData Object (MDN) I suggest you to follow the link for a better reading.

CodePudding user response:

Here. I just put the whole code.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <form id="formConfirm">
      <input id="textWalletAddress" name="walletAddress" type="text" />
      <input id="textEncodedFunctionCall" th:value="${encodedFunctionCall}" />
      <input type="text" id="textTxHash" readonly />
      <input type="submit" value="Submit" />
    </form>

    <script>
      const form = document.getElementById("formConfirm")

      async function processStep1(e) {
        // let efc = document.getElementById("textEncodedFunctionCall").value
        // let walletAddress = document.getElementById("textWalletAddress").value
        // const txParams = {
        //   to: CONTRACT,
        //   from: walletAddress,
        //   data: efc,
        // }

        // if (window.ethereum) {
        //   try {
        //     const txHash = await window.ethereum.request({
        //       method: "eth_sendTransaction",
        //       params: [txParams],
        //     })

        //     document.getElementById("textTxHash").value = txHash
        //     // how/where do I preventDefault()?
        //   } catch (err) {
        //     alert("ERROR! "   err)
        //   }
        // } else {
        //   alert("MetaMask is not installed!")
        // }
        document.getElementById("textTxHash").value = "HASH"
      }

      form.addEventListener("submit", async function (e) {
        e.preventDefault()

        await processStep1()
      })
    </script>
  </body>
</html>

  • Related