tutorials.21-lessons.com

Week 8 - How to render Data from JavaScript

Now that we have a weather widget with static data let's talk about the next step. Ultimately, we want to fetch data from a remote source and render it into our widget. Before that, though, we need to discuss how to set up our code. Create a new script.js file to host all our application logic.

Also, let's include jQuery to help us render actual HTML Elements.

<!DOCTYPE html>
<html>

<head>
  <title>Weather Widget</title>
  <link rel="stylesheet" href="style.css" />
  <!-- add this line -->
  <script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
  <script src="/script.js"></script>
</head>

<body>
  <div class="weather-widget">
    <div class="headline">
    </div>
    <ul class="forecast">
    </ul>
  </div>
</body>

</html>

Now we're ready to get started. You notice, compared to last week, we're now using the same HTML template, except it's stripped of all actual weather values. Also, we're adding the class forecast to the <ul> element that'll hold all forecasted values. Let's add some code to fill in the blanks. Open script.js and add the following:

//script.js

$(document).ready(function() {
  var currentLocation = "Boston";
  var currentTempF = 55;
  var forecastTemperatures = [{
      time: "05:00pm",
      tempF: 54,
    },
    {
      time: "06:00pm",
      tempF: 50,
    },
    {
      time: "07:00pm",
      tempF: 45,
    },
  ];
})

These variables hold the data we want to render into our widget. We're using variables here to keep data and view logic separate. View logic describes code that's responsible for generating HTML.

Excursion: Objects

In the above code example, did you notice the curly braces?

var forecastTemperatures = [{
    time: '05:00pm',
    tempF: 54
  },
  {
    time: '06:00pm',
    tempF: 50
  },
  {
    time: "07:00pm",
    tempF: 45
  }
]

First, we declare a variable forecastTemperatures, whose data type is Array (indicated by the brackets). So far, we have only dealt with primitive data types (string, number, boolean). In many use cases, using primitive data types is more than enough. Yet, we are encountering a situation that requires more. Our problem: We need to store the forecasted temperatures for the next few hours. We could start with a list holding all forecast numbers:

var forecastTemperatures = [
  55,
  50,
  45
]

This approach would get the job done partially. While we have temperature data, we're missing crucial information, such as the time of day. We could use a second list:

vart forecastTemperatureTimes = [
  '05:00 pm',
  '06:00 pm',
  '07:00 pm'
]

Now we'd have all the necessary data, and we could look in both lists to correlate temperatures with their appropriate timestamps. It's feasible but not very user-friendly (from a developer's point of view). Also, imagine if we wanted to add more data, such as anticipated precipitation or UV Index. We'd have to add more lists, which, in turn, would complicate our code. Since it's an everyday use case, JavaScript (and many other languages) offer a dedicated data type to solve this issue. Instead of adding many separate lists, we are using an Object. An Object is a complex data structure. Instead of saving a primitive value, we can construct a data structure that holds all necessary data points. The syntax for an object looks like this:

{
  key: "value"
}

Curly braces always denote an object. Inside the curly braces, we see the object's attributes or properties (both mean the same thing). A property consists of a key and a value. The value can have any data type:

  • String
  • Number
  • Boolean
  • List
  • Object
  • Function

We'll work with objects in a second.

Rendering Data

Let's start with rendering the location and current temperature. Open script.js and add the following:

//script.js

$(document).ready(function() {
  var currentLocation = "Boston";
  var currentTempF = 55;
  var forecastTemperatures = [{
      time: "05:00 pm",
      tempF: 54,
    },
    {
      time: "06:00 pm",
      tempF: 50,
    },
    {
      time: "07:00 pm",
      tempF: 45,
    },
  ];
  //add the following two lines
  $('.headline').append($(`<h1>${currentLocation}</h1>`));
  $('.headline').append($(`<h2>${currentTempF} F</h2>`));
});

String interpolation

We're using jQuery to add HTML elements to our template. $(.headline) selects the <div> container where we'd like to insert our data. .append allows us to add a new HTML element to the selected <div>. Let's look a bit closer at the value we provide to .append:

$(`<h1>${currentLocation}</h1>`)

`` We know we can use the $ function to create a new HTML element, usually looking like this:

$("<h1>Hi There</h1>")

So, why does our code use a different syntax? We generate a headline with static text in the example with double quotes. We'd get five identical results if we ran that code five times. Instead, we want to create a headline element with dynamic text (using the value we stored in our currentLocation variable). Therefore, we want to use a JavaScript mechanism to "patch in" the value from our variable. This is called string interpolation.

The syntax looks like this:

var value = 'Dynamic';
var interpolated = `Static Part | ${value} Part`;
console.log(interpolated); // "Static Part | Dynamic Part"

Instead of single or double quotes, we're using backticks to denote a string. At the place where we need to insert a dynamic value, we use ${value} to patch in our variable's value.

Loops and accessing Objects

With the first two values rendered, we now focus on rendering a list of forecasts:

//script.js

$(document).ready(function() {
  var currentLocation = "Boston";
  var currentTempF = 55;
  var forecastTemperatures = [{
      time: "05:00pm",
      tempF: 54,
    },
    {
      time: "06:00pm",
      tempF: 50,
    },
    {
      time: "07:00pm",
      tempF: 45,
    },
  ];
  $('.headline').append($(`<h1>${currentLocation}</h1>`));
  $('.headline').append($(`<h2>${currentTempF} F</h2>`));

  //add the following lines

  for (var i = 0; i < forecastTemperatures.length; i++) {
    var currentTemperature = forecastTemperatures[i]; //(1)
    var row = $('<li>'); // (2)
    row.append($(`<h2>${currentTemperature.tempF}</h2>`)); //(3)
    row.append($(`<h2>${currentTemperature.time}</h2>`)); //(4)
    $('.forecast').append(row); //(5)
  }
});

Rendering forecast data consists of a bunch of steps. We're starting with a for loop, iterating over the list of forecasts (forecastTemperatures). As a first step, we retrieve an object from our list: var currentTemperature = forecastTemperatures[i];. [i] is the so-called Index Operator. It allows us to fetch an element from a list at a specific location. Since forecastTemperatures contains objects, how do we work with an object? currentTemperature holds a reference to an element from the list. We know each object has two properties: tempF and time. To access these properties, we use the following notation:

currentTemperature.tempF
currentTemperature.time

For each element we retrieve from the list (1), we create a new row (2). This <li> element will hold both the temperature (3) and time (4). We append the new row to our <ul> (5). While this approach might seem like much work to render three values into a list, it will pay off once we start to fetch data from a remote data source because a for loop does not care how many elements we have in our list. It'll loop over five elements as well as a hundred.