david dawn
david dawn

Reputation: 1

How to pass ajax call result to subsequent ajax calls

Im currently trying to utilize multiple ajax calls through ajax chaining, but unsure on the best approach since there are a few ways to do this via new frameworks, jquery and pure javascript.

I would prefer to do this with pure vanilla javascript given the native development on js has improved a lot over recent years, however, in the instance of multiple ajax calls, i believe there is still plenty to be improved upon, i believe one of the ways would be to use promises ? i do see many deal with this occurrence via jquery.

i would be very appreciative if fellow coders could give their example as to how they would code a modern approach ajax chain call dependent on ajax returned call values preceding it.

ok, so in short, i am attempting to pass the value of the first ajax call to the second ajax call, along with identifying the correct way of executing the second ajax call.

Below i have added code with comments:

// Establish functionality on window load:
window.onload = function() {

    'use strict';

    // get product id on load
    var pid = document.getElementById('pid');
    var colorlist = document.getElementById('colorlist');
    var sizelist = document.getElementById('sizelist');

     colorlist.onclick = function(e) { 
    if (typeof e == 'undefined') e = window.event;

    var colorid = e.target.value

    while (sizelist.firstChild) {
    sizelist.removeChild(sizelist.firstChild);
    }

        // 2ND AJAX CALL
        var xhr = getXMLHttpRequestObject();

        xhr.open('GET', '/ajax/get_sizes.php?id=' + encodeURIComponent(pid.value) + '&colorid=' + encodeURIComponent(colorid), true);
        // set header if sending to php
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.send(null);

        // Function to be called when the readyState changes:
        xhr.onreadystatechange = function() {

            // Check the readyState property:
            if (xhr.readyState == 4) {

                    // Check the status code:
                    if ( (xhr.status >= 200 && xhr.status < 300) 
                    || (xhr.status == 304) ) {

                    var sizes = xhr.responseText;
                    var sizes = JSON.parse(sizes);

                    for (var i = 0, num = sizes.length; i < num; i++) {

                    var label = document.createElement('label');

                    label.setAttribute ("for", sizes[i].id);
                    label.classList.add("swatch");
                    label.innerHTML = sizes[i].size;

                    var radio = document.createElement('input');

                    radio.type = "radio";
                    radio.id = sizes[i].id;
                    radio.value = sizes[i].id;
                    radio.name = "sizes";

                    sizelist.appendChild(label);
                    sizelist.appendChild(radio);

                    } //END OF FOR LOOP

                } else { // Status error!
                document.getElementById('output').innerHTML = xhr.statusText;
                }

            } // End of readyState IF.

        }; // End of onreadystatechange anonymous function.
    }; // END OF COLORLIST ONCLICK

    // 1ST AJAX CALL
    var ajax = getXMLHttpRequestObject();

        // Function to be called when the readyState changes:
        ajax.onreadystatechange = function() {

            // Check the readyState property:
            if (ajax.readyState == 4) {

                // Check the status code:
                if ( (ajax.status >= 200 && ajax.status < 300) 
                || (ajax.status == 304) ) {

                    var colors = ajax.responseText;
                    var colors = JSON.parse(colors);

                    for (var i = 0, num = colors.length; i < num; i++) {

                        var label = document.createElement('label');
                        label.setAttribute ("for", colors[i].id);
                        label.classList.add("swatch", colors[i].color);
                        label.innerHTML = colors[i].color;

                        var radio = document.createElement('input');

                        radio.type = "radio";
                        radio.id = colors[i].id;
                        radio.value = colors[i].id;
                        radio.name = "colors";

                        colorlist.appendChild(label);
                        colorlist.appendChild(radio);
                    } // END OF FOR LOOP

                } //END OF STATUS CODE CHECK
                    else { // Status error!
                    document.getElementById('output').innerHTML = ajax.statusText;
                    }

            } // End of onreadyState IF.

        }; // End of onreadystatechange anonymous function.

    ajax.open('GET', '/ajax/get_colors.php?id=' + encodeURIComponent(pid.value), true);
    // set header if sending to php
    ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    ajax.send(null); 

}; // End of onload anonymous function.

Regards David

Upvotes: 0

Views: 570

Answers (2)

Emiel Zuurbier
Emiel Zuurbier

Reputation: 20934

Welcome to SO and thank you for your question. I'll do my best to show you some examples of how you could execute your code in a way that might be preferable to you as a solution.

Callbacks

What is a callback?

Simply put: A callback is a function that is to be executed after another function has finished executing — hence the name ‘call back’.

Source of quote

In your code example you want to execute at least 2 HTTP request after one another. This would mean that a piece of code has to be executed twice. For this you can write a function around the XMLHTTPRequest piece to be able to execute it multiple times when writing it down only once.

The function below here has two parameters: url and callback. The url parameter is a string which will be injected in the second parameter of the xhr.open method. The callback parameter will be a function. This function will be called when the request has been succesfully finished.

function get(url, callback) {
  var xhr = new XMLHTTPRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
      if ('function' === typeof callback) {
        callback(xhr.responseText);
      }
    }
  };
  xhr.open('GET', url, true)
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.send();
}

Here is a little example of how it would work. See that the callback function has a parameter called data1. That is the xhr.responseText that we got back from the XMLHTTPRequest. Inside the callback function call the get function again to make another request.

get('/ajax1.php', function(data1) {
  // Do something with data1.

  get('/ajax2.php', function(data2) {
    // Do something with data2.
  });

});

This is a fairly simple way to make a request after another is finished.
But what if we have 100 requests after each other?

Promisified XMLHTTPRequest

The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.

Source of quote

Enter Promises. The example below here is almost the same as the example above. Only this time we use a Promise. When calling get we immediately return a Promise. This promise will wait for itself to either resolve or reject. In this case we only use resolve for successful requests. Whenever the request has finished resolve is called and the Promise chain begins.

function get(url) {
  return new Promise(resolve => {
    var xhr = new XMLHTTPRequest();
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4 && xhr.status === 200) {
        if ('function' === typeof callback) {
          resolve(xhr.responseText);
        }
      }
    };
    xhr.open('GET', url, true)
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send();
  });
}

So instead of using a callback function we use then. Inside then we do use a callback function which allows us to use the value that has been resolved in the returned Promise. then can be chained with more then's inifinitely until you run out of things to chain.

Inside the callback function call the next request.

get('/ajax1.php')
  .then(data1 => {
    // Do something with data1.
    get('/ajax2.php')
      .then(data2 => {
        // Do something with data2.
      });
  });

Fetch

The Fetch API provides an interface for fetching resources (including across the network). It will seem familiar to anyone who has used XMLHttpRequest, but the new API provides a more powerful and flexible feature set.

Source of quote

Before we've created our own Promise version of an XMLHTTPRequest. But JavaScript has evolved an has gotten new tools to work with. fetch kind of looks like how our get function works, but has way more features and options to make it more powerful. And it also uses promises!

fetch('/ajax1.php')
  .then(response1 => response1.text())
  .then(data1 => {
    // Do something with data1.

    fetch('/ajax2.php')
      .then(response2 => response2.text())
      .then(data2 => {
        // Do something with data2.
      });

  })
  .catch(error => console.log(error));

Though the then syntax still makes us nest functions. Like before, what about when you have 100 callback functions to call? That will be a nesting mess!

Fetch + Async/Await

Now this is the way to tackle the nesting problem and make the syntax more like assigning a simple variable in JS. Async/Await is a part of modern JavaScript, so be wary of older browsers not supporting it. Check caniuse for the current support.

The Async/Await syntax works like the following. Create a function with the async keyword in front of it. This will indicate, like it implies, that async code will be performed here. It also makes the function with async before it automatically return a Promise.

Inside the async function use the await keyword whenever you call a function which returns a Promise, like fetch, or our own function get. This will return the resolved value without having to use then or a callback function.

The await keyword also makes the code actually wait before continueing to the next line of code. Now your JS looks nice and can be written with less nesting.

(async function() {

  const response1 = await fetch('/ajax1.php');
  const data1 = await response1.text();
  // Do something with data1.

  const response2 = await fetch('/ajax2.php');
  const data2 = await response2.text();
  // Do something with data1.

}());

I really hope this is helpful and helps you get where you need to be going. If you have any questions regarding the above, please let me know!

Have a good one!

Upvotes: 3

KrishnaSingh
KrishnaSingh

Reputation: 746

You can use Promise chain which could be like the example mentioned below:

.then(function(result) {
    return doSomethingElse(result);
    })
    .then(function(newResult) {
    return doThirdThing(newResult);
    })
    .then(function(finalResult) {
    console.log('Got the final result: ' + finalResult);
    })
    .catch(failureCallback);enter code here

You can the documentation mentioned below:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Upvotes: 0

Related Questions