skip to Main Content

I’m building a fictional webshop for plants and currently I’m working on filtering them combining different options (light demand, water demand, toxic etc.).

Using a separate JSON file, I’m creating cards based on the data after the JSON file was fetched:

getPlants().then((data) => {
  data.forEach((data) => {
    plantcards.insertAdjacentHTML(
      "afterbegin",
      `<article class="plantcard ${getPlantLight(data.Light)} ${getPlantWater(
        data.WaterDemand
      )}wasser ${getPlantToxic(data.Toxic)}">
        <div class="article-wrapper">
          <figure>
            <img src="../images/plant_types/${data.Image}" alt="${data.Name}" />
          </figure>
          <div class="article-body">
            <h2>${data.Name}</h2>
            <h3>${data.NameLatin}</h3>
            <p>
               Standort: ${getPlantLight(data.Light)}<br/>
               Wasserbedarf: ${getPlantWater(data.WaterDemand)}<br/>
               Schwierigkeitsgrad: ${getPlantMaintenance(data.Maintenance)}<br/>
               Giftig: ${getPlantToxic(data.Toxic)}<br/>
            </p>
            <a href="#" class="read-more">
              Read more <span class="sr-only">about this is some title</span>
              <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
                <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
              </svg>
            </a>
          </div>
        </div>
      </article>`
    );
  });
});

let allPlantcards = Array.from(document.querySelectorAll(".plantcard"));

allPlantcards is always an empty array with a length of 0, I guess because allPlantcards is created before or while the cards are loaded.

I also tried to place let allPlantcards = Array.from(document.querySelectorAll(".plantcard")); within other functions but then I can’t use them outside of the function, right?

2

Answers


  1. It sounds like you’re dealing with a timing issue where you’re trying to select elements that haven’t been added to the DOM yet because your document.querySelectorAll(".plantcard") call is executed before the cards are inserted.

    Here is the modest proposition of the working code:

    This HTML template sets up a basic structure and functionality for displaying and managing plant cards in a webshop. Adjust the paths to images and data as needed for your application.

    getPlants() simulates fetching plant data. Replace this with your actual API call. getPlantLight(), getPlantWater(), getPlantToxic(), and getPlantMaintenance() determine CSS classes based on plant attributes. displayPlantCards(data) adds plant cards to the DOM and selects them afterward.

    async function getPlants() {
      return [{
          Name: "Aloe Vera",
          NameLatin: "Aloe barbadensis",
          Light: "Bright",
          WaterDemand: "Low",
          Maintenance: "Easy",
          Toxic: "No",
          Image: "https://fastly.picsum.photos/id/649/200/300.jpg?hmac=3hfKZ0fzc7Ie_jSDrRCLD-bO3e71sZ_5xyZmJQXyNFg"
        },
        {
          Name: "Spider Plant",
          NameLatin: "Chlorophytum comosum",
          Light: "Indirect",
          WaterDemand: "Medium",
          Maintenance: "Easy",
          Toxic: "No",
          Image: "https://fastly.picsum.photos/id/649/200/300.jpg?hmac=3hfKZ0fzc7Ie_jSDrRCLD-bO3e71sZ_5xyZmJQXyNFg"
        }
        // Add more plant objects as needed
      ];
    }
    
    function getPlantLight(light) {
      return light === "Bright" ? "bright-light" : "indirect-light";
    }
    
    function getPlantWater(waterDemand) {
      return waterDemand === "Low" ? "low-water" : "medium-water";
    }
    
    function getPlantToxic(toxic) {
      return toxic === "Yes" ? "toxic" : "non-toxic";
    }
    
    function getPlantMaintenance(maintenance) {
      return maintenance === "Easy" ? "easy-maintenance" : "hard-maintenance";
    }
    
    function displayPlantCards(data) {
      const plantcards = document.getElementById("plantcards");
    
      data.forEach((plant) => {
        plantcards.insertAdjacentHTML(
          "beforeend",
          `<article class="plantcard ${getPlantLight(plant.Light)} ${getPlantWater(
            plant.WaterDemand
          )} ${getPlantToxic(plant.Toxic)}">
                            <div class="article-wrapper">
                                <figure>
                                    <img src="${plant.Image}" alt="${plant.Name}" />
                                </figure>
                                <div class="article-body">
                                    <h2>${plant.Name}</h2>
                                    <h3>${plant.NameLatin}</h3>
                                    <p>
                                       Standort: ${getPlantLight(plant.Light)}<br/>
                                       Wasserbedarf: ${getPlantWater(
                                         plant.WaterDemand
                                       )}<br/>
                                       Schwierigkeitsgrad: ${getPlantMaintenance(
                                         plant.Maintenance
                                       )}<br/>
                                       Giftig: ${getPlantToxic(plant.Toxic)}<br/>
                                    </p>
                                    <a href="#" class="read-more">
                                      Read more
                                      
                                      <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
                                        <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
                                      </svg>
                                    </a>
                                </div>
                            </div>
                          </article>`
        );
      });
    
      // After inserting the plant cards, you can select them
      const allPlantcards = Array.from(document.querySelectorAll(".plantcard"));
    
      // Example: Add your logic to filter or manipulate plant cards here
      console.log(allPlantcards); // Check if cards are correctly selected
    }
    
    // Fetch data and display plant cards
    getPlants().then((data) => {
      displayPlantCards(data);
    });
    #plantcards {
      display: flex;
      flex-wrap: wrap;
      gap: 20px;
      padding: 20px;
      justify-content: center;
    }
    
    .plantcard {
      width: 200px;
      background-color: #f0f0f0;
      border: 1px solid #ddd;
      border-radius: 8px;
      overflow: hidden;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
      display: flex;
      flex-direction: column;
    }
    
    .article-wrapper {
      display: flex;
      flex-direction: column;
      flex: 1;
    }
    
    .article-body {
      padding: 10px;
      flex: 1;
      display: flex;
      flex-direction: column;
    }
    
    .article-body h2 {
      margin: 0;
      font-size: 1.2em;
    }
    
    .article-body h3 {
      margin: 5px 0;
      color: #555;
      font-size: 1em;
    }
    
    .article-body p {
      margin: 10px 0;
      font-size: 0.9em;
      color: #333;
    }
    
    .read-more {
      display: flex;
      align-items: center;
      text-decoration: none;
      color: #007bff;
      font-weight: bold;
      margin-top: auto;
      padding: 10px;
      border-top: 1px solid #ddd;
      background-color: #fff;
    }
    
    .read-more .icon {
      margin-left: 5px;
      width: 16px;
      height: 16px;
    }
    
    .plantcard img {
      width: 100%;
      height: auto;
      display: block;
    }
    <div id="plantcards">
      <!-- Plant cards will be dynamically inserted here -->
    </div>
    Login or Signup to reply.
  2. The problem you’re running into is really due to the fact that querySelectorAll is called before the elements have been added to the DOM using insertAdjacentHTML. To solve this problem, you need to make sure that the code to select the elements is executed after all the plant cards have been added to the DOM.

    Simply move the querySelectorAll call to the end of getPlants().then(…) so that it is executed after all the cards have been added to the DOM:

    getPlants().then((data) => {
      data.forEach((data) => {
        plantcards.insertAdjacentHTML(
          "afterbegin",
          `<article class="plantcard ${getPlantLight(data.Light)} ${getPlantWater(
            data.WaterDemand
          )}wasser ${getPlantToxic(data.Toxic)}">
            <div class="article-wrapper">
              <figure>
                <img src="../images/plant_types/${data.Image}" alt="${data.Name}" />
              </figure>
              <div class="article-body">
                <h2>${data.Name}</h2>
                <h3>${data.NameLatin}</h3>
                <p>
                   Standort: ${getPlantLight(data.Light)}<br/>
                   Wasserbedarf: ${getPlantWater(data.WaterDemand)}<br/>
                   Schwierigkeitsgrad: ${getPlantMaintenance(data.Maintenance)}<br/>
                   Giftig: ${getPlantToxic(data.Toxic)}<br/>
                </p>
                <a href="#" class="read-more">
                  Read more <span class="sr-only">about this is some title</span>
                  <svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
                    <path fill-rule="evenodd" d="M12.293 5.293a1 1 0 011.414 0l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414-1.414L14.586 11H3a1 1 0 110-2h11.586l-2.293-2.293a1 1 0 010-1.414z" clip-rule="evenodd" />
                  </svg>
                </a>
              </div>
            </div>
          </article>`
        );
      });
    
      // Now the cards have already been added to the DOM and we can select them
      let allPlantcards = Array.from(document.querySelectorAll(".plantcard"));
      console.log(allPlantcards); // Now allPlantcards will not be empty
    });
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search