0

Im strugglin with a problem I cannot figure out. Im getting data from a JSON to write the DOM of my html (a store, I write the different items with that json). The problem starts when I try to get the json data out of the function, in order to push all the items into an array (the array will be the shopping cart). I`ve tried every thing I know and the only thing I get is undefined. I need help!

this is the code

//this is the JSON file

[{
    "id" : "cnj01",
    "form_id" : "cnj_form",
    "title" : "Conejita dormilona",
    "name" : "conejitadormilona",
    "description" : "Conejita tejida con hilo fino rosa, sin accesorios.",
    "description_mid" : "Conejita tejida al crochet con hilo mediano color rosa. Se pueden incluir accesorios como chaleco o bufanda.",
    "description_long" : "Conejita tejida al crochet con hilo mediano color rosa. Rellenada con vellón siliconado. La altura es de 22 cm. El accesorio incluído es una vincha tejida con el mismo tipo y color de hilo. También se pueden incluir accesorios como chaleco o bufanda con colores a elección.",
    "price" : 850,
    "cant" : 1,
    "image" : "images/products/conejita.jpg",
    "altimg" : "conejita dormilona - mununuras.ar - juguetes de apego",
    "stock" : 4
},
{
    "id" : "zrt01",
    "form_id" : "zrt_form",
    "title" : "Zorrito cariñoso",
    "name" : "zorritocarinoso",
    "description" : "Zorrito tejido en hilo fino con ojos de seguridad.",
    "description_mid" : "Este simpático zorrito viene con un ocico plástico y ojitos de seguridad para los mas chiquitos.",
    "description_long" : "Este simpático zorrito viene con un ocico plástico y ojitos de seguridad para los mas chiquitos. Rellenada con vellón siliconado. La altura es de 14 cm. Tejido en hilo mediano de color negro, blanco y marron anaranjado.",
    "price" : 950,
    "cant" : 1,
    "image" : "images/products/zorrito.jpg",
    "altimg" : "zorrito cariñoso - mununuras.ar - juguetes de apego",
    "stock" : 3
},
{
    "id" : "mds01",
    "form_id" : "mds_form",
    "title" : "Llavero medusa",
    "name" : "llaveromedusa",
    "description" : "Llavero medusa, con anilla metálica pequeña.",
    "description_mid" : "Medusa tejida al crochet con hilo fino. Posee anilla de metal cosida. Viene en tres tamaños.",
    "description_long" : "Medusa tejida al crochet con hilo fino. Posee anilla de metal cosida. Viene en tres tamaños grande (7cm), mediano (5cm) y chico (3cm). Rellena con vellón siliconado. Ideal para regalar!",
    "price" : 550,
    "cant" : 1,
    "image" : "images/products/medusa.jpg",
    "altimg" : "Llavero medusa - mununuras.ar - juguetes de apego",
    "stock" : 10
},
{
    "id": "plt01",
    "form_id" : "plt_form",
    "title" : "Colgante de pollitos",
    "name" : "colgantepollito",
    "description" : "Colgante de tres pollitos con anillo transparente.",
    "description_mid" : "Cogante de tres pollitos con anillo transparente. Ideal para adornar tus cortinas.",
    "description_long" : "Colgante de tres pollitos tejidos al crochet, ideal para adornar tus cortinas. Viene en un único tamaño (45cm). Los pollitos están rellenos con vellón siliconado.",
    "price" : 750,
    "cant" : 1,
    "image" : "images/products/pollito.jpg",
    "altimg" : "Colgante de tres pollitos - mununuras.ar - juguetes de apego",
    "stock" : 5
}
]


// product constructor
class Product {
    constructor (id, form_id, title, name, description, description_mid, description_long, price, cant, image, altimg, stock) {
        this.id = id;
        this.form_id = form_id;
        this.title = title;
        this.name = name;
        this.description = description;
        this.description_mid = description_mid;
        this.description_long = description_long;
        this.price = parseFloat(price);
        this.cant = parseInt(cant);
        this.image = image;
        this.altimg = altimg;
        this.stock = parseInt(stock);
        this.subtotal = this.price * this.cant;
    }
}

// this is where I want to push every item of the JSON//
let shoppingCart = new Array;


const req = new XMLHttpRequest();
req.open('GET', 'scripts/products.json', true);
req.send();
req.onreadystatechange = function () {
    if (this.readyState == 4 && this.status == 200) {
        let data = JSON.parse(this.responseText);

        // this IS NOT WORKING
        data.forEach( (element) => {
            // this shows the correct data
            console.log(element);
            let product =  new Product (`${element.id}`, `${element.form_id}`, `${element.title}`, `${element.name}`, `${element.description}`, `${element.description_mid}`, `${element.description_long}`, `${element.price}`, `${element.cant}`, `${element.image}`, `${element.altimg}`, `${element.stock}`);
            shoppingCart.push(product);
//   these logs show me the correct data but when I do a console.log(shoppingCart) 
// out of this function, The only thig I get is "undefined".
            console.log(product);
            }
        )
        console.log(data);
        //the "for" below is writing my html without any problem.
        //That means the problem starts when I try to take the "data" content out of req.onreadystatechange = function ()
        // in order to push every item into shoppingCart
        for (item of data) {
            $("#show_products").append(`
            <article class="products__item">
            <div>
                <img src="${item.image}" alt="${item.altimg}">
            </div>
            <div class="products__item--description">
                <h3 tabindex=0>${item.title}</h3>
                <p tabindex=0>${item.description_mid}</p>
                <div class="products__item--description--buttons">
                    <a tabindex=0 href="#${item.id}_popup" class="know">know more</a>
                    <a tabindex=0 class="add" id="${item.form_id}">add to shopping cart</a>
                </div>
            </div>
        </article>
            <div id="${item.id}_popup" class="window__popup">
                <div class="container__popup">
                    <div class="popup"><a tabindex=0 href="" class="close__popoup">X</a>
                        <div><img src="${item.image}" alt="${item.altimg}"></div>
                            <div class="popup--description">
                                <div tabindex=0 class="title">${item.title}</div>
                                <p tabindex=0>${item.description_long}</p>
                            <div tabindex=0 class="price__popup">$950.-</div>
                            <a tabindex=0 class="add" id="zrt-btn2">add to shopping cart</a>
                        </div>
                    </div>
                </div>
            </div>
            `);
        }
    }
}
// here I can see al the items in the array
console.log(shoppingCart);

// but here, I get undefined
console.log(shoppingCart[0]);
console.log(shoppingCart[1]);
console.log(shoppingCart[2]);
// etc

I don´t know what I´m doing wrong.

  • 2
    You are doing the logging before the request completes. You can see `shoppingCart` array because console treats it as a live object but it is being populated after you log it. See [Weird behavior with objects & console.log](https://stackoverflow.com/questions/23429203/weird-behavior-with-objects-console-log) – charlietfl Jun 03 '21 at 02:02
  • 1
    Move those logs into the `onreadystatechange` function – charlietfl Jun 03 '21 at 02:05

2 Answers2

0

This is an issue involving async logic. Here's what's going on:

// #1
const shoppingCart = new Array
// ...
const req = new XMLHttpRequest();
// ...
req.onreadystatechange = function () {
  // ...
  // #3
}
// #2
console.log(shoppingCart)

The number signs in the above snippet denote the order of execution. First, you create this XMLHttpRequest() and attach an event listener to it. Then you attempt to log out the value of shoppingCart (which should be an empty list - Are you sure you read your output correctly and didn't get mixed up with your other console.logs?). At some point in the future, your request finishes and the callback is executed with your JSON data, which you then put into the array.

See the issue?

Any code that depends on this JSON data must be placed inside the XMLHttpRequest callback. That is, move your console.log() stuff into that callback like so:

const req = new XMLHttpRequest();
// ...
req.onreadystatechange = function () {
  // ...
  console.log(yourData)
}

If the callback starts getting really big, then split it up into multiple smaller functions.

(As a side note - XMLHttpRequest is a pretty old and difficult-to-use API. In the future, I would recommend using the fetch API instead)

Scotty Jamison
  • 10,498
  • 2
  • 24
  • 30
  • Yes, I´m trying to implement Fetch, but anyways, I can´t include my html code inside the XMLHttpRequest function. Is there any way I can get the data out of there without getting a "undefined" answer? – AbelMartin Jun 03 '21 at 06:04
  • if not, then the question would be: How can I import a json file inside my js without the need of using a request? – AbelMartin Jun 03 '21 at 06:06
  • I see you were able to figure it out - glad you found a solution. – Scotty Jamison Jun 03 '21 at 14:52
0

Well, finally I made it work! Thanx scott for your help. This is what I came up with:

fetch('scripts/products.json')
    .then(response => response.json())
    .then(data => { let fetchedData = [];
                    data.forEach( (item) => {fetchedData.push(item);});
                    sessionStorage.setItem('storeItems', JSON.stringify(fetchedData));
    });

fetch is easier to use as scott said, and then I used a forEach to push the different items of the store into the array (fetchedData) and then put that array on sessionStorage.

Then I load that on the shoppingCart array and I can rearrange it as I want.

It worked like a charm. I don´t know if this is the best way to do this but it works and hope this can help.