Course catalog: many courses

The story so far

Records are stored in JS objects. You can make HTML to show what is in an object.

Showing a course list

Try the course catalog page. It starts off empty:

Start

When you click the button, you see a course list:

Output

Making some records

Let's break up the logic into two pieces:

  • Make a record set
  • Show the record set

A record set is a bunch of records, as if fetched from a database table. We're going to use JS objects for records.

This JS creates a record set when the page loads.

(function($) {
    //Initialize course catalog.
    var catalog = [
        {
            id: 42,
            title: "Web apps for happy dogs",
            maxEnrollment: 40,
            location: "Monty Hall 301"
        },
        {
            id: 155,
            title: "Databases for happy dogs",
            maxEnrollment: 32,
            location: "Monty Hall 301"
        },
        {
            id: 312,
            title: "Old rock bands",
            maxEnrollment: 90,
            location: "Tower of Power, 3822"
        },
        {
            id: 837,
            title: "Dogs in the ancient world",
            maxEnrollment: 70,
            location: "Rotunda of Doom"
        }
    ];
    ...

You can see the individual records. Each one is a JSON object.

This bit…

var catalog = [
    ...
];

Creates a JS array. You won't need to know much about arrays in this course, because we have some convenient JS functions for handling them.

So, we're using JS arrays to store record sets.

Pattern

Record set

Situation:
You want to store a bunch of records in JS. Each record has the same fields.
Actions:
Use a record set. Make a JS array. Each element is a JS object, with the same properties.

Showing the courses

Remember that the page has two tasks:

  • Make a recordset (when the page loads)
  • Show the recordset (when the user clicks a button)

Let's add some HTML to the page:

<div id="catalogContainer" class="hide-on-load"></div>

catalogContainer is a place to show the courses.

Adela
Adela
Oh! So we're not creating the HTML ahead of time. The JS is going to make the HTML in a variable, and inject it into the page.

Right! We have to do it that way, because the number of courses might change. Right now, there are four courses in catalog. Next week, there might be 16. In three months, 255.

We should write the code so that it works no matter how many courses there are. Fortunately, JS helps us with that.

Thinking through the logic

So, we have this container:

<div id="catalogContainer" class="hide-on-load"></div>

We want to make this display:

List output

Each course has its own <ul> tag. Inside the <ul>, each data field has its own <li>. So, to show the first course, our code should make this HTML:

<ul>
  <li>Title: Web apps for happy dogs</li>
  <li>Maximum enrollment: 40</li>
  <li>Location: Monty Hall 301</li>
</ul>

We make chunks of HTML like this for each course. Then we jam all the chunks together, and we have the HTML for the catalog.

Here's some pseudocode:

For each course:
  Make HTML for the course
  Add the course HTML to the catalog HTML
Show the catalog HTML

Here's the JS code:

CourseCatalog.showCatalog = function() {
    var catalogHtml = "";
    catalog.forEach(function(course){
        var courseHtml =
            "<ul>" +
            "  <li>Title: " + course.title + "</li>" +
            "  <li>Maximum enrollment: " + course.maxEnrollment + "</li>" +
            "  <li>Location: " + course.location + "</li>" +
            "</ul>";
        catalogHtml += courseHtml;
    });
    $("#catalogContainer")
        .html(catalogHtml)
        .show('slow');
};

The key variables are courseHtml and catalogHtml. We'll put the HTML for one course in courseHtml. Then we'll collect all the different values for courseHtml into catalogHtml.

Loopy

There's a new construct here:

catalog.forEach(function(course){
  //Do something with @course@.
}

This is a forEach loop. It runs across the array in catalog. Here's catalog again:

var catalog = [
    {
        id: 42,
        title: "Web apps for happy dogs",
        maxEnrollment: 40,
        location: "Monty Hall 301"
    },
    {
        id: 155,
        title: "Databases for happy dogs",
        maxEnrollment: 32,
        location: "Monty Hall 301"
    },
    {
        id: 312,
        title: "Old rock bands",
        maxEnrollment: 90,
        location: "Tower of Power, 3822"
    },
    {
        id: 837,
        title: "Dogs in the ancient world",
        maxEnrollment: 70,
        location: "Rotunda of Doom"
    }
];

The first time through this loop…

catalog.forEach(function(course){
  //Do something with @course@.
}

… JS will set course to be the first element of catalog, the course with an id of 42. Then it will run the code in the loop.

The second time through the loop, JS will set course to be the second element of catalog, the course with an id of 155. Then it will run the code in the loop.

And so on.

Inside the loop

What happens inside the loop?

catalog.forEach(function(course){
    var courseHtml =
        "<ul>" +
        "  <li>Title: " + course.title + "</li>" +
        "  <li>Maximum enrollment: " + course.maxEnrollment + "</li>" +
        "  <li>Location: " + course.location + "</li>" +
        "</ul>";
    catalogHtml += courseHtml;
});

The code in the loop builds HTML for a courses's <ul> tag, using whatever data is in course.

The last line of the loop adds that data to the current catalogHtml.

As the loop runs, catalogHtml will get longer and longer, as it accumulates the HTML for each course.

Georgina
Georgina
I just want to check something. Each time through the loop, we put some HTML in courseHtml, add it to the catalog variable, then throw courseHtml away, right?
Yes! The code inside the loop is in its own function.

  1. bc. catalog.forEach(function(course){  Start a function
  2.     var courseHtml = Make a local variable
  3.         "<ul>" +
  4.         "  <li>Title: " + course.title + "</li>" +
  5.         "  <li>Maximum enrollment: " + course.maxEnrollment + "</li>" +
  6.         "  <li>Location: " + course.location + "</li>" +
  7.         "</ul>";
  8.     catalogHtml += courseHtml; Use the local variable
  9.     Function ends, local variable courseHtml is destroyed.
  10. });
Georgina
Georgina
OK, so the first time through, courseHtml is made, used, and destroyed.

The second time through, courseHtml is made, used, and destroyed.

The third time through, courseHtml is made, used, and destroyed.

Right. courseHtml is a local variable. They're used a lot in JS.

After the loop

What happens when the loop is done?

For each course:
  Make HTML for the course
  Add the course HTML to the catalog HTML
Show the catalog HTML  UP TO HERE

Here's the code.

  1. var catalogHtml = "";
  2.     catalog.forEach(function(course){
  3.         var courseHtml =
  4.             "<ul>" +
  5.             "  <li>Title: " + course.title + "</li>" +
  6.             "  <li>Maximum enrollment: " + course.maxEnrollment + "</li>" +
  7.             "  <li>Location: " + course.location + "</li>" +
  8.             "</ul>";
  9.         catalogHtml += courseHtml;
  10.     });
  11.     $("#catalogContainer") Runs after the loop is done
  12.         .html(catalogHtml)
  13.         .show('slow');
  14. };
JS takes the value of catalogHtml, and injects it into the container catalogContainer. Then it shows catalogContainer, with an animated effect.

Making a table

We've been showing record sets using the <ul> tag:

Using lists

A list is OK for individual records, but the <table> tag is a better choice for record sets:

Table

Here's the new JS:

CourseCatalog.showCatalog = function() {
    var catalogHtml =
        "<table class='table'>" +
        "  <thead>" +
        "      <th>Title</th>" +
        "      <th>Max enroll</th>" +
        "      <th>Location</th>" +
        "  </thead>" +
        "  <tbody>";
    catalog.forEach(function(course){
        var courseRow =
            "<tr>" +
            "  <td>" + course.title + "</td>" +
            "  <td>" + course.maxEnrollment + "</td>" +
            "  <td>" + course.location + "</td>" +
            "</tr>";
        catalogHtml += courseRow;
    });
    catalogHtml += "</tbody></table>";
    $("#catalogContainer")
        .html(catalogHtml)
        .show('slow');
};

Tables have code to start and end the table:

  1. CourseCatalog.showCatalog = function() {
  2.     var catalogHtml =
  3.         "<table class='table'>" + Start the table
  4.         "  <thead>" +
  5.         "      <th>Title</th>" + Add column headings
  6.         "      <th>Max enroll</th>" +
  7.         "      <th>Location</th>" +
  8.         "  </thead>" +
  9.         "  <tbody>";
  10.     catalog.forEach(function(course){
  11.         var courseRow =
  12.             "<tr>" +
  13.             "  <td>" + course.title + "</td>" +
  14.             "  <td>" + course.maxEnrollment + "</td>" +
  15.             "  <td>" + course.location + "</td>" +
  16.             "</tr>";
  17.         catalogHtml += courseRow;
  18.     });
  19.     catalogHtml += "</tbody></table>"; End the table
  20.     $("#catalogContainer")
  21.         .html(catalogHtml)
  22.         .show('slow');
  23. };
The code to start and end the table runs once. The code in the loop runs for each course.

  1. CourseCatalog.showCatalog = function() {
  2.     var catalogHtml =
  3.         "<table class='table'>" +
  4.         "  <thead>" +
  5.         "      <th>Title</th>" +
  6.         "      <th>Max enroll</th>" +
  7.         "      <th>Location</th>" +
  8.         "  </thead>" +
  9.         "  <tbody>";
  10.     catalog.forEach(function(course){
  11.         var courseRow = Runs for each course
  12.             "<tr>" +
  13.             "  <td>" + course.title + "</td>" +
  14.             "  <td>" + course.maxEnrollment + "</td>" +
  15.             "  <td>" + course.location + "</td>" +
  16.             "</tr>";
  17.         catalogHtml += courseRow;
  18.     });
  19.     catalogHtml += "</tbody></table>";
  20.     $("#catalogContainer")
  21.         .html(catalogHtml)
  22.         .show('slow');
  23. };
Pattern

Show record set

Situation:
You have a record set. You want to show it to the user.
Actions:
Create HTML that uses the <table> tag. Use .forEach() to loop across the record set. Create HTML for each record. Accumulate the HTML.

Exercises

Exercise: Jokes
Make a page that shows some jokes, like this:

Result

Use different jokes, at least three.

Make sure the data shows when the page loads. There is no button to press.

Create and call a function called JokeCatalog.showJokes().

Use the record set pattern.

Use the show record set pattern, but with lists rather than tables.

Submit the URL of your page.

(If you were logged in as a student, you could submit an exercise solution, and get some feedback.)

Exercise: Countries
Make a table to show data from at least four countries from the CIA World Fact Book.

Sample output:

Output

Use different countries.

Make sure the data shows when the page loads. There is no button to press.

Create and call a function called Countries.showData().

Use the record set pattern.

Use the show record set pattern.

Submit the URL of your page.

(If you were logged in as a student, you could submit an exercise solution, and get some feedback.)

Summary

  • We make a JS object for each record.
  • A record set is a bunch of records. We store record sets in JS arrays.
  • .forEach(function(){...}) loops across an array. The code in the function runs once for each array element.
  • Use <table> tags to show record sets.