Objective:
To work with our βMoviesβ API (from Assignment 1) on the client-side to produce a rich user interface for accessing data.
Sample Solution:
You can see a video of the solution running at the following location:
https://pat-crawford-sdds.netlify.app/shared/winter-2023/web422/A2/A2.mp4
Specification:
For this assignment, we will create a single, searchable table that shows a subset of the movie data (ie: columns: Year, Title, Plot, Rating and Run Time). When the user clicks on a specific movie (row) in the table, they will be shown a modal window that shows the movie βposterβ (if available) as well as additional information such as the director, full plot, cast, awards and IMDB rating.
Β
The Solution Directory
The first step is to create a new directory for your solution, open it in Visual Studio Code and add following folders / files:
We will not be including any of the JavaScript / CSS libraries locally.Β Instead, we will be leveraging their CDN locations (See the Bootstrap Introduction notes for the <script> and <link> elements necessary).
NOTE: While the below instructions provide guidelines on how to use Bootstrap, you are not forced to use it if you prefer to use another UI / CSS framework.Β As long as your solution functions according to the below specification, it will still be accepted.
Β
Creating the Static HTML:
Next, we must create some Static HTML as a framework for the dynamic content.
Open your index.html file and add the minimum code required for an HTML5 page (HINT: type ! and then immediately type the tab key to get an HTML 5 skeleton).Β Once this is complete, include links for:
- The Bootstrap Minified CSS File (Using the CDN)
- Your css file (NOTE: This file will only consist of one selector (for now) to ensure that your βmoviesTableβ (or whatever you wish to call it) causes the cursor to change to a βpointerβ whenever a user moves their mouse over a row, ie:#moviesTable tr:hover{ cursor:pointer; }
Β
- The Bootstrap Minified JS File (Using the CDN)
- Your js file
With all of our libraries and files in place, we can concentrate on placing the static HTML content on the page.Β This includes the following:
Navbar
Assignment 2 will use an extremely simplified navbar.Β Begin by copying the full Default Navbar example HTML code from the official documentation: https://getbootstrap.com/docs/5.1/components/navbar and pasting it as the first element within the <body> of your file.
- Next, proceed to remove the <ul>β¦</ul> element from the <div> element with id: βnavbarSupportedContentβ
Β
- This should leave you with just the search form. To match the sample, make the following changes:
- Add the class βjustify-content-endβ to the <div> element with id: βnavbarSupportedContentβ
Β
- Give the form an βidβ value, ie: βsearchFormβ
Β
- Update the placeholder in the search field to read: βTitle (case sensitive)β and give it an βidβ value, ie: βtitleβ
Β
- Add a 2nd button (type: βbuttonβ) beside βSearchβ with the text βClearβ and give it an βidβ value, ie: βclearFormβ
Β
- Finally, change the βnavbar-brandβ to include your name
When completed, your navbar should look like the following
Β
Bootstrap Grid System (1 Column)
Since we are leveraging Bootstrap for this assignment, we should make use of their excellent responsive grid system.Β Beneath the navbar, add the following HTML
- Include a <div> element with the class βcontainerβ (so that our content is centered)
Β
- Within the βcontainerβ, create a <div> with class βrowβ
Β
- Within the βrowβ, create a <div> with class βcolβ (we will only have one column to show our data)
Main Table Skeleton
The main interface that users will interact with to view data in our application is a HTML table consisting of 5 columns: Year, Title, Plot, Rating and Run Time.Β Create this table within your βcolβ div according to the following specification:
- The <table> element should (at a minimum) have the class βtableβ and a unique id, ie: βmoviesTableβ, since we will be accessing it programmatically from JavaScript
- The <thead> element should contain one row
- The single header row should have 5 table heading elements with the text:
- Year
- Title
- Plot
- Rating
- Run Time
- The <tbody> element should be empty
Once your table is in place, your app should look like the following:
Paging Control
Since our βmoviesβ collection contains 23530 documents, we will leverage our web APIβs pagination feature when pulling movies from the database (ie: /api/movies?page=1&perPage=10, etc).Β To give the user some control over which page they wish to see, we must include a primitive pagination control (for this assignment, we will not let them βjumpβ to a specific page, but instead we will let them go back and forth between the pages in sequence).
To accomplish this, we must place the pagination buttons on our page before wiring up their functionality:
- Begin by copying the full Pagination HTML code from the official documentation: https://getbootstrap.com/docs/5.1/components/pagination and pasting it somewhere underneath your newly created βmoviesTableβ.
Β
- Next, delete the list items that contain the numbers 2, and 3 (leaving just 1)
- Give each of the 3 remaining <a> elements (nested within the <li> elements) unique id values such as βprevious-pageβ, βcurrent-pageβ and βnext-pageβ (we will use these id values to add functionality to the links and display the current page)
- Finally, remove the text 1 from the middle link (it will be added dynamically later).
Once your pagination control is in place, your app skeleton should look like the following:
Β
βGenericβ Modal Window Container
We will be showing the poster & details for a specific movie in a Bootstrap modal window.Β Since every time we show the modal window, it will have different content (Specific to the movie that was clicked), we must add an empty, generic modal window to the bottom of our page.
To get the correct HTML to use for your Bootstrap modal window, use the following example from the notes as a starting point.
Once you have copied and pasted the βmodalβ HTML into the bottom of your <body> element (ie, below the other content) , make the following changes:
Β
- Give your <div> with the class βmodal fadeβ a unique id, ie: βdetailsModalβ. We will need to reference this element every time we wish to show / work with the modal window.
Β
- Remove the βModal titleβ text from the <h5> element with class βmodal-titleβ. We will be using JavaScript to populate this with the selected movie title.
Β
- Remove the <p> element with the text βModal body text goes here.β from the <div> element with class βmodal-bodyβ. Again, we will be using JavaScript to populate this element
Β
- Finally, remove the button element with the text βSave changesβ. This modal is used to display information only, so a βsaveβ button is not required.
Β
NOTE: If you wish to use a larger modal window, the class βmodal-lgβ can be added beside the βmodal-dialogβ class.
Β
JavaScript File (main.js):
Now that we have all of our static HTML / CSS in place, we can start dynamically adding content and responding both user and bootstrap events using JavaScript.Β In your main.js file add the following variables & functions at the top of the file:
- page (number)
This will keep track of the current page that the user is viewing. Set it to 1 as the default value - perPage (number)This will be a constant value that we will use to reference how many movie items we wish to view on each page of our application. For this assignment, we will set it to 10.
- loadMovieData(title = null) (function)
This is arguably the most complex function to be created for this assignment.Β Its job is to pull movie data from your published movies API (created in A1), correctly format the data / add it to the DOM, add βclickβ events to each row item and populate / show a modal window with the correct data when the event fires.
Β
NOTE: It is not mandatory to do so, but you may wish to split the following logic up into multiple functions.
Β
Β
Β
Β
Loading The Data
Β
Depending on whether the value of βtitleβ is null or not, this function must make a βfetchβ request to your published API (created in A1) using the page and perPage values defined (above) to obtain the data.
Β
For example, if the title parameter is not null, then you must make the following request for data:
Β
/api/movies?page=page&perPage=perPage&title=title
Β
Additionally (since the title parameter is not null), you must set the page value to 1 and hide the pagination control β this can be done by adding the class βd-noneβ to the element with class βpaginationβ.Β HINT: Element.classlist can be used here: https://developer.mozilla.org/en-US/docs/Web/API/Element/classList
Β
If the title parameter is null, then you must make a similar request for data, only omitting the βtitleβ query parameter.Β Also, you must show the pagination control by removing the class βd-noneβ from the element with class βpaginationβ
Β
Creating the <tr> Elements
Β
Once we have obtained the data from the API, we must transform it into something that we can add to the DOM (specifically the <body> element of our moviesTable).Β This can be done by utilizing the Array βmapβ method within a Template literal (HINT: Review βGenerating HTMLβ section of the notes for more information).
Β
For guidance on how the data must be transformed, consider the following film: βThe Matrixβ (ie: /api/movies/573a139bf29313caabcf3d23).Β Reference the JSON output from your API at this path and note the generated HTML below: (NOTE: each element in the array of returned results must use the this format for rows in the table)
Β
<tr data-id=β573a139bf29313caabcf3d23β>
<td>1999</td>
<td>The Matrix</td>
<td>A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers.</td>
<td>R</td>
<td>2:16</td>
</tr>
Β
The HTML shown above can be obtained using the following properties from the returned JSON data:
Β
- 573a139bf29313caabcf3d23 β obtained from the _id property
Β
- 1999 β obtained from the year property
Β
- The Matrix β obtained from the title property
Β
- A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers. β obtained from the plot property (NOTE: There are some movies in the dataset without a plot. If this is the case, show N/A instead)
Β
- R β obtained using rated property (NOTE: As above, there are some movies in the dataset without a rated value. If this I the case, show N/A instead)
Β
- 2:16 β obtained using the runtime property, where the number of hours (2) was calculated using the formula: floor(runtime / 60) and the number of minutes (16) was calculated using the formula: (runtime % 60).toString().padStart(2, β0β)
Β
Adding <tr> Elements to the Table
Β
Using document.querySelector, obtain the <tbody> element of your moviesTable and update it to show your newly created <tr> elements.
Β
Updating the βCurrent Pageβ
Β
Using document.querySelector, obtain the element with id βcurrent-pageβ and update it to show the value of the global page value (from above)
Β
Adding Click Events & Loading / Displaying Movie Data
Β
With the rows in place, we can once again use document.querySelector to obtain all of newly created <tr> elements added to the table (above).Β Once you have selected them, loop through the array and add a βclickβ event to each element, in order to execute the following logic:
Β
- Obtain the value of the βdata-idβ attribute of the clicked element
Β
- Use this value to make a request for data using the path: /api/movies/data-id
Β
- Set the βmodal-titleβ of your βdetailsModalβ to show the value of the title property from the returned data
Β
- Set the βmodal-bodyβ of your βdetailsModalβ to show the data using the following format. For example, once again using the data from βThe Matrixβ
(ie: /api/movies/573a139bf29313caabcf3d23), the following HTML must be generated
Β
<img class=βimg-fluid w-100β³ src=βhttps://m.media-amazon.com/images/M/MV5BNzQzOTk3OTAtNDQ0Zi00ZTVkLWI0MTEtMDllZjNkYzNjNTc4L2ltYWdlXkEyXkFqcGdeQXVyNjU0OTQ0OTY@._V1_SY1000_SX677_AL_.jpgβ><br><br>
<strong>Directed By:</strong> Andy Wachowski, Lana Wachowski<br><br>
<p>Thomas A. Anderson is a man living two lives.</p>
<strong>Cast:</strong> Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss, Hugo Weaving<br><br>
<strong>Awards:</strong> Won 4 Oscars. Another 33 wins & 40 nominations.<br>
<strong>IMDB Rating:</strong> 8.7 (1080566 votes)
The HTML shown above can be obtained using the following properties from the returned JSON data:
Β
- https://m.media-amazon.com/images/M/MV5BNzQzOTk3OTAtNDQ0Zi00ZTVkLWI0MTEtMDllZjNkYzNjNTc4L2ltYWdlXkEyXkFqcGdeQXVyNjU0OTQ0OTY@._V1_SY1000_SX677_AL_.jpg β obtained from the poster property
Β
- Andy Wachowski, Lana Wachowski β obtained from the directors property (Array displayed using the βjoinβ method with a value of β, β)
Β
- Thomas A. Anderson is a man living two lives. β (NOTE: this is a shortened version of the full value from the API, shown here to save space) obtained from the fullplot property
Β
- Keanu Reeves, Laurence Fishburne, Carrie-Anne Moss, Hugo Weaving β obtained from the cast property (Array displayed using the βjoinβ method with a value of β, β). (NOTE: There are some movies in the dataset without a cast.Β If this is the case, show N/A instead)
Β
- Won 4 Oscars. Another 33 wins & 40 nominations. β obtained from the text property
Β
- 7 β obtained from the imdb.rating property
Β
- 1080566 β obtained from the votes property
Β
- Using querySelector, obtain the <div> element of your βdetailsModalβ with class βmodal-bodyβ and update it to show your newly created elements (from above).
Β
- Once this is complete, show the modal (HINT: Refer to the code outlined in the notes under βModal Windowsβ for more information).
Β
The remainder of the code within main.js must be executed when the βDOM is readyβ, ie: once the
βDOMContentLoadedβ event has fired for the βdocumentβ object:
Β
- Click event for the βprevious pageβ pagination button:When this event is triggered we simply need to check if the current value of page (declared at the top of the file) is greater than 1. If it is, then we decrease the value of page by 1 and invoke the loadMovieData function (without the βtitleβ parameter) to refresh the rows in the table with the new page value.
Β
Β
Β
Β
Β
- Click event for the βnext pageβ pagination button:This event behaves almost exactly like the click event for the βprevious pageβ, except that instead of decreasing the value of page, we increase the value of page by 1 and invoke the loadMovieData function (without the βtitleβ parameter) to refresh the rows in the table with the new page value.
Β
- Submit event for the βsearchFormβ form:This event simply prevents the default submit from occurring for the form and invokes the loadMovieData function with the value of the βtitleβ field (from the search form).
Β
- Click event for the βclearFormβ button:This event resets the value of the βtitleβ field (from the search form) to an empty string (ββ) and invokes the loadMovieData function without any parameters
Β
Assignment Submission:
- Add the following declaration at the top of your main.js file/*********************************************************************************
* WEB422 β Assignment 2
*Β I declare that this assignment is my own work in accordance with Seneca Academic Policy.
*Β No part of this assignment has been copied manually or electronically from any other source
*Β (including web sites) or distributed to other students.
*
*Β Name: ______________________ Student ID: __________________ Date: ____________________
*
********************************************************************************/ - Compress (.zip) the files in your Visual Studio working directory (this is the folder that you opened in Visual Studio to create your client side code).
Important Note:
- NO LATE SUBMISSIONS for assignments. Late assignment submissions will not be accepted and will receive a grade of zero (0).
- After the end (11:59PM) of the due date, the assignment submission link on My.Seneca will no longer be available.
- Submitted assignments must run locally, ie: start up errors causing the assignment/app to fail on startup will result in aΒ grade of zero (0)for the assignment.





