skip to Main Content

Built a Webform

<!DOCTYPE html>
<html lang="en">

<head>
  <meta name="robots" content="noindex">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap" rel="stylesheet">
  <link href="./css/styles.css" rel="stylesheet">
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="./js/cardreader.js"></script>
  <title>POSKick v1</title>
</head>

<body>
  <div class="container mx-auto p-4 h-full">
    <div class="flex justify-center h-full">
      <div class="max-w-[350px] w-full">
        <form action="/v1processpayment.php" method="POST">
          <div class="form-step active-step" id="step1">
            <h2 class="text-2xl text-center font-bold mb-4"> Order Info</h2>
            <label for="name">Order Amount:</label>
            <input type="text" id="amount" name="amount" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
            <br>
            <label for="name">Phone Number:</label>
            <input type="text" id="phone" name="phone" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
            <br>
            <label for="name">Zipcode:</label>
            <input type="text" id="zipcode" name="zipcode" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
            <input type="submit" id="submitButton" value="Submit" class="w-full mt-2 p-2.5 text-sm font-medium text-white bg-blue-600 rounded-md">

            <h2 class="text-2xl text-center font-bold mb-4"> Swipe Card</h2>

            <!--<label for="carddata">Card Data:</label>-->

            <button id="scanButton" class="w-full mt-2 p-2.5 text-sm font-medium text-white bg-blue-600 rounded-md">Capture Card</button>
            <div id="scanModal" class="modal">
              <div class="modal-content">
                <div class="spinner"></div>
                <p>Waiting for Customer...</p>
              </div>
            </div>
            <input type="password" id="carddata" name="carddata" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
          </div>
      </div>
    </div>
    </form>
</body>

</html>

and I am using some JS to capture input from a MSR card reader which passes the data to the carddata input field.

document.addEventListener("DOMContentLoaded", function() {
  const scanModal = document.getElementById("scanModal");
  const scanButton = document.getElementById("scanButton");
  const cardDataInput = document.getElementById("carddata");
  const form = document.querySelector("form"); // Select the form element
  let listeningForCardInput = false;
  let checkInterval;
  // Prevent the form from submitting
  form.addEventListener("submit", function(event) {
    if (listeningForCardInput) {
      event.preventDefault(); // Prevent the form from submitting
    }
  });
  // Show the modal and start listening for card input when the button is clicked
  scanButton.addEventListener("click", function() {
    scanModal.style.display = "block";
    listeningForCardInput = true;
    cardDataInput.focus(); // Automatically focus on the input for keyboard input
    // Check the input periodically with a short interval
    checkInterval = setInterval(checkAndCloseModal, 10); // Adjust the interval as needed
  });
  // Check if the card data is complete and close the modal
  function checkAndCloseModal() {
    const input = cardDataInput.value;
    if (input.endsWith("?")) {
      cardDataInput.value = input.trim(); // Remove leading/trailing spaces
      listeningForCardInput = false;
      scanModal.style.display = "none";
      clearInterval(checkInterval);
      // Automatically submit the form after the modal is closed
      submitForm();
    }
  }
  // Clear the interval when the modal is closed
  scanModal.addEventListener("click", function(event) {
    if (event.target === scanModal) {
      clearInterval(checkInterval);
      submitForm();
    }
  });
  // Function to submit the form
  function submitForm() {
    // Prevent further submissions
    form.removeEventListener("submit", preventSubmission);
    // Submit the form
    form.submit();
  }
  // Function to prevent form submission
  function preventSubmission(event) {
    event.preventDefault();
  }
  // Initially prevent form submission
  form.addEventListener("submit", preventSubmission);
});

if i hide the carddata field via either display:none or by changing the input type="hidden" the modal does not close nor does the form get submitted. But if i leave the input field visible the js populates the field, the modal closes and the form gets submitted.

How can i achieve the same goal but have both the submit button hidden and the input field hidden?

tried hiding the input field via type="hidden" field was hidden but the modal would never close.
tried hiding the input field via display:none in css but again the modal would never close.

Expected result is

  • Cashier taps Capture Card
  • Modal Pops up which triggers a js event listener looking for keyboard input
  • Customer swipes their card using the MSR which emulates KB input.
  • The JS event listener sees that there is no more input and the final character of the string is ? triggering the modal to close and the form to be submitted.

I want to hide the submit button and the carddata input field and have the modal dump the information collected from the MSR to the carddata input field that is hidden and submit the form when the modal is closed.

Lastly the form as you see it here is for Development purposes Amount, Phone, Zipcode will be automatically filled in by the POS System and wont actually be visible to the cashier this form will then be embed into the checkout process inside the point of sale system. via a tab titled Credit / Debit with the only button visible being the Capture Card Button

2

Answers


  1. Your code has a few syntax errors and mismatched tag closings

    If I remove the inner content, your HTML looks like this

    <body>
      <div class="container mx-auto p-4 h-full">
        <div class="flex justify-center h-full">
          <div class="max-w-[350px] w-full">
            <form action="/v1processpayment.php" method="POST">
              <div class="form-step active-step" id="step1">
                ...
              </div>
          </div>
        </div>
      </form>
    <body>
    

    It’s obvious the tag endings are mismatched now! Change it to the following

    <body>
      <div class="container mx-auto p-4 h-full">
        <div class="flex justify-center h-full">
          <div class="max-w-[350px] w-full">
            <form action="/v1processpayment.php" method="POST">
              <div class="form-step active-step" id="step1">
                ...
              </div>
            </form>
          </div>
        </div>
      </div>
    <body>
    

    For the future I recommend using a tool that will point this out for you, or validating your code here: https://validator.w3.org/

    This may or may not be the cause of the issue you are having, but it sure isn’t helping anything either

    Login or Signup to reply.
  2. I don’t know this MSR device but you say that is emulates a keyboard. In that case you can probably just listen for the input event on the form field. And each time there is an input you test if the form is valid. The value from the MSR has a pattern (as I can read, there is a "?" in the end). So, define a pattern for the formfield that matches the value expected from the MSR (maybe a certain length, "?" in the end or whatever). It is a regular expression — in the example I used .*?s* meaning "any character 0-more times, then a "?" and maybe 0-more spaces in the end". And set the form field to required. Now, the form can only submit if the pattern of the value is correct.

    Instead of calling form.submit() use the requestSubmit() method.

    And then the scanButton should have the type type="button" so that it does not trigger the submit event.

    I used a setTimeout() for emulating the keyboard input. Remove that code before testing with your MSR device.

    document.addEventListener("DOMContentLoaded", function() {
      const scanModal = document.getElementById("scanModal");
      const form = document.forms.form01; // Select the form element
      
      // Prevent the form from submitting
      form.addEventListener("submit", e => {
        e.preventDefault(); // Prevent the form from submitting
        scanModal.style.display = "none";
        let data = new FormData(e.target);
        console.log([...data]);
      });
      
      // Show the modal and start listening for card input when the button is clicked
      form.scanButton.addEventListener("click", e => {
        let form = e.target.form;
        scanModal.style.display = "block";
        form.carddata.value = ""; // clear value if a failed attempt left data
        form.carddata.focus(); // Automatically focus on the input for keyboard input
        // this setTimeout and its callback function is just for testing
        setTimeout(function(){
          form.carddata.value = " 12345?";
          let event = new Event('input');
          form.carddata.dispatchEvent(event);
        }, 1000);
      });
      
      form.carddata.addEventListener('input', e => {
        let form = e.target.form;
        // if the pattern defined on input[name="carddata"] is matching
        // the form is valid and can be submitted
        let formvalid = form.checkValidity();
        if (formvalid) {
          form.requestSubmit();
        }
      });
    });
    input[name="carddata"] {
      display: none;
    }
    #scanModal {
      display: none;
    }
    <form action="/v1processpayment.php" method="POST" name="form01">
      <div class="form-step active-step" id="step1">
        <h2 class="text-2xl text-center font-bold mb-4"> Order Info</h2>
        <label for="name">Order Amount:</label>
        <input type="text" id="amount" name="amount" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
        <br>
        <label for="name">Phone Number:</label>
        <input type="text" id="phone" name="phone" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
        <br>
        <label for="name">Zipcode:</label>
        <input type="text" id="zipcode" name="zipcode" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30">
        <input type="submit" id="submitButton" value="Submit" class="w-full mt-2 p-2.5 text-sm font-medium text-white bg-blue-600 rounded-md">
    
        <h2 class="text-2xl text-center font-bold mb-4"> Swipe Card</h2>
    
        <!--<label for="carddata">Card Data:</label>-->
    
        <button type="button" id="scanButton" class="w-full mt-2 p-2.5 text-sm font-medium text-white bg-blue-600 rounded-md">Capture Card</button>
        <div id="scanModal" class="modal">
          <div class="modal-content">
            <div class="spinner"></div>
            <p>Waiting for Customer...</p>
          </div>
        </div>
        <input type="text" id="carddata" name="carddata" class="w-full px-3 py-2 mb-2 transition-all border border-gray-200 rounded-md outline-blue-600/50 hover:border-blue-600/30" pattern=".*?s*" required>
      </div>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search