Day 16: DOM Manipulation
Lesson 3: Creating DOM Elements
Getting DOM elements and deleting them is one thing, but creating them is obviously the thing we really want to be able to do. Let's start with an empty list and then have JavaScript add some items to it shall we?
This is a multi step process. We will
- Get an element in the DOM to add new child nodes to - in this case a
<ul>
- Create a new node to hold some text - in this case a list item
<li>
- Add some text to the list item
- Add the list item to the list so it appears on screen
1<ul id="todos"></ul>
And then your JavaScript.
1const todos = document.getElementById("todos"); 2 3const listItem = document.createElement("li"); 4const content = document.createTextNode("Clean kitchen"); 5 6listItem.appendChild(content); 7 8todos.appendChild(listItem);
Save that and there you have it, we added an item to a list with JavaScript.
Let's take this one step further:
1const todoList = ["Clean kitchen", "Walk dog", "Watch TV", "Plan next project"]; 2 3const todos = document.getElementById("todos"); 4 5todoList.forEach((todoItem) => { 6 const listItem = document.createElement("li"); 7 const content = document.createTextNode(todoItem); 8 listItem.appendChild(content); 9 todos.appendChild(listItem); 10});
This is the same as we did above but instead we took an array, iterated over it, created an <li>
added the text from the item in the array and appended it to the <ul>
.
Let's take this one step further and combine a few topics in one. Let's fetch some data from somewhere and add it to the page.
Change your JavaScript to this.
1fetch("https://pokeapi.co/api/v2/pokemon/") 2 .then((pokemonResponse) => pokemonResponse.json()) 3 .then((pokemonData) => { 4 console.log(pokemonData); 5 6 const pokemonArray = pokemonData.results; 7 8 const pokemonList = document.getElementById("pokemon"); 9 10 pokemonArray.forEach((pokemon) => { 11 const listItem = document.createElement("li"); 12 const content = document.createTextNode(pokemon.name); 13 listItem.appendChild(content); 14 pokemonList.appendChild(listItem); 15 }); 16 });
There's nothing new here, just a remix of concepts you've already learned.
We use fetch()
to get some data from the PokeAPI, we then have to unwrap the returned promise with the first .then()
then unwrap the data with the call the .json()
so we can access the data in the second .then()
.
Then we have a big object that you can see in your console that has an array of Pokemon on the results property.
We then iterate over that array in results, creating list items and Pokemon names from the individual Pokemon object (pokemon.name
) as we go.
Pretty cool right?!
Async/Await
If you prefer to use the async/await syntax here then you can, however you need to make a modification to get await to work at the top level. The simple, modern way is to change your <script>
to be <script type="module">
and then this code will work:
1const pokemonResponse = await fetch("https://pokeapi.co/api/v2/pokemon/"); 2const pokemonData = await pokemonResponse.json(); 3console.log(pokemonData); 4 5const pokemonArray = pokemonData.results; 6 7const pokemonList = document.getElementById("pokemon"); 8 9pokemonArray.forEach((pokemon) => { 10 const listItem = document.createElement("li"); 11 const content = document.createTextNode(pokemon.name); 12 listItem.appendChild(content); 13 pokemonList.appendChild(listItem); 14});
The older way to make this work is with an IIFE (Immediately Invoked Function Expression) function like this.
1(async () => { 2 const pokemonResponse = await fetch("https://pokeapi.co/api/v2/pokemon/"); 3 const pokemonData = await pokemonResponse.json(); 4 console.log(pokemonData); 5 6 const pokemonArray = pokemonData.results; 7 8 const pokemonList = document.getElementById("pokemon"); 9 10 pokemonArray.forEach((pokemon) => { 11 const listItem = document.createElement("li"); 12 const content = document.createTextNode(pokemon.name); 13 listItem.appendChild(content); 14 pokemonList.appendChild(listItem); 15 }); 16})();
It looks horrible but it's really quite simple.
Without type="module"
we have await
at the top, we need it to be in a function market with async
. So let's create a function:
1() => {};
Mark it with async
1async () => {};
and then invoke it (call it)
1(async () => {})();
That last bit is usually where the confusion comes in.
If I rewrote it as this:
1const run = async () => {}; 2 3run();
It should be clearer. Like this:
1const run = async () => { 2 const pokemonResponse = await fetch("https://pokeapi.co/api/v2/pokemon/"); 3 const pokemonData = await pokemonResponse.json(); 4 console.log(pokemonData); 5 6 const pokemonArray = pokemonData.results; 7 8 const pokemonList = document.getElementById("pokemon"); 9 10 pokemonArray.forEach((pokemon) => { 11 const listItem = document.createElement("li"); 12 const content = document.createTextNode(pokemon.name); 13 listItem.appendChild(content); 14 pokemonList.appendChild(listItem); 15 }); 16}; 17 18run();
We don't need to await
run()
because it doesn't return anything.