The asynchronous AJAX request is finished after the function call has been made. This can be achieved without using

I am in search of a solution that will allow an AJAX API call to finish before the containing function does without relying on jQuery as a dependency for just one REST call...

After going through multiple solutions, all of which involve using jQuery, I came across this question How do I return the response from an asynchronous call?. However, I am determined to find a way to achieve this without adding jQuery as a dependency.

Currently, when a failing zip code value is inputted and the user clicks Submit, an alert pops up displaying other failed business rules but not the error related to "Mismatch in State and Zip."). Upon console logging, it seems that the REST call is successfully made and a response is received, but the alert(error) gets triggered before the async REST call completes and appends the value of error.

JS

function checkForm(form){
  var state = form.state;
  var zip = form.zip;
  var error = '';
  var flag = 0;

  var ckZip = checkZip(state, zip);
  if (ckZip.flag == 1){
    flag = 1;
  }
  error += ckZip.error;

  // show error and disable form submit if flag == 1
  if (flag == 1){
    alert(error);
    return false;
  }
}

function checkZip(state, zip){
  var state = form.state;
  var zip = form.zip;
  var error = '';
  var flag = 0;

  // check if value entered
  if (zip == ''){
    error += "Please provide a zip/postal code.\r\n";
    flag = 1;
  }

  // business rule: cannot enter - in a ZIP
  if (zip.search(/\x2d/) != -1){
    error += "Please remove dash from zip or postal code.\r\n";
    flag = 1;
  }

  // check if state and zip match
  // IMPORTANT: Fill in your client key
  var clientKey = "this-is-a-valid-key";
  var zipcode = zip.substring(0, 5);
  var url = "https://www.zipcodeapi.com/rest/"+clientKey+"/info.json/" + zipcode + "/radians";
  // Make AJAX request
  var request = new XMLHttpRequest();
  request.open('GET', url, true);

  request.onreadystatechange = function() {
    if (this.readyState === 4) {
      if (this.status >= 200 && this.status < 400) {alert("Got it");
        // Success!
        var data = JSON.parse(this.responseText);alert(data.state);
        if (data.state != state){
          error += "Mismatch in State and Zip.\r\n";
      flag = 1;
        }
      } else {
        // Error :(
        var response = JSON.parse(this.responseText);
        error += "error: " + response.error_msg;
      }
    }
  };

  request.send();
  request = null;

  return {flag: flag, error: error};
}

HTML

<form>
  <select id="state" name="state">
      <option value="" selected=""></option>
      <option value="AA">APO AA</option>                
      <option value="AE">APO AE</option>                
      <option value="AP">APO AP</option>                
      <option value="AL">Alabama</option>               
      <option value="AK">Alaska</option>                
      <option value="AZ">Arizona</option>               
      <option value="AR">Arkansas</option>                
      <option value="CA">California</option>                
      <option value="CO">Colorado</option>                
      <option value="CT">Connecticut</option> 
      <!-- ... -->              
  </select>

  <input type="text" id="zip" name="zip" value="">   
  <input type="Submit" id="Submit" name="Submit" value="Continue" onclick="return checkForm(this.form)">
</form>

Answer №1

To actually retrieve information from the ajax call within your function, you may consider making the ajax call synchronous. However, I advise against this approach as it can freeze the UI of the browser tab, leading to a negative user experience. In addition, it is not necessary.

Instead, opt for an asynchronous call and learn how to handle the inability of the function to return information directly as a return value. You can refer to this question and its answers for guidance on how to achieve this. It's simpler than one might think. :-)

If you want to make your checkZip function work asynchronously, follow these steps:

Firstly, move the ajax call from the submit button to the form itself:

<form onsubmit="return checkZip(this)">

Next, ensure that checkZip always prevents form submission by returning false, and then submit the form once the ajax call is completed:

function checkZip(form) {

    // ...

    request.onreadystatechange = function() {
        // ...
        if (/* it's okay to submit the form*/) {
            form.submit(); // Does NOT call the handler again
        } else {
            // show error to user
        }
    };

    // Prevent initial form submission
    return false;
}

Keep in mind that since the form was not actually submitted when the "Submit" button was pressed, it will not include the Submit field with the value

Continue</code. If needed, you can remove the <code>name
from the submit button and add a hidden field instead:

<input type="hidden" name="Submit" value="Continue">

While it is technically feasible to make the ajax call synchronous by setting the third argument of open to false, I strongly discourage doing so.

request.open('GET', url, false);
// ----------------------^^^^^

Once again, I highly recommend avoiding synchronous ajax calls.

Answer №2

To ensure synchronous behavior, you have the option to use the XMLHTTPRequest object in a synchronous mode:

var request = new XMLHttpRequest();
request.open('GET', url, false);

It is worth noting that this method is generally discouraged by many developers.

Alternatively, you could place your alert function inside a setTimeout with a short delay to give the request enough time to complete processing:

setTimeout(function() {
    // Display error message and prevent form submission if flag is equal to 1
    if (flag == 1) {
        alert(error);
        return false;
    }
}, 1000);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating React component when a property in an array of objects changes by utilizing the useEffect() hook

In my current project, I am creating a React application that resembles Craigslist. In this app, logged-in users can browse through items for sale or services offered. When a user clicks on an item, they are able to view more details and even leave a comm ...

What is the best way to pass the reference of the p tag every time the button is clicked?

This is the code I used to create a button: <button type="submit" id="likebtn" onclick="likedpost(this) " data-postid="<%=blog._id%>" data-author="<%=user.username%>">Like</button> ...

Passing the unique identifier of a record in NextJS to a function that triggers a modal display

I'm currently facing an issue with my NextJS component that displays a list of people. I have implemented a delete button which triggers a modal to confirm the deletion of a person, but I am struggling with passing the id of the person to be deleted. ...

What is the most elegant way to retrieve a new item from Firebase and read it?

My goal is to display the result of a successful read on a page, with only one attempt available before the headers are set and the page is sent. I am looking to retrieve one new value, generated after a listener was initiated so as not to pull existing da ...

Ways to extract information from PayFast

One issue I'm facing with my online store is that although PayFast does call my notify_url, it appears that no data is being posted. Below are the codes I've been using: Code for purchasing: <button id="cCart" type="submit" class="bt ...

Utilizing a drop-down menu to display two distinct sets of data tables

After spending some time on my WordPress site, I've encountered a problem that has me feeling stuck. Currently, I have two functioning datatables which are displaying one on top of the other on the page. Additionally, there is a dropdown selection box ...

Ensuring the checkbox is disabled prior to editing

Check out my table below: https://i.stack.imgur.com/7byIa.png Whenever I click the edit button, I can modify the status field and action field. This feature works correctly. However, the issue is that I am able to change the values of status and action e ...

Is it achievable to set a tab value for an HTML form element?

I'm wondering if it's possible to set a tab character as the value for an HTML dropdown list. Here is the code I currently have: <select id="delimiter-select" class="form-control form-control-sm csv-select"> <option value ...

Check out how to utilize the jQuery .ajax Post method in a function

Can an AJAX POST be directed to a specific function in a PHP file? $.ajax({ type: "POST", url: "functions.php", //is there a way to specify a function here? data: "some data...", success: function(){ alert('Succ ...

How do I specify a unique directory for pages in Next.js that is not within the src or root folders?

I'm currently facing an issue when trying to set a custom directory in Next JS. Although the default setup dictates that the pages directory should be located at the root or within the src directory, this arrangement doesn't fit my requirements ...

Setting the content-type for static assets in NuxtJS

I'm trying to use the Nuxt built-in server to serve the static file /.well-known/apple-app-site-association with a content-type of application/json. Unfortunately, because the file does not have a .json extension, it is returning as application/octet- ...

Tips for customizing vue-bootstrap-datetimepicker: Adjusting width and adding icons for a personalized touch

I am working with two date pickers from the Vue Bootstrap DateTimePicker package. While the functionality is great, I need to modify their appearance. Here is the relevant code snippet: <template> <div> <div class="form-row"> ...

Encountering an issue with NextJS useRouter when it is utilized within a function

I have encountered a puzzling issue that I can't seem to resolve. In my experimentation with NextJS, I am attempting to access the params in the router by utilizing the useRouter hook and integrating it with the querystring plugin to parse the asPath, ...

Retrieve both the key and value from an array of objects

I have been scouring the internet for a solution to this question, but I haven't come across anything that fits my needs. Let's say we have an array of objects like this -- "points":[{"pt":"Point-1","value":"Java, j2ee developer"},{"pt":"Point ...

Show information - press the button on the current PHP page

After successfully reading files via PHP from a directory and dynamically creating a drop-down menu to view the file content, I have a query. Is there a way to display the text files' content on the same page without calling another PHP page? I know t ...

Having npm start is causing an error to be displayed

I am encountering an issue when I try to start 'npm' on my mean.js application. The error message is related to a missing file called '.csslintrc'. Below, I have included the terminal output as well as the snippet of code where the erro ...

Using ngFor in Angular 2-5 without the need for a div container wrapping

Using ngFor in a div to display an object containing HTML from an array collection. However, I want the object with the HTML node (HTMLElement) to be displayed without being wrapped in a div as specified by the ngFor Directive. Below is my HTML code snipp ...

When the second click triggers the loading of a JSON lot via AJAX

As a newcomer to jQuery and ajax, I am in the process of developing an application where content is loaded from a JSON file based on the navigation option selected. Here is the code snippet I've been working on: $(document).ready(functi ...

Adjust the aesthetic based on whether the field is populated or empty

I have a simple text field on my website that triggers a search when the user inputs a value. I am wondering if it is possible to style the text field differently depending on whether it is empty or has content. Specifically, I want to change the border c ...

Disregard the popstate triggered by Safari's Initial Page Load

Utilizing pushState, I am able to generate the page view on popstate events based on the history.state of the current page. In cases where there is no history.state present, my intention is to reload the document (hopefully). window.onpopstate = function ...