Home > Enterprise >  cloneNode() and append() using Javascript
cloneNode() and append() using Javascript

Time:09-26

I am having trouble to achieve a desired result using cloneNode() and append(). When I execute the code below:

function loadMagicItems() {
    fetch('https://api.open5e.com/magicitems/?fields=slug,name,desc,type,rarity&limit=1000'
    ).then(function (responses) {
        return responses.json();
    }).then(function (data) {
        displayMagicItems(data.results);
    });
};

function displayMagicItems(items) {
    items.map((item) => {
        const itemName = item.name;
        if (itemName.startsWith("A")) {
            const magicItem = document.querySelector("li").cloneNode(true);
            magicItem.querySelector("a").innerHTML = itemName;
            document.querySelector(".magic-list").append(magicItem);
            document.querySelector('.magic-area').append(document.querySelector('.magic-list'));
        }
        else if (itemName.startsWith("B")) {
            const magicItem = document.querySelector("li").cloneNode(true);
            magicItem.querySelector("a").innerHTML = itemName;
            document.querySelector(".magic-list").append(magicItem);
            document.querySelector('.magic-area').append(document.querySelector('.magic-list'));
        }
    })
}
  <body onload="loadMagicItems()">
    <li><a></a></li>
    <ul class="magic-list"></ul>
    <div class="magic-area"></div>
  </body>

I have the following HTML result:

<div class="magic-area">
  <ul class="magic-list">
    <li><a>Adamantine Armor</a></li>
    <li><a>Amulet of Health</a></li>
    <li><a>Amulet of Proof against Detection and Location</a></li>
    <li><a>Amulet of the Planes</a></li>
    <li><a>Animated Shield</a></li>
    <li><a>Apparatus of the Crab</a></li>
    <li><a>Armor of Invulnerability</a></li>
    <li><a>Armor of Resistance</a></li>
    <li><a>Armor of Vulnerability</a></li>
    <li><a>Arrow-Catching Shield</a></li>
    <li><a>Arrow of Slaying</a></li>
    <li><a>Bag of Beans</a></li>
    <li><a>Bag of Devouring</a></li>
    <li><a>Bag of Holding</a></li>
    <li><a>Bag of Tricks</a></li>
    <li><a>Bead of Force</a></li>
    <li><a>Belt of Dwarvenkind</a></li>
    <li><a>Belt of Giant Strength</a></li>
    <li><a>Berserker Axe</a></li>
    <li><a>Boots of Elvenkind</a></li>
    <li><a>Boots of Levitation</a></li>
    <li><a>Boots of Speed</a></li>
    <li><a>Boots of Striding and Springing</a></li>
    <li><a>Boots of the Winterlands</a></li>
    <li><a>Bowl of Commanding Water Elementals</a></li>
    <li><a>Bracers of Archery</a></li>
    <li><a>Bracers of Defense</a></li>
    <li><a>Brazier of Commanding Fire Elementals</a></li>
    <li><a>Brooch of Shielding</a></li>
    <li><a>Broom of Flying</a></li>
  </ul>
</div>

Also I have tried this code:

function loadMagicItems() {
    fetch('https://api.open5e.com/magicitems/?fields=slug,name,desc,type,rarity&limit=1000'
    ).then(function (responses) {
        return responses.json();
    }).then(function (data) {
        displayMagicItems(data.results);
    });
};

function displayMagicItems(items) {
    items.map((item) => {
        const itemName = item.name;
        if (itemName.startsWith("A")) {
            const magicItem = document.querySelector(".magic-list").cloneNode(true);
            magicItem.querySelector("a").innerHTML = itemName;
            document.querySelector(".magic-area").append(magicItem);
        }
        else if (itemName.startsWith("B")) {
            const magicItem = document.querySelector(".magic-list").cloneNode(true);
            magicItem.querySelector("a").innerHTML = itemName;
            document.querySelector(".magic-area").append(magicItem);
        }
    })
}
  <body onload="loadMagicItems()">
    <ul class="magic-list">
      <li><a></a></li>
    </ul>
    <div class="magic-area"></div>
  </body>

But it gives me:

<div class="magic-area"><ul class="magic-list">
  <li><a>Adamantine Armor</a></li>
</ul><ul class="magic-list">
  <li><a>Amulet of Health</a></li>
</ul><ul class="magic-list">
  <li><a>Amulet of Proof against Detection and Location</a></li>
</ul><ul class="magic-list">
  <li><a>Amulet of the Planes</a></li>
</ul><ul class="magic-list">
  <li><a>Animated Shield</a></li>
</ul><ul class="magic-list">
  <li><a>Apparatus of the Crab</a></li>
</ul><ul class="magic-list">
  <li><a>Armor of Invulnerability</a></li>
</ul><ul class="magic-list">
  <li><a>Armor of Resistance</a></li>
</ul><ul class="magic-list">
  <li><a>Armor of Vulnerability</a></li>
</ul><ul class="magic-list">
  <li><a>Arrow-Catching Shield</a></li>
</ul><ul class="magic-list">
  <li><a>Arrow of Slaying</a></li>
</ul><ul class="magic-list">
  <li><a>Bag of Beans</a></li>
</ul><ul class="magic-list">
  <li><a>Bag of Devouring</a></li>
</ul><ul class="magic-list">
  <li><a>Bag of Holding</a></li>
</ul><ul class="magic-list">
  <li><a>Bag of Tricks</a></li>
</ul><ul class="magic-list">
  <li><a>Bead of Force</a></li>
</ul><ul class="magic-list">
  <li><a>Belt of Dwarvenkind</a></li>
</ul><ul class="magic-list">
  <li><a>Belt of Giant Strength</a></li>
</ul><ul class="magic-list">
  <li><a>Berserker Axe</a></li>
</ul><ul class="magic-list">
  <li><a>Boots of Elvenkind</a></li>
</ul><ul class="magic-list">
  <li><a>Boots of Levitation</a></li>
</ul><ul class="magic-list">
  <li><a>Boots of Speed</a></li>
</ul><ul class="magic-list">
  <li><a>Boots of Striding and Springing</a></li>
</ul><ul class="magic-list">
  <li><a>Boots of the Winterlands</a></li>
</ul><ul class="magic-list">
  <li><a>Bowl of Commanding Water Elementals</a></li>
</ul><ul class="magic-list">
  <li><a>Bracers of Archery</a></li>
</ul><ul class="magic-list">
  <li><a>Bracers of Defense</a></li>
</ul><ul class="magic-list">
  <li><a>Brazier of Commanding Fire Elementals</a></li>
</ul><ul class="magic-list">
  <li><a>Brooch of Shielding</a></li>
</ul><ul class="magic-list">
  <li><a>Broom of Flying</a></li>
</ul></div>

What I am looking for would be something like this:

<div class="magic-area">
  <ul class="magic-list">
    <li><a>Adamantine Armor</a></li>
    <li><a>Amulet of Health</a></li>
    <li><a>Amulet of Proof against Detection and Location</a></li>
    <li><a>Amulet of the Planes</a></li>
    <li><a>Animated Shield</a></li>
    <li><a>Apparatus of the Crab</a></li>
    <li><a>Armor of Invulnerability</a></li>
    <li><a>Armor of Resistance</a></li>
    <li><a>Armor of Vulnerability</a></li>
    <li><a>Arrow-Catching Shield</a></li>
    <li><a>Arrow of Slaying</a></li>
  </ul>
  <ul class="magic-list">
    <li><a>Bag of Beans</a></li>
    <li><a>Bag of Devouring</a></li>
    <li><a>Bag of Holding</a></li>
    <li><a>Bag of Tricks</a></li>
    <li><a>Bead of Force</a></li>
    <li><a>Belt of Dwarvenkind</a></li>
    <li><a>Belt of Giant Strength</a></li>
    <li><a>Berserker Axe</a></li>
    <li><a>Boots of Elvenkind</a></li>
    <li><a>Boots of Levitation</a></li>
    <li><a>Boots of Speed</a></li>
    <li><a>Boots of Striding and Springing</a></li>
    <li><a>Boots of the Winterlands</a></li>
    <li><a>Bowl of Commanding Water Elementals</a></li>
    <li><a>Bracers of Archery</a></li>
    <li><a>Bracers of Defense</a></li>
    <li><a>Brazier of Commanding Fire Elementals</a></li>
    <li><a>Brooch of Shielding</a></li>
    <li><a>Broom of Flying</a></li>
  </ul>
</div>

Is this possible using those methods or should I try something else? The reason I want like this is because I am fetching the data and I want to put them in its individual <ul> according to the first letter of the item name. I also apologize for the long Question text, but I wanted to give details as possible as I can. If it is not the right way to do it, please let me know and I would not do it again, since I am new at stackoverflow community. Thanks for the help and understanding.

CodePudding user response:

You are cloning the entire ul (unordered list) for each item and appending them to the magic-area.

Consider not using the <ul> you created. But create an ul for each iteration of items starting with A and B.

const ulMagicItemsA = document.createElement("ul");

Now iterate all the items starting with A. Create a list item <li> for each of them. Create an anchor a and set the inner HTML to the name of the item. Append the ancher to to list item and append the list item to the newly create list ulMagicItemsA.

  const li = document.createElement("li");
  const a = document.createElement("a");
  a.innerHTML = item.name;
  li.append(a);
  ulMagicItemsA.append(li);

Finally append ulMagicItemsA to your magic-area.

Here's how that would work:

function loadMagicItems() {
    fetch('https://api.open5e.com/magicitems/?fields=slug,name,desc,type,rarity&limit=1000'
    ).then(function (responses) {
        return responses.json();
    }).then(function (data) {
        displayMagicItems(data.results);
    });
};

function displayMagicItems(items) {
    const magicArea = document.querySelector(".magic-area");
    const magicItemA = items.filter((item) => item.name.startsWith("A"));
    const magicItemB = items.filter((item) => item.name.startsWith("B"));
    
    const ulMagicItemsA = document.createElement("ul");
    ulMagicItemsA.classList.add("magic-list");
    magicItemA.map((item) => {
      const li = document.createElement("li");
      const a = document.createElement("a");
      a.innerHTML = item.name;
      li.append(a);
      ulMagicItemsA.append(li);
    });
    magicArea.append(ulMagicItemsA);
    
    const ulMagicItemsB = document.createElement("ul");
    ulMagicItemsB.classList.add("magic-list");
    magicItemB.map((item) => {
      const li = document.createElement("li");
      const a = document.createElement("a");
      a.innerHTML = item.name;
      li.append(a);
      ulMagicItemsB.append(li);
    });
    magicArea.append(ulMagicItemsB);
}
  <body onload="loadMagicItems()">
    <div class="magic-area"></div>
  </body>

CodePudding user response:

you are appending each item to same node and writing if case for each letter is repeating of code. Check below code where we can do things dynamically without hardcoding for each letter.

function loadMagicItems() {
    fetch('https://api.open5e.com/magicitems/?fields=slug,name,desc,type,rarity&limit=1000'
    ).then(function (responses) {
        return responses.json();
    }).then(function (data) {
        displayMagicItems(data.results);
    });
};

function displayMagicItems(items) {
    items.map((item) => {
        const itemName = item.name;
        //check for ul node with id first letter of list item
        let node = document.getElementById(`magic-ul-${itemName[0]}`)
        if (!node) {
           //if node is node there create new node and append it to main div
           node = document.createElement('ul');
           node.id=`magic-ul-${itemName[0]}`;
           document.querySelector('.magic-area').append(node);
        }
        const magicItem = document.querySelector("li").cloneNode(true);
        magicItem.querySelector("a").innerHTML = itemName;
        node.append(magicItem);
    })
}
<body onload="loadMagicItems()">
    <li><a></a></li>
    <ul class="magic-list"></ul>
    <div class="magic-area"></div>
  </body>

  • Related