Skip to content

JavaScript Review

In this class we will explore the first two language review demos in your workbook:


We begin be reviewing the HTML for a simple web page. The relevant portions are highlighted below.

index.html
<div class="container">
<h1 class="text-center">What did you do over break?</h1>
<form class="new-topic-form">
<div class="mb-3">
<label for="new-topic-input" class="form-label">Topic</label>
<input type="text" name="new-topic" class="form-control" id="new-topic-input">
<div class="invalid-feedback">
Please enter a valid topic
</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<h5 class="pt-3">Topics</h5>
<ul class="topics-list list-group">
</ul>
</div>

The JavaScript file is empty, save for a comment about the format for each list item’s content to be added to the unordered list each time the form is submitted.

js/index.js
/*
Enter JS here
HTML for list topic list item
<li class="list-group-item">
NEW TOPIC HERE
</li>
*/

The goal is simple: Create an event handler that will respond to form submit events and add list items to the un-ordered list.

We’re going to need a web server for our project. We’ll accomplish this by turning these simple files from our starter kit into an actual Node project, using Parcel as the build and development server.

  1. Create a Node project by running npm init -y in the terminal. (Be sure your terminal path is at the root of this starter kit.) You should have the following as your contents in the folder.

    • Directory~ Folder holding the starter kit files
      • Directoryjs
        • index.js
      • index.html
      • package.json
      • README.md
  2. We’ll add in parcel to the project by running npm install parcel in the terminal.

  3. Update the package.json to include the following changes.

    package.json
    "source": "index.html",
    "scripts": {
    "start": "parcel",
    "build": "parcel build"
    },
  4. Run the project by typing npm run start or npm start in the terminal. The web page should load correctly.

Now we can add in the functionality of the website. We’ll create an event listener function for the form’s "submit" event and hook it up to the form.

  1. Create the following function in your index.js file.

    index.js
    const handleSubmit = function(evt) {
    // client-side only
    evt.preventDefault(); // stop the POST to the webserver
    const targetForm = evt.target;
    const textInput = targetForm.elements['new-topic'];
    if(textInput.value.trim() !== '') {
    // Good, I have text... 🚀
    const list = document.querySelector('ul');
    list.innerHTML += `<li>${textInput.value.trim()}</li>`;
    textInput.value = ''; // clear the input
    textInput.classList.remove('is-invalid');
    } else {
    // Bad input 😢
    textInput.classList.add('is-invalid');
    }
    textInput.focus();
    }
  2. Add it to the form element so that it responds to the “submit” event.

    index.js
    const myForm = document.querySelector('form');
    myForm.addEventListener('submit', handleSubmit);

When we test it out, we should be able to add items to the unordered list through the form.

Through this simple example, we’ve recalled several JavaScript basics. In the end, you were able to

  • Create a Node-based project that uses Parcel
  • Use the DOM API to select elements from the page
  • Create and assign a function to acts as an event handler for an element on the page

Take this review a step farther. Define a function that will use the document.createElement() and document.createTextNode() DOM API to build and then return the following list item as a document fragment. Then, replace the existing template string with this function call and append the list item to the unordered list using its .appendChild() function.

<li class="list-group-item">
NEW TOPIC HERE
</li>

Data is a core aspect of any and all websites, whether that data is simple hard-coded content (text, images, etc.) or information that is pulled from some API. In this demo, we explore The Space Devs public API to retrieve information about astronauts. Specifically, we’ll be using the Launch Library API 2. The starter kit’s README.md file contains a brief outline of the steps to follow.

The instructions in the starter kit guided us to set up our Node project with the starter files (npm init) and then add a couple of third-party libraries (npm install boostrap and npm install parcel --save-dev). After a couple of small tweaks to package.json (see below), we’re ready to run the site using npm start in the terminal.

package.json
{
"name": "review-astronauts-example-START",
"version": "1.0.0",
"description": "In this example we're going to see past and present astronauts.",
"main": "index.js",
"source": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"start": "parcel"
},
"keywords": [],
"author": "",
"license": "ISC"
}

The ReadMe for this project had us jump into exploring the API we’re going to use. Before we do that, however, let’s make use of Bootstrap in our site by importing it in our JavaScript entry point (js/index.js).

js/index.js
import 'bootstrap/dist/css/bootstrap.min.css';

When deciding how to organize our JavaScript logic, a good principle to follow is separation of concerns. As such, we’re using JavaScript Modules and we’re organizing our code in a way that separates API calls from the code that renders to the DOM.

  • Directory~ Starter kit folder
    • Directoryjs
      • Directoryapi The layer that gets JSON data
        • astronaut.js
      • Directorydom The layer that renders to the DOM
        • astronaut.js
      • index.js The “main” entry point of our app
    • index.html
    • README.md

There are a few ways we can make our API calls. The key thing to know is that our fetch() function returns a Promise<Response>. We’ll keep it simple for now, and just ensure we return a list of the astronauts as a JavaScript object (meaning that we need to convert it from the JSON string returned by the API endpoint).

js/api/astronaut.js
const BASE_URL = "https://lldev.thespacedevs.com/2.2.0"
// api functions here.
const getAstronautList = function() {
return fetch(BASE_URL + '/astronaut/')
.then(response => response.json());
}
export { getAstronautList }

To make our code available to other scripts, we need to export our function. In the main index.js of our app, we can import it and just dump out the data to the console (to make sure our API call is working).

js/index.js
// js here.
import 'bootstrap/dist/css/bootstrap.min.css';
import { getAstronautList } from './api/astronaut';
getAstronautList().then(data => {
console.log(data);
});

Besides ensuring that we are getting data back from The Space Devs, this gives us the opportunity to examine what structure or shape the data has. We’ll need to know this when it comes to the DOM Rendering step.

The target for the astronaut data is the <ul> tag. Similar to the last demo, there is only one unordered list on the page.

index.html
<div class="container">
<h1 class="text-center">Past and Present Astronauts</h1>
<ul class="astronaut-list list-group">
</ul>
</div>

As far as our rendering needs are concerned, all we need is the data about each individual astronaut and a reference to the <ul> for displaying the content. Let’s build a shell of the function and ensure it is exported from our module.

js/dom/astronaut.js
const renderAstronautListItem = function(astronautData, listElement) {
// TODO: complete this function stub
}
export { renderAstronautListItem }

When we have an object as our parameter (astronautData) and we need to get several pieces of data from that object (in this case, to fill in placeholders in our template string), an excellent approach is to use destructuring. For example, our astronaut data has a huge set of properties, but we are interested in only a few. With destructuring syntax, we can declare variables for the information we want displayed.

js/dom/astronaut.js
const renderAstronautListItem = function(astronautData, listElement) {
// Get the properties via destructuring the object
const { name, bio } = astronautData;
}

With that in place, we can build our HTML template string with some basic content. We’ll start with the name and bio, just to see if it’s rendering correctly. We’ll append the list item to the listElement reference.

js/dom/astronaut.js
const renderAstronautListItem = function(astronautData, listElement) {
// Get the properties via destructuring the object
const { name, bio } = astronautData;
const listItem = `<li>${name}<br />${bio}</li>`;
listElement.innerHTML += listItem;
}
export { renderAstronautListItem }

Returning to the entry point of our app, the next step is to call renderAstronautListItem with the data from the API call.

js/index.js
// js here.
import 'bootstrap/dist/css/bootstrap.min.css';
import { getAstronautList } from './api/astronaut';
import { renderAstronautListItem } from './dom/astronaut';
getAstronautList().then(data => {
console.log(data);
// use the data.results array and render each astronaut
const listContainer = document.querySelector('ul');
data.results.forEach(person => {
renderAstronautListItem(person, listContainer);
});
});

Our preliminary results should show some basic data for each astronaut.

TODO: Screenshot here

To wrap things up, we can resume dropping all the astronaut data in our list item. I added a little extra for the status to indicate if the astronaut is currently on a space mission. Here is the final version of our renderAstronautListItem function.

js/dom/astronaut.js
const renderAstronautListItem = function(astronautData, listElement) {
// Get the properties via destructuring the object
const { name, agency, bio, status, date_of_birth, in_space, nationality, profile_image_thumbnail } = astronautData;
let statusDescription = status.name;
if(in_space) {
statusDescription += ' | Currently in Space'
}
const listItem = `<li href="#" class="list-group-item list-group-item-action">
<div class="d-flex w-100 justify-content-between">
<img src="${profile_image_thumbnail}" class="rounded float-start" alt="${name} thumbnail">
<h5 class="mb-1">${name} (${statusDescription})</h5>
<small class="float-end">born ${date_of_birth}</small>
</div>
<small>${nationality} (${agency.name})</small>
<p class="mb-1">${bio}</p>
</li>`;
listElement.innerHTML += listItem;
}
export { renderAstronautListItem }