Skip to content

Lab 7: Fetch, Map, Filter

Due: Monday, Mar 31st

In this lab, you will use JavaScript array functions (forEach(), map(), and filter()) to search within an array of movie data entries. You should consult the following references as needed:

Starter Code

Download the following files to get started:

You will modify and submit only the funs.js file. You are encouraged to examine the data.json file to develop an understanding of the structure of the data.

Step 1: Initialization function

Your first step is to populate an unordered list based on an array of objects. The data.json file contains an array of movie objects based on real data retrieved from IMDb. Each entry in this array is an object that contains the following information:

Attribute Description
id A unique identifier for the movie
title The name of the movie
subtitle (optional) The movie's subtitle
series (optional) The name of the movie's series
rating The IMDb rating based on user votes (range from 0 to 10)
runtime The runtime of the movie as measured in minutes
year The year the movie was released

Note that the title, subtitle, and series fields are nested within a name field. That is, while you can access movie.id directly, you would need to access movie.name.title. Similarly, the rating, runtime, and year fields are contained within a data field.

Your first task is to define the setTitleContent() function that modifies a movie object by copying the movie's title into a new field called titleContent. (Later functions will modify this new field further.) Note that this function will be used within a call to map(), so it will need to return the modified movie object.

Once you've got setTitleContent() working, you will create a self-executing initialization function where indicated. Some parts of this code are provided for convenience. Your main task here is to use fetch() to retrieve the data from data.json.

Once you've retrieved the data and parsed it as JSON, you will use map() (on setTitleContent()) and forEach() (using buildItem()) to build an HTML list dynamically. Note that buildItem() relies on the movie's titleContent field that you add in setTitleContent().

Do NOT use any form of loop (such as a for-each loop) for this lab. The purpose is to work with the array functions only.

Finally, for all steps, update the 'target-label' element to append "N movies" to its textContent, where N is the number of movies in the list.

The original data set has over 100 movies in it. For this stage, you will just use the first 10 records. Your generated list should look like the one in this screenshot.

In the provided source code, there are hard-coded hostname and url variables that your call to fetch() will use. Note that your code will not actually access the data.json file you retrieved. CORS (a security mechanism we will discuss later) prevents using fetch() with a local file, so it must retrieve the data from a web server over HTTP.

Step 2: Chaining map calls

Your next task is to implement three more functions to append the year, runtime, and rating values to the movie's titleContent field. Extend your initialization function so that these functions are chained together using a sequence of map() calls.

A completed version of this step will produce output such as that shown in this screenshot. Note that the only observable difference here is the additional fields in the list item.

Step 3: Queries and filters

Your final task is to implement a group of functions for setting minimum or maximum criteria to filter the data set based on particular values. You'll start by implementing setMinRating() and the related functions. These functions will return a closure that will return a Boolean value (true or false) based on whether a movie would satisfy the condition.

As an example, consider the following code:

let f = setMinRating(8.0);
You can then use f as a function that determines if a movie has at least a minimum rating of 8.0. For instance, calling f(godfather) would return true, assuming godfather refers to the movie object for "The Godfather". On the other hand, calling f(legend) would return false for "I Am Legend". Once you've completed the setMinRating() function, you cam complete the others that serve similar purposes for year and runtime.

First, note that you need to use parseInt() and parseFloat() on the fields that you get from the movie objects. These fields are originally strings, so you cannot do a basic > or < comparisons. Also make sure that you are returning these comparisons as closures (i.e., return an arrow function) rather than trying to return true or false itself.

Finally, amend your initialization function to filter results. If the query string is empty (i.e., query is undefined), then you should continue to display the first 10 movies. However, if there is a query, you'll need to get the appropriate minimum or maximum values. For simplicity, the provided code splits the query string into an array of criteria, such as minrating=8.2.

The navigation menu at the top of the page contains some embedded query strings for testing purposes. Your results should match those shown in the following screenshots:

Optional: One more step

All of the above examples followed the flow of using a series of calls to filter() followed by a series of calls to map() (or vice versa…either works). But what if you only wanted to make a call to map() if you were doing a certain filter() but not otherwise? That kind of logic doesn't easily lend itself to just chaining functions together.

As a specific example, the last link in the <nav> bar selects the movies with the highest ratings, but only if they are part of a series. If the movie fits into this criterion, append the series title to the titleContent. The challenge, though, is that you only want to do this if you are selecting this category. If you are clicking on the "High Rating" link, you don't want to append the text.

As an optional last step, integrate this criterion. If the query string includes inseries=true, show only the filtered results that are part of a series (i.e., movie.name.series is defined). The complete list should look like this screenshot.

Submission

When you are finished, submit funs.js to Gradescope. Note this lab will be manually graded.