JSON

To use our dataset (our poem) more efficiently, we'll use JSON. JSON stands for JavaScript Object Notation. We can use a JSON object (as a separate file) to store our poem data, and then use that data to populate our poem.

JSON, as a data format, allows us to store data in a structured way and utilize it in a variety of ways in JavaScript. Like object syntax you have seen so far, JSON object data is written in key/value pairs. For instance, here's a object containing details about an example person named Sal Ami in JSON:

{
   "firstName": "Sal",
   "lastName": "Ami",
   "age": 30,
   "streetAddress": "404 JavaScript Dr",
   "city": "JavaTown",
   "state": "JA",
   "postalCode": "12345",
   "phoneNumbers": [
      { "Mobile": "111-111-1111" },
      { "Home": "222-222-2222" }
   ]
}

As you can see, we store data in key/value pairs as usual, and we can use both object and array syntax.

Using JSON, we can store our poem in a file called poem.json. As you might imagine, writing it all out is a bit of a pain, so luckily for you I've already done it. Download the poem.json file from the button below and save it to your working folder.


If you open the file in VSCode, you can see that we have stored the lines of the text in a similar fashion as we did before, with a text property for each word of the poem. I also went ahead and added a few extra literary devices for the first half of the poem and listed them as info.

In general, just keep in mind that:

  1. JSON objects are very much like JavaScript objects.
  2. JSON objects are written in key/value pairs.
  3. JSON objects are surrounded by curly braces { }.
  4. Keys must be strings, and values must be a valid JSON data type (string, number, object, array, boolean or null).
  5. Keys and values are separated by a colon.
  6. Each key/value pair is separated by a comma.
  7. Arrays are enclosed in square brackets [ ] and each element is separated by a comma.

Now that we have a full JSON file with our poem, let's use it to populate our page with the text. We'll need to revamp our code one more time to accomplish this.

To clearly observe the logic of what we have so far, let's take a look at the 3 different parts to our program:

//Part 1 - Define the extra information section for the poem
$("#info").html("<p>Extra info will go here.</p>");

// Part 2 - Display the first line of the poem and access info from the poem object if it exists
let line1, line1Text;
line1 = [{text:  "What", info: "Anaphora: The repetition of a word or phrase at the beginning of (usually successive) lines. For example, the use of What in the first four lines."}, 
    {text: "hurrying"}, {text: "human"}, {text: "tides,"}, 
    {text: "or"}, {text: "day"}, {text: "or"}, {text: "night!"}];
line1Text = "<blockquote><p>"; 
line1.map(function(word){
  let wordString;
  wordString = word.text;
  if (word.info){
    wordString = "<a href='#' data-info='"+ word.info + "'>" + wordString + "</a>";
  }
  line1Text = line1Text + wordString + " ";
});
line1Text = line1Text + "</p></blockquote>";

$("#poem").html(line1Text);

// Part 3 - Add the click event to the poem
$("#poem a").click(function(){
    let infoText, clickedWord, clickedInfo;
    clickedWord = $( this ).text();
    clickedInfo = $( this ).data("info");
    infoText = clickedInfo;
    $("#info").html(infoText);
  });

I have deleted all the earlier comments, so just look at the three new ones I've added here. We can see that we have 3 parts to our program:

  • Part 1 - Define the extra information section for the poem
  • Part 2 - Display the first line of the poem and access info from the poem object if it exists
  • Part 3 - Add the click event to the poem

It is clear that we'll need to revamp part 2 to display the full data from the JSON file instead of just the first line we manually inputted. Let's do just that. We'll use the getJSON method to retrieve the data from the JSON file. We'll also create a new variable that will store all the text of the poem garnered from the JSON file.

//Part 1 - Define the extra information section for the poem
$("#info").html("<p>Extra info will go here.</p>");

// Part 2 - Display the first line of the poem and access info from the poem object if it exists
$.getJSON("poem.json", function(data){ // data variable is the JSON object
  let poemText; // Define a new variable to hold all text
  poemText = "<blockquote><p>"; // Open the starting tags
  // Now you can iterate (map) over the data variable’s .lines property:
  data.lines.map(function(line){ // We get a variable, line
    // Define a blank lineText.
    let lineText = "";
    // Now iterate over each word. This part should be familiar to you from before
    line.map(function(word){
      let wordString;
      wordString = word.text;
      if (word.info){
        wordString = "<a href='#' data-info='" + word.info + "'>" + wordString + "</a>";
      }
      lineText = lineText + wordString + " "; // Add the word to the lineText variable with spacing
    });
    // Add lineText with a line break to the poemText
    poemText = poemText + lineText + "<br/>";
  });
  // Close the poemText tags
  poemText = poemText + "</p></blockquote>";
  // Replace the content of #poem
  $("#poem").html(poemText);
  // Now that we have the data, we can add the click event to the poem
  $("#poem a").click(function(){
    let infoText, clickedWord, clickedInfo;
    clickedWord = $( this ).text();
    // .data("info") looks for the data-info HTML attribute
    clickedInfo = $( this ).data("info");
    infoText = clickedInfo;
    $("#info").html(infoText);
  });
}); // Close the getJSON method and callback function

There is some new syntax and logic here, so try to follow along with the comments. We're first using a selector and the getJSON() method to retrieve the data from the JSON file. getJSON() takes two arguments: the source of the JSON file, and what's called a callback function. Callback functions are functions that are passed in as arguments to other functions. In this case, we're passing in a function that takes one argument, which is the data from the JSON file.

In other words, the essential moves of the code are as follows:

  • Run the getJSON() method, passing in the poem.json file as the source.
  • Call the callback function, passing in the data variable (the JSON object).
  • Create a new variable to hold all the text of the poem.
  • map() over the data variable's lines property.
  • map() over each word in each line.
  • Make elements clickable if they have info data.
  • Add each line to the poemText variable with a line break, and add the text to the #poem element.
  • Run the click() method on the #poem element, to see if the user clicks on a word.

All together, your program should now look something like this:

//Part 1 - Define the extra information section for the poem
$("#info").html("<p>Extra info will go here.</p>");

// Part 2 - Display the poem and allow for clicking on words
$.getJSON("poem.json", function(data){ // data variable is the JSON object
  let poemText; // Define a new variable to hold all text
  poemText = "<blockquote><p>"; // Open the starting tags
  // Now you can iterate (map) over the data variable’s .lines property:
  data.lines.map(function(line){ // We get a variable, line
    // Define a blank lineText.
    let lineText = "";
    // Now iterate over each line. This part should be familiar to you from before
    line.map(function(word){
      let wordString;
      wordString = word.text;
      if (word.info){
        wordString = "<a href='#' data-info='" + word.info + "'>" + wordString + "</a>";
      }
      lineText = lineText + wordString + " "; // Add the word to the lineText variable with spacing
    });
    // Add lineText with a line break to the poemText
    poemText = poemText + lineText + "<br/>";
  });
  // Close the poemText tags
  poemText = poemText + "</p></blockquote>";
  // Replace the content of #poem
  $("#poem").html(poemText);
  // Now that we have the data, we can add the click event to the poem
  $("#poem a").click(function(){
    let infoText, clickedWord, clickedInfo;
    clickedWord = $( this ).text();
    // .data("info") looks for the data-info HTML attribute
    clickedInfo = $( this ).data("info");
    infoText = clickedInfo;
    $("#info").html(infoText);
  });
}); // Close the getJSON method and callback function

Save and check the page. You should now see the full poem and have a few clickable elements to explore.

Congrats! You now have a workable dataset and some interesting ways to display and interact with it. We've covered quite a lot of new terrain in this lesson, but for the most part, we are still just utilizing the foundational skills and tools you've encountered so far.

In the next lesson, we'll introduce a brand new tool called Leaflet. We'll learn how to use Leaflet to add interactive maps to our web pages.

But, as major takeaways from this lesson, just keep in mind that:

  • We usually want to break down data into smaller, discrete pieces we can manipulate
  • JSON allows you to store data in a structured way and work with it
  • Data attributes are used to store extra information that you may want to access or display
  • Events are used to trigger actions when something happens

Review Questions

  1. True or False - map() allows you to iterate over an array, but it doesn't return anything.
Quiz

  1. True or False - We can import a JSON dataset as an object in JavaScript.
Quiz

  1. The following code would affect which element?
$("#poem h3").click(function(){
    // some action
});
Quiz

Challenges

  1. Our poem page is quite bland. Spruce it up however you'd like by marshalling your CSS skills.

  2. .map() is an important method. Get a little practice in by writing a new function that takes an array of integers and, using .map(), returns an array of those integers, doubled. So if we give it [1, 2, 3], we receive, in turn, [2, 4, 6]. Display this info in the console.

  1. .map() is similar to another method, .forEach(). We haven't covered the latter, but you may encounter it in the wild. Read through this article to understand the differences between the two, and to learn a little more about .map() specifically.

  2. Add a new property to the JSON file that stores a wiki link for a particular literary device (e.g., here for anaphora. Create a new data attribute to access this property and add it to the info message that is displayed when clicked.

Key Terms

Do you recall the meaning of the following terms?

  • .map()
  • .join()
  • .getJSON()
  • data attributes
  • events
  • callbacks

Download the Project

Here are the course files we created for this lesson if you need a reference: