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

The AJAX data submission did not go through as expected

I am facing an issue with two files on my site - home.php (view) and home.php (controller). In the home.php (view) file, I have a jQuery function that sends an AJAX request based on the W3 example. However, in the home.php (controller) file, the PHP variab ...

How come the HTML page served by the express.js route isn't linked to a CSS stylesheet?

Recently, I've been working with a server.js file that imports a router const path = require("path"); const express = require("express"); const app = express(); const PORT = 8080; app.use(express.urlencoded({ extended: true })); app.use(express.jso ...

The encoding function in Javascript and manipulation of unicode characters

Currently, I am working with ASP.NET MVC, utilizing Kendo UI Editor and jQuery AJAX. The issue arises when I have a £ character in the Kendo UI editor and proceed to send the content to the server using AJAX. The code snippet for this operation looks lik ...

Building a JavaScript application with Node.js and MySQL to seamlessly interact with both offline and online databases

As I develop a JavaScript web-app, my plan is to utilize Node.js for connecting the app with an existing MySQL database. My initial question pertains to the structure of the Node code: should it be written in the same .js file as my application or kept se ...

Guide on sharing a Vue project with other devices within a network

I'm a complete beginner when it comes to vue.js. After working on a few small projects, I want to make sure I understand how to share a vue project with others at this stage. Typically, I know that running 'npm run serve' in my project dir ...

Attempting to incorporate the jquery-mousewheel plugin into the jquery cycle2 library

I've been working on integrating the jquery-mousewheel plugin (https://github.com/jquery/jquery-mousewheel) with the jquery cycle2 plugin. Initially, everything was running smoothly until I encountered an issue where mouse scrolling was generating ex ...

The destination you are trying to reach through a POST request at this time is unavailable

I'm encountering an issue while attempting to send an AJAX request to a separate controller within my view. Here is how my form for the AJAX request appears. I have also experimented with sites_search_results_index_path, which according to my routes ...

Investigating High Energy Usage on Vue.js Websites: Identifying the Root Causes

My Vue.js application has grown to be quite large with over 80 .vue components. Users have been complaining about their phone batteries draining quickly and Safari displaying a "This webpage is using significant energy..." warning. I have tried investigat ...

When utilizing jade.compile for compiling a jade template containing mixins or included partials

I'm currently exploring solutions for this challenge. The issue at hand involves compiling a jade template for an email campaign, but the file I am attempting to compile is a mixin that includes some partials. Here's an example: controllers/us ...

What is the process for creating a local repository for Node.js npm?

When it comes to the building process in node js, there are a few goals that need to be called: Begin by calling npm install, which creates a folder called node_modules and places all dependencies from package.json into it. [for UI development] Execute a ...

What mechanism does the useState() function utilize in React to fetch the appropriate state object and function for a functional component when employing the state hook?

Currently focusing on deepening my understanding of the useState hook in react. I have a question regarding how useState retrieves the state object and modifier function specific to each functional component when it is called. What I'm wondering is w ...

Is it possible for me to generate HTML using JavaScript?

Below is the javascript code I have written, saved as create.js: var stuff = document.querySelector(".stuff"); var item = document.createElement('div'); item.className = 'item'; stuff.appendChild(item); This is the corresponding HT ...

Changing the fill color of an SVG pattern remains unchanged

I have been working with Vue.js to create SVGs with shape patterns as background. The patterns themselves are functioning correctly, but I am encountering an issue when attempting to dynamically change the color of the pattern filling by passing props. D ...

Is there a way to transmit the ENTER key press to the page setup dialog within Internet Explorer 7?

My code is designed to change the page orientation. It functions correctly in IE6, but encounters issues in IE7. Specifically, it stops at %a and fails to input the enter or tab keys needed to press 'OK'. var shell; function SetPrintProperties() ...

The Correct Way to Implement Google ReCaptcha

I've developed a PHP contact form that performs validation using AJAX/JSON on the server side. The errors are then passed to Javascript for display and adjustments to the HTML/CSS. My challenge now is to integrate Google ReCaptcha with AJAX validatio ...

Exploring the angular js repeater component's context menu options

In one of my current projects, the client has specifically requested a right-click menu feature. However, the challenge lies in ensuring that the function triggered by the menu options has access to relevant information from the model. For instance, you ...

What is the best way to implement a nested lookup in MongoDB within a field?

Within my database, I have a collection named Randomhospital. Inside this collection, there is a field named hospital structured as follows: { "id": "GuDMUPb9gq", "Hospital Name": "UPHI", "Hospital City&qu ...

Concealing Popover with internal click

I am currently implementing Vue-PopperJS in my project, following the setup provided on the linked page with a few modifications: <template> <Popper ref="popover" trigger="clickToToggle" :options="{ pla ...

Vue error: Uncaught promise rejection - RangeError: The computed value update has exceeded the maximum call stack size

My computed code snippet: computed: { display: { get() { return this.display }, set(newValue) { this.display = newValue } } }, Attempting to update the computed value from a function in ...

Change the default direction of content scrolling in CSS and JavaScript to scroll upwards instead of

I am currently working on a website where the navigation bar spans the entire width and remains fixed in place. Below the navigation bar is a cover image, followed by the main content section. As you scroll down, the navigation bar covers the image from t ...