There was a problem retrieving the product information from the API

I have been struggling to pinpoint the exact issue at hand.

The foundation of HTML and CSS is pre-written, with JavaScript responsible for generating the core elements to populate the DOM.

Within my script, I am attempting to retrieve product data in order to fill the browser interface with shopping items.

The error appearing in the console is: Cannot set properties of undefined (setting 'innerText')

async function fakeStoreAPI_Products () {
    const urlOfData = await fetch('https://fakestoreapi.com/products');
    if(urlOfData.status !== 200 || !urlOfData.ok){
        throw new Error('There was a problem fetching the data...')
    }else if(urlOfData.status === 200 && urlOfData.ok){
        const response = await urlOfData.json();
        populate(response)
    }
}

function populate (completeData) {
    const displayAllCardsHere = document.getElementById('cards_inner');    
    const data = completeData;
    
    for(const datum of data){
        // The parent
        const div_class_card = document.createElement('div').setAttribute('class', 'card')
        // Child [p_class_title]
        const p_class_title = document.createElement('p').setAttribute('class', 'title')
        // Child [img]
        const img = document.createElement('div').setAttribute('class', 'img')
        // Child [p_class_description]
        const p_class_description = document.createElement('p').setAttribute('class', 'description')
        // Child [div_class_cat_price] ~ With children
        const div_class_cat_price = document.createElement('div').setAttribute('class', 'cat_price')
        // Children of [div_class_cat_price] ~ descendants of [div_class_card ~ The [grand] parent]
        const p_class_category = document.createElement('p').setAttribute('class', 'category')
        const p_class_price = document.createElement('p').setAttribute('class', 'price')
        
        p_class_title.innerText = datum['title']
        img.innerText = datum['image']
        p_class_description.innerText = datum['description']
        p_class_category.innerText = datum['category']
        p_class_price.innerText = datum['price']
        
        div_class_card.append(p_class_title)
        div_class_card.append(img)
        div_class_card.append(p_class_description)
        
        div_class_card.append(div_class_cat_price)
        
        div_class_cat_price.append(p_class_category)
        div_class_cat_price.append(p_class_price)
        
        displayAllCardsHere.append(div_class_card)
    }
}

fakeStoreAPI_Products().catch((err) => {
    console.log(err)
})
*{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body{
    font-family: Nunito Sans, Yu Gothic UI;
}

div#cards_outer{
    width: 100%;
    padding: 20px;
    display: grid;
    grid-row-gap: 20px;
}

div#heading{
    text-align: center;
}

div#heading span{
    font-size: 40px;
    font-weight: 600;
    /* hori verti blur colour */
    text-shadow: 0px 0px 6px #0007;
}

div#cards_inner{
    width: 100%;
    display: grid;
    grid-template: 1fr / repeat(auto-fit, minmax(200px, 1fr));
    grid-gap: 20px;
}

div#cards_inner div.card{
    /* hori verti blur color */
    box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.7);
    padding: 10px;
}

div#cards_inner div.card img{
    width: 100%;
}

div#cards_inner div.card p.description{
    font-size: 14px;
    text-align: justify;
    word-wrap: break-word;
}

div#cards_inner div.card p.title,
div#cards_inner div.card div.cat_price p.category,
div#cards_inner div.card div.cat_price p.price{
    text-align: center;
}

div#cards_inner div.card p.title{
    font-size: 18px;
    font-weight: 600;
    text-transform: capitalize;
}

div#cards_inner div.card div.cat_price p.category,
div#cards_inner div.card div.cat_price p.price{
    font-size: 14px;
    font-weight: 600;
}

div#cards_inner div.card div.cat_price p.category{
    text-transform: capitalize;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito+Sans&display=swap" />
    <title>Fetch data from API and display data on the browser</title>
</head>

<body>
    <div id="cards_outer">
        <div id="heading"><span>Fake API Store</span></div>
        <div id="cards_inner">
            <!-- populate cards here -->
        </div>
    </div>
</body>

</html>

What aspect did I overlook?

Answer №1

The issue lies in your method of setting the variable to

document.createElement('div').setAttribute('class', 'title')
. The function setAttribute('class', 'title') does not return the created HTML element.

To rectify this, follow these steps:

// Create parent element
const div_class_card = document.createElement('div')
div_class_card.setAttribute('class', 'card')
// Create child [p_class_title]
const p_class_title = document.createElement('p')
p_class_title.setAttribute('class', 'title')
// Create child [img]
const img = document.createElement('img')
img.setAttribute('class', 'img')
// Create child [p_class_description]
const p_class_description = document.createElement('p')
p_class_description.setAttribute('class', 'description')
// Create child [div_class_cat_price] along with its children
const div_class_cat_price = document.createElement('div')
div_class_cat_price.setAttribute('class', 'cat_price')
// Set attributes for children of [div_class_cat_price] which are descendants of [div_class_card (parent)]
const p_class_category = document.createElement('p')
p_class_category.setAttribute('class', 'category')
const p_class_price = document.createElement('p')
p_class_price.setAttribute('class', 'price')

The key is to create the element first and assign it to a variable before setting any attributes using that variable.

Edit:

The image may not be displayed because you have mistakenly created a div element instead of an img element in your img variable. Div elements cannot handle src attributes. To fix this, use the following code:

// Create child [img]
const img = document.createElement('img')
img.setAttribute('class', 'img')

Additionally, ensure that when setting the src attribute, you correctly reference the source data like this:

img.setAttribute('src', datum["image"])

Answer №2

Personally, I prefer utilizing HTML for the structure and then using javascript to manipulate and fill in the content. Your current code lacks clarity in the internal structure of the card. To improve this, consider organizing your card using the <template> tag before dynamically populating it with javascript.

In my experience, working with HTML directly not only simplifies the process but also leads to cleaner javascript code.

/*No modifications here, keep going*/
async function fetchProductsFromAPI() {
  const dataUrl = await fetch('https://fakestoreapi.com/products');
  if (dataUrl.status !== 200 || !dataUrl.ok) {
    throw new Error('There was a problem fetching the data...')
  } else if (dataUrl.status === 200 && dataUrl.ok) {
    const response = await dataUrl.json();
    renderCards(response)
  }
}

function renderCards(allData) {
  const displayContainer = document.getElementById('cards_inner');
  //Access the template object
  const template = document.getElementById("cardTemplate");  
  const data = allData;  
  
  for (const item of data) {
    //Clone the template
    let clone = template.content.cloneNode(true);
    /*Utilize query selectors to populate the clone*/
    clone.querySelector(".title").innerText = item["title"];
    clone.querySelector(".img img").setAttribute("src", item["image"]);
    clone.querySelector(".description").innerText = item["description"];
    clone.querySelector(".cat_price .category").innerText = item["category"];
    clone.querySelector(".cat_price .price").innerText = item["price"];
    
    //Add cloned element to the DOM
    displayContainer.appendChild(clone);
  }
}

fetchProductsFromAPI().catch((err) => {
  console.log(err)
})
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Nunito Sans, Yu Gothic UI;
}

div#cards_outer {
  width: 100%;
  padding: 20px;
  display: grid;
  grid-row-gap: 20px;
}

div#heading {
  text-align: center;
}

div#heading span {
  font-size: 40px;
  font-weight: 600;
  /* horizontal vertical blur color */
  text-shadow: 0px 0px 6px #0007;
}

div#cards_inner {
  width: 100%;
  display: grid;
  grid-template: 1fr / repeat(auto-fit, minmax(200px, 1fr));
  grid-gap: 20px;
}
​
div#cards_inner div.card {
  /* horizontal vertical blur color */
  box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.7);
  padding: 10px;
}

div#cards_inner div.card img {
  width: 100%;
}

div#cards_inner div.card p.description {
  font-size: 14px;
  text-align: justify;
  word-wrap: break-word;
}

div#cards_inner div.card p.title,
div#cards_inner div.card div.cat_price p.category,
div#cards_inner div.card div.cat_price p.price {
  text-align: center;
}

div#cards_inner div.card p.title {
  font-size: 18px;
  font-weight: 600;
  text-transform: capitalize;
}

div#cards_inner div.card div.cat_price p.category,
div#cards_inner div.card div.cat_price p.price {
  font-size: 14px;
  font-weight: 600;
}

div#cards_inner div.card div.cat_price p.category {
  text-transform: capitalize;
}
<div id="cards_outer">
  <div id="heading"><span>Fake API Store</span></div>
  <div id="cards_inner">
    <!-- populate cards here -->
  </div>
</div>
<template id="cardTemplate">
  <div class="card">
      <p class="title"></p>
      <div class="img"><img src=""/></div>
      <div class="description"></div>
      <div class="cat_price">
        <p class="category"></p>
        <p class="price"></p>        
      </div>
  </div>
</template>

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

Tips for concealing the header menu when scrolling on a Drupal website

Hey there, I need some help with hiding the header div while scrolling in Drupal. <header class="header<?php print theme_get_setting('header_top_menu') && !$one_page ? '' : ' header-two'; ?>"> <div clas ...

Dropped down list failing to display JSON data

I created a website where users can easily update their wifi passwords. The important information is stored in the file data/data.json, which includes details like room number, AP name, and password. [ {"Room": "room 1", "AP nam ...

Guide to designing a CSS gradient with a downward arrow linked to a specific container

I'm attempting to add a triangular arrow beneath the v-container, complete with a gradient color scheme. However, I'm struggling to integrate the gradient seamlessly. If I use CSS to create the arrow, the gradient doesn't align correctly. ...

Error encountered: Attempting to access the 'length' property of an undefined variable in JSON data while using the $.each function

When I execute the following code snippet: var obj = $.parseJSON(json.responseText); $.each(obj.collection.response, function (i) { $.each(this.PRESENT_STUDENT, function (i, j) { $.each(j , function (i, j){ $( ...

What is the best way to add a blob to the document object model (

I am a beginner when it comes to working with blobs, and I am looking for some guidance to avoid wasting hours on unsuccessful brute-force attempts. I have been using the PHP code below (sourced from here) to retrieve the base64-encoded image from my data ...

Is there a way I can detect a browser timeout and display a custom error message?

My webpage in classic asp contains a link to a local IP address, shown below: <a href="http://192.168.1.89">Link</a> When the local IP address is not available, the web browser eventually times out and shows its own error message. I ...

React Component Div Containing a Hydration Error

Can someone help me resolve the Hydration error related to a nested div issue? I am working on a component that has two main functions - fetching data and mapping it. However, I keep encountering a hydration error and I'm not sure why it's happe ...

One might encounter undefined JSON keys when attempting to access them from a script tag

During my attempts to load a specific Json using an Ajax GET request and then parsing it, I encountered an issue when trying to access the Json key from an HTML script tag, as it returned as undefined. To troubleshoot this problem, I decided to log all th ...

Retrieving registered components dynamically in Vue.js

Check out my scenario on jsBin In my setup, I have a selector <component :is="selectedComponent"></component>, along with a <select v-model="currentComponent">...</select> that allows me to choose which one is displayed. Currently ...

Select2 using AJAX: chosen option disappears upon receiving AJAX response

Despite going through numerous questions and answers, the issue persists. Here is an excerpt of the code in question: <div class="col-md-2"> <label for="wh_location">{{ __('reports.warehouse_movement.location') ...

Create a specialized angular controller

Is there a way to create a custom controller programmatically while preserving scope inheritance? I am looking to achieve something similar to this: var controller = 'myCtrl'; var html = '<p>{{value}}</p>'; var validScope= ...

Locate grandchildren elements using getElementById

My task is to modify the content and attributes of the table. The DOM structure is generated by a third-party tool, and I am using JavaScript to make changes in various sections. <div id="myId"> <div> <div> <table&g ...

Arrange the "See More" button in the Mat Card to overlap the card underneath

I'm currently working on a project that involves displaying cards in the following layout: https://i.stack.imgur.com/VGbNr.png My goal is to have the ability to click 'See More' and display the cards like this: https://i.stack.imgur.com/j8b ...

Utilizing JavaScript to Invoke Controller Actions

Currently, my ASP.NET MVC actions return JSON data, which is then displayed on the screen by my client using jQuery's ajax function. The JavaScript code I use to call these controller actions includes absolute paths like this: $.ajax({ url: &apos ...

Setting a cookie within an Angular interceptor

My angular interceptor function includes a request object. intercept(req: HttpRequest<any>, next: HttpHandler) { return next.handle(req); } I am looking to set my token in the request cookie under the name my-token. How can I achieve this? I ...

Error message '[object Error]' is being returned by jQuery ajax

I'm currently facing a challenge with my HTML page that calls an API. Every time I attempt to run it, I encounter an [object Error] message. Below is the code snippet in question: jQuery.support.cors = true; jQuery.ajax({ type: "POST", url: ...

When utilizing Rx.Observable with the pausable feature, the subscribe function is not executed

Note: In my current project, I am utilizing TypeScript along with RxJS version 2.5.3. My objective is to track idle click times on a screen for a duration of 5 seconds. var noClickStream = Rx.Observable.fromEvent<MouseEvent>($window.document, &apos ...

What is the best method for extracting [object Text] using XPath?

I'm currently working with Selenium and attempting to extract text from a node that contains the keyword "approved," but I'm unsure of how to retrieve and validate this specific text. Here is the node structure - <div class="Notification-bo ...

Using jQuery to handle nested div elements and triggering a click event only once when the inner div is clicked

I have a situation where I have nested divs. When the inner div (closeme) is clicked, I do not want the click event of the outer div (container) to be triggered. How can I achieve this? html <div id="container"> content <div id="closeme">< ...

Mobile video created with Adobe Animate

Currently, I am designing an HTML5 banner in Adobe Animate that includes a video element. However, due to restrictions on iPhone and iPad devices, the video cannot autoplay. As a workaround, I would like to display a static image instead. Can anyone provid ...