Ensure that my program is halted until the xmlhttprequest has completed

It seems like I've overcomplicated this problem for myself. In my page, I have 2 XMLHTTPRequests - the first request retrieves data from an API and fills my elements with this data. However, one of the fields in my elements requires a second request to a different endpoint using a value received from the first request, but it always ends up being filled with undefined.

I understand that this is happening because of the asynchronous nature of the request, where the site continues loading without waiting for the request to complete. I tried making the second request synchronous, but the issue persists (now causing the site to freeze briefly). I also attempted to use async/await, but my text editor gave me an error saying "await has no effect on the type of this expression," and now I'm at a standstill.

I believe my struggle stems from a lack of experience and understanding of asynchronous JavaScript (this is my first application using it).

Below is the code snippet:

let ourGrid = document.getElementById("res");
let searchValue;

function search() {
    searchValue = document.getElementById("search").value;
    getFoods(`https://api.spoonacular.com/recipes/findByIngredients?ingredients=${searchValue}&number=2&apiKey=${apikey}`);
}

function getFoods(url) {
    let xhr = new XMLHttpRequest();
    xhr.responseType = 'json';
    xhr.onreadystatechange = () => {
        if(xhr.readyState == XMLHttpRequest.DONE) {
            setFoods(xhr.response);
        } else {
            return "error";
        }
    };
    xhr.open('GET', url);
    xhr.send();
}

function setFoods(json) {
    if(json.length == 0) {
        alert(`No results found for ${searchValue}`);
    }else{
        ourGrid.innerHTML = json.map(foodLogic).join("");
    }
}

function foodLogic(foodItem) {
     return `<div class="imageItem"><img src="${foodItem.image}"></div>
     <div class="infoItem"><h2>${foodItem.title}</h2>
     <p class="summary">${requestSummary(foodItem.id)}</p>
     <p class="more"><a href="./moreInfo.html" target="_blank">More</a></p></div>`;
}

function requestSummary(id) {
    let url2 = `https://api.spoonacular.com/recipes/${id}/summary?apiKey=${apikey}`;
    let xhr2 = new XMLHttpRequest();
    xhr2.onreadystatechange = () => {
        if(xhr2.readyState == XMLHttpRequest.DONE){
            return returnSummary(JSON.stringify(xhr2.response));
        }
    };    
    xhr2.open('GET', url2, false);
    xhr2.send();
}

function returnSummary(json) {
    return json.summary;
}

Answer №1

Another option is to utilize promises or callbacks. Execute the second function only after the first one has completed and pass the data to a single function that handles everything.

Retrieve the summary right here and send it to the next function.

function getFoods(url){
    let xhr=new XMLHttpRequest();
    xhr.responseType='json';
    xhr.onreadystatechange=()=>{
        if(xhr.readyState==XMLHttpRequest.DONE){
            let summary = requestSummary(xhr.response.id);
            setFoods(xhr.response, summary); //pass summary
        }else{
            return "error";
        }
    }
    xhr.open('GET',url);
    xhr.send();
}

Now that you have access to the summary in setfoods, you can use it as needed

function setFoods(json,summary){
    if(json.length==0){
        alert(`no results found for ${searchValue}`);
    }else{
    ourGrid.innerHTML=json.map(foodLogic).join("");
    // You now have access to the summary, feel free to use it
    } 
}

Answer №2

I successfully tackled the issue by storing all the ids and subsequently requesting them one by one after the website and initial content from the first request had loaded. Instead of using ajax, which wasn't effective for me initially (I consulted a tutorial on it), I utilized fetch requests to achieve this. I then targeted each summary element in the HTML and filled them in sequence.

Here's the code snippet:

let grid = document.getElementById("res");
let searchValue;
let arrId = [];

function search() {
    searchValue = document.getElementById("search").value;
    getFoods(`https://api.spoonacular.com/recipes/findByIngredients?ingredients=${searchValue}&number=2&apiKey=${key}`);
}

function getFoods(url) {
    let xhr = new XMLHttpRequest();
    xhr.responseType = 'json';
    xhr.onreadystatechange = () => {
        if (xhr.readyState == XMLHttpRequest.DONE) {
            setFoods(xhr.response);
        } else {
            return "error";
        }
    }
    xhr.open('GET', url);
    xhr.send();
}

function setFoods(json) {
    if (json.length == 0) {
        alert(`no results found for ${searchValue}`);
    } else {
        grid.innerHTML = json.map(foodLogic).join("");
        fetchIds();
    }
}

function foodLogic(foodItem) {
    arrId.push(foodItem.id);
    return `<div class="imageItem"><img src="${foodItem.image}"></div>
    <div class="infoItem"><h2>${foodItem.title}</h2>
    <p class="summary"></p>
    <p class="more"><a href="./moreInfo.html" target="_blank">More</a></p></div>`;
}

function fetchIds() {
    let items = grid.getElementsByClassName("infoItem");
    for (let i = 0; i < arrId.length; i++) {
        fetch(`https://api.spoonacular.com/recipes/${arrId[i]}/summary?apiKey=${key}`)
        .then(response => response.json())
        .then(data => {
            console.log(data);
            items[i].getElementsByClassName("summary")[0].innerHTML = data.summary;
        });
    }
}

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

Please move the scroll down and then back up after an Ajax request because the scroll position has been reached

When I click a button, I am loading results using ajax. Every time I click, the page scrolls to a specific position with the following code: success: function(data) { $("#test").html(data).fadeIn("slow&quo ...

Converting an object of objects into an associative array using Javascript and JSON

Using AngularJS, I am sending this data to my API : $http.post('/api/test', { credits: { value:"100", action:"test" } }); Upon receiving the data in my nodeJS (+Express) backend, it appears as follows : https://i.stack.imgur.com/NurHp.png Why ...

Validation error occurred while attempting to send form data to the Contact Form 7 API through Next.js

Having trouble sending data to the Contact Form 7 API and encountering an error while submitting the form: {into: "#", status: "validation_failed", message: "One or more fields have an error. Please check and try again.", post ...

Steps to prevent specific links from being clickable in React Native's webview component

In my React Native app, I am utilizing the react-native-webview component to display blog posts. The code I have implemented is straightforward, but my goal is to restrict the webview to only show content from the blog section of the website, preventing us ...

AJAX requests sent from different origins to AWS S3 may encounter CORS errors on occasion

My current objective is to access publicly available files stored in S3. The CORS configuration for my S3 setup is as follows: <?xml version="1.0" encoding="UTF-8"?> <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> < ...

Shift the attention from the text box to the AJAX combobox when the enter key is pressed

I need to make it so that when I press the enter key in a textbox, the focus shifts to an ajax combobox. <script type="text/javascript"> $(document).ready(function () { $("#txtGroupSname").keydown(checkForEnter); function checkF ...

Limiting a user's ability to directly interact with JSP pages

When it comes to limiting user access to certain pages, I'm encountering some difficulties. Currently, I am sending an ajax request to a servlet. Upon successful ajax response, my goal is to redirect the page to another based on a condition. However, ...

Sharing information through a hyperlink to a Bootstrap popup window

I've been attempting to send data to a Bootstrap modal window with no success so far. First, I tried: <a href="#TestModal?data=testdata" role="button" class="btn" data-toggle="modal">Test</a> However, the modal did not open as expected. ...

Checking for the status of a checked box when the ::after pseudo-element is added after the box is marked

I need help verifying if a checkbox is checked in my selenium code. After the checkbox is checked, it adds ::after but I'm struggling to confirm the existence of that pseudo element. Can anyone assist me in resolving this issue? I have been unable to ...

Can you provide me with the sequelize query that is equivalent to this raw query?

Retrieve the ID from the offers table where the user ID is not equal to '2' and the ID is not present in the list of notified offers for user '2'. ...

Guide for accessing and interpreting a random folder arrangement using JavaScript located alongside index.html

I am currently developing a testing reporting tool that organizes images into folders, resulting in a structure similar to this: root/ /counter/ img1.png img2.png /alarm/ img3.png The names of the folders like counter and alarm are not f ...

PHP/JSON formatting

My goal is to populate a dropdown menu with entries from MySQL using a technique I found in this particular answer. It's functioning well - when an event is selected, a new dropdown appears with the dates that event is scheduled for. But now, I also ...

How to enable CORS in Flask while avoiding the "Response to preflight request does not have an HTTP ok status" issue

Seeking assistance with setting up client-side Javascript code to send post requests to my Flask backend. I referenced this helpful answer regarding an issue with flask-cors being blocked by CORS policy, resulting in a preflight request error without passi ...

How can one implement an AJAX login feature in the Yii framework?

Recently embarked on the journey of learning AJAX and Yiiframework. Can someone guide me through the process of creating an AJAX login form in Yii? Appreciate any help. Thanks! ...

What is the most efficient way to incorporate MongoDB into your codebase using ES6-style

I have encountered an issue with importing MongoDB using the es6 import-from style. When I try to import using node's require method, everything works fine. let mongo = require('mongodb'); let MongoClient = mongo.MongoClient; However, when ...

"Utilizing jQuery to integrate an Ajax-powered Gauge using Google Visualization API

I need help creating a dynamic dashboard gauge that updates using ajax. The code snippet below shows what I have so far, but I'm struggling with updating the gauge itself. Any advice or suggestions on how to achieve this? google.load('v ...

Addressing simple JavaScript "async" AJAX requests that are sequenced and reliant on each other

I'm currently developing an application that includes a dashboard on its main page. In order to address any potential loading issues, the content of the dashboard is being calculated asynchronously using Ajax. This means that users do not have to wait ...

Encountering a Nuxt error where properties of null are being attempted to be read, specifically the 'addEventListener' property. As a result, both the default

Currently, I am utilizing nuxt.js along with vuesax as my UI framework. I made particular adjustments to my default.vue file located in the /layouts directory by incorporating a basic navbar template example from vuesax. Subsequently, I employed @nuxtjs/ ...

Having trouble getting an Angular directive to bind a click event to an external element?

I've been working on creating a unique custom event for toggling with Angular. The directive I'm using is called toggleable. It may sound simple at first, but the tricky part is that I want to be able to use any button or link on the page for to ...