[SOLVED] Web322 Assignment 4

35.00 $

Category:
Click Category Button to View Your Next Assignment | Homework

You will receive the following solution file(s) instantly after successful payment:

zip file icon Assignment-4-szbmsn.zip (2118.7 KB)
Assignment Instructions Updated Recently? Submit Below and we will provide new Solution!
Submit New Instructions
πŸ”’ Securely Powered by:
Secure Checkout
5/5 - (2 votes)

Build upon the code created in Assignment 3 by incorporating the Handlebars view engine to render our JSON data visually in the browser using .hbs views and layouts.Β  Additionally, update our data-service module to allow for people to be updated using a web form.

Β 

NOTE: If you are unable to start this assignment because Assignment 3 was incomplete – email your professor for a clean version of the Assignment 3 files to start from (effectively removing any custom CSS or text added to your solution).

Specification:

As mentioned above, this assignment will build upon your code from Assignment 3.Β  To begin, make a copy of your assignment 3 folder and open it in Visual Studio Code.Β  Note:Β  this will copy your .git folder as well (including the β€œheroku” remote for assignment 3).Β  If you wish to start fresh with a new git repository, you will need to delete the copied .git folder and execute β€œgit init” again in.

Β 

Part 1: Getting Express Handlebars & Updating your views

Β 

Step 1: Install & configure express-handlebars

  • Use npm to install the β€œexpress-handlebars” module
  • Wire up your server.js file to use the new β€œexpress-handlebars” module, ie:
    • β€œrequire” it as exphbs
    • add the app.engine() code using exphbs({ … }) and the β€œextname” property as β€œ.hbs” and the β€œdefaultLayout” property as β€œmain” (See the Week 6 Notes) o call app.set() to specify the β€˜view engine’ (See the Week 6 Notes)
  • Inside the β€œviews” folder, create a β€œlayouts” folder

Step 2: Create the β€œdefault layout” & refactor home.html to use .hbs

Β 

  • In the β€œlayouts” directory, create a β€œmain.hbs” file (this is our β€œdefault layout”)
  • Copy all the content of the β€œhome.html” file and paste it into β€œmain.hbs”

o Quick Note: if your site.css link looks like this href=”css/site.css”, it must be modified to use a leading β€œ/”, ie href=”/css/site.css”

  • Next, in your main.hbs file, remove all content INSIDE (not including) the single <div class=”container”>…</div> element and replace it with {{{body}}}
  • Once this is done, rename home.html to home.hbs
  • Inside home.hbs, remove all content EXCEPT what is INSIDE the single <div class=”container”>…</div> element (this should leave a single <div class=”row”>…</div> element containing two β€œcolumns”, ie elements with class β€œcol-md- …” and their contents)
  • In your server.js file, change the GET route for β€œ/” to β€œrender” the β€œhome” view, instead of sending home.html
  • Test your server – you shouldn’t see any changes. This means that your default layout (β€œmain.hbs”), β€œhome.hbs” and server.js files are working correctly with the express-handlebars module.

Step 3: Update the remaining β€œabout”, β€œaddPeople” and β€œaddPicture” files to use .hbs

Β 

  • Follow the same procedure that was used for β€œhome.html”, for each of the above 3 files, ie:
    • Rename the .html file to .hbs o Delete all content EXCEPT what is INSIDE the single <div class=”container”>…</div> element
    • Modify the corresponding GET route (ie: β€œ/about”, β€œ/pictures/add” or β€œ/people/add”) to β€œres.render” the appropriate .hbs file, instead of using res.sendFile
  • Test your server – you shouldn’t see any changes, except for the fact that your menu items are no longer highlighted when we change routes (only β€œHome” remains highlighted, since it is the only menu item within our main.hbs β€œdefault layout” with the class β€œactive”

Step 4: Fixing the Navigation Bar to Show the correct β€œactive” item

Β 

  • To fix the issue we created by placing our navigation bar in our β€œdefault” layout, we need to make some small updates, including adding the following middleware function above your routes in server.js:

Β 

app.use(function(req,res,next){Β Β Β Β  let route = req.baseUrl + req.path;Β Β Β Β  app.locals.activeRoute = (route == β€œ/”) ? β€œ/” : route.replace(/\/$/, β€œβ€);Β Β Β Β  next();

});

Β 

This will add the property β€œactiveRoute” to β€œapp.locals” whenever the route changes, ie: if our route is β€œ/people/add”, the app.locals.activeRoute value will be β€œ/people/add”.

  • Next, we must use the following handlebars custom β€œhelper” (See the Week 6 notes for adding custom β€œhelpers”)”

Β 

navLink: function(url, options){Β Β Β Β  return β€˜<li’ +

((url == app.locals.activeRoute) ? β€˜ class=”active” β€˜ : ”) +

β€˜><a href=β€β€˜ + url + β€˜β€>’ + options.fn(this) + β€˜</a></li>’;

}

  • This basically allows us to replace all of our existing navbar links, ie: <li><a href=”/about”>About</a></li> with code that looks like this {{#navLink β€œ/about”}}About{{/navLink}}. The benefit here is that the helper will automatically render the correct <li> element add the class β€œactive” if app.locals.activeRoute matches the provided url, ie β€œ/about”
  • Now that our helpers are in place, update all the navbar links in main.hbs to use the new helper, for example:

o <li><a href=”/about”>About</a></li> will become {{#navLink β€œ/about”}}About{{/navLink}}

  • Test the server again – you should see that the correct menu items are highlighted as you navigate between views

Part 2: Rendering the Pictures in the β€œ/pictures” route

Β 

Next, we’ll work with pictures.Β Β  It’ll be easier if 1 or more pictures have been added via the application, so do this now.

Β 

Step 1: Add / configure β€œpictures.hbs” view and server.js

  • First, add a file β€œpictures.hbs in the β€œviews” directory
  • Inside your newly created pictures.hbs file, add the following code to render 1 (one) of your (already-existing) uploaded pictures, ie (picture β€œ1518186273491.jpg” – your picture will have a different timestamp):

<div class=”row”>

<div class=”col-md-12β€³>

<h2>Pictures</h2>

<hr />

</div>

Β 

<div class=”col-md-4β€³>

<img src=”/pictures/uploaded/1518186273491.jpg” class=”img-responsive img-thumbnail” />Β Β Β Β  </div>

</div>

Note the classes β€œimg-responsive” and β€œimg-thumbnail”.Β  These are simply bootstrap classes that correctly scale and decorate the picture with a border. See https://getbootstrap.com/docs/3.3/css/#images / https://getbootstrap.com/docs/3.3/css/#images-shapes for more information

  • Next, modify your GET route for /pictures. Instead of executing res.json and sending the β€œpictures” array, you should use res.render(β€œpictures”, Object Containing β€œpictures” Array Here); so that you can send the object containing the array of pictures as data for your β€œpictures” view
  • Once this is complete, modify your pictures.hbs file using the handlebars #each helper to iterate over the

β€œpictures” array, such that every picture is shown in its own <div class=”col-md-4β€³>…</div> element

(effectively replacing our single β€œstatic” picture).Β  This will have the effect of giving us a nice, responsive grid of multiple β€œcol-md-4” columns, each containing its own picture.

o NOTE: you can use {{this}} within the loop to get the current value of the item in the array of strings

(this will be the filename of the current picture, ie: β€œ1518186273491.jpg”)

  • If there are no pictures (ie the β€œpictures” array is empty), show the following element instead:

<div class=”col-md-12 text-center”>

<strong>No Pictures Available</strong> </div>

  • NOTE: since we are hosting our app on heroku, you will notice that once the app β€œsleeps” and starts up again, any uploaded pictures are gone. This is expected behavior.Β  However, if you wish to develop an application that will persist its images between restarts of the app, you can look at something like Cloudinary (this service provides a mechanism to upload pictures to Cloudinary from your server.js code and store them online using their service)

Part 3: Updating the People Route & Adding a View

Β 

Rather than simply outputting a list of people using res.json, it would be much better to actually render the data in a table that allows us to access individual people and filter the list using our existing req.params code.

Β 

Step 1: Creating a simple β€œPeople” list & updating server.js

Β 

  • First, add a file β€œpeople.hbs” ” in the β€œviews” directory
  • Inside the newly created β€œpeople.hbs” view, add the html:

<div class=”row”>

<div class=”col-md-12β€³>

<h2>People</h2>

<hr />

Β 

<p>TODO: render a list of all People first and last names here</p>

Β 

</div>

</div>

Β 

Β 

  • Replace the <p> element (containing the TODO message) with code to iterate over each person and simply render their first and last names (you may assume that there will be an β€œpeople” array (see below).
  • Once this is done, update your GET β€œ/people” route according to the following specification
    • Every time you would have used res.json(data), modify it to instead use res.render(β€œpeople”, {people:

data})

  • Every time you would have used res.json({message: β€œno results”}) – ie: when the promise has an error (ie in .catch()), modify instead to use res.render({message: β€œno results”});
  • Test the Server – you should see the following page for the β€œ/people” route:

Β 

Β 

Β 

Step 2: Building the Table & Displaying the error β€œmessage”

  • Update the people.hbs file to render all of the data in a table, using the bootstrap classes: β€œtable-responsive”

(for the <div> containing the table) and β€œtable” (for the table itself) – Refer to theΒ  completed sample here https://gentle-earth-90224.herokuapp.com/people

  • The table must consist of 5 columns with the headings: Person ID, Full Name, Phone Number, Address, and Car Vin
  • Additionally, the Name in the Full Name column must link to /person/id where id is the person’s id for that row o The β€œPhone” column must be a β€œtel” link to the user’s phone number for that row
  • The β€œCar Vin” link must link to /cars?vin=vin where vin is the vin number for the person for that row
  • Beneath <div class=”col-md-12β€³>…</div> element, add the following code that will conditionally display the β€œmessage” only if there are no people (HINT: #unless people)

Β 

<div class=”col-md-12 text-center”>

<strong>{{message}}</strong> </div>

This will allow us to correctly show the error message from the .catch() in our route

Β 

Step 3: Adding new query route for /stores

Update server.js to add a new query route for stores

  • /stores?retailer=value
    • return a JSON string consisting of all stores where value could is retailer attribute of the stores object – this can be accomplished by calling the getStoresByRetailer(value) function of your data-service (defined below)
  • Add getStoresByRetailer(data) Function
    • In data-service.js this function will provide an array of β€œstores” objects whose retailer property matches the data parameter using the resolve method of the returned promise.
    • If for some reason, the length of the array is 0 (no results returned), this function must invoke the reject method and pass a meaningful message, ie: β€œno results returned”.

Β 

Β 

Β 

Part 4: Updating the Stores Route & Adding a View

Now that we have the β€œPeople” data rendering correctly in the browser, we can use the same pattern to render the β€œStores” data in a table:

Β 

Step 1: Creating a simple β€œStores” list & updating server.js

Β 

  • First, add a file β€œstores.hbs” in the β€œviews” directory
  • Inside the newly created ” stores.hbs” view, add the html:

<div class=”row”>

<div class=”col-md-12β€³>

<h2>Stores</h2>

<hr />

Β 

<p>TODO: render a list of all stores id’s and names here</p>

Β 

</div> </div>

  • Replace the <p> element (containing the TODO message) with code to iterate over each store and simply render their id, name, phone and address values (you may assume that there will be a β€œstores” array (see below).
  • Once this is done, update your GET β€œ/stores” route according to the following specification

o Instead of using res.json(data), modify it to instead use res.render(β€œstores”, {stores: data});

  • Test the Server – you should see the following page for the β€œ/stores” route:

Β 

Β 

Β 

Step 2: Building the Table

  • Update the stores.hbs file to render all of the data in a table, using the bootstrap classes: β€œtable-responsive” (for the <div> containing the table) and β€œtable” (for the table itself).
  • The table must consist of 4 columns with the headings: Store id, Store Name, Store Phone, and Address
  • The β€œStore Name” link must link to /cars?make=make where make is the make of the retailer for that row
  • The β€œPhone” column must be a β€œtel” link to the user’s phone number for that row
  • Refer to the example online at https://gentle-earth-90224.herokuapp.com/stores

Β 

Part 5: Updating the Cars Route & Adding a View

Now that we have the β€œPeople” and β€œStores” data rendering correctly in the browser, we can use the same pattern to render the β€œCars” data in a table:

Β 

Step 1: Creating a simple β€œCars” list & updating server.js

Β 

  • First, add a file β€œcars.hbs” in the β€œviews” directory
  • Inside the newly created ” cars.hbs” view, add the html:

<div class=”row”>

<div class=”col-md-12β€³>

<h2>Cars</h2>

<hr />

Β 

<p>TODO: render a list of all cars id’s and names here</p>

Β 

</div> </div>

  • Replace the <p> element (containing the TODO message) with code to iterate over each car and simply render their id, make, model, year and vin values (you may assume that there will be a β€œcars” array (see below).
  • Once this is done, update your GET β€œ/cars” route according to the following specification

o Instead of using res.json(data), modify it to instead use res.render(β€œcars”, {cars: data});

  • Test the Server – you should see the following page for the β€œ/cars” route:

Β 

Β 

Β 

Step 2: Building the Table

  • Update the cars.hbs file to render all of the data in a table, using the bootstrap classes: β€œtable-responsive” (for the <div> containing the table) and β€œtable” (for the table itself).
  • The table must consist of 5 columns with the headings: Car id, Car Make, Car Model, Car Year and Vin
  • The β€œCar make” link must link to /stores?retailer=retailer where retailer is the retailer of the make for that row
  • The β€œCar Year” ” link must link to /cars?year=year where year is the year of the car for that row
  • The β€œCar Vin” link must link to /people?vin=vin where vin is the vin of the car for that row
  • Refer to the example online at https://gentle-earth-90224.herokuapp.com/cars

Β 

Part 6: Updating Existing People

The last piece of the assignment is to create a view for a single person.Β  Currently, when you click on an person’s name in the β€œ/people” route, you will be redirected to a page that shows all of the information for that person as a JSON-formatted string (ie: accessing http://localhost:8080/person/21, should display a JSON formatted string representing the corresponding person – person 21).

Now that we are familiar with the express-handlebars module, we should add a view to render this data in a form and allow the user to save changes.

Β 

Step 1: Creating new .hbs file / route to Update Person

Β 

  • First, add a file β€œperson.hbs” in the β€œviews” directory
  • Inside the newly created β€œperson.hbs” view, add the html (NOTE: Some of the following html code may wrap across lines to fit on the .pdf – be sure to check that the formatting is correct after pasting the code):

<div class=”row”>

<div class=”col-md-12β€³>

<h2>{{person.first_name}} {{ person.last_name}} – Person: {{ person.id}}</h2>

<hr />

<form method=”post” action=”/person/update”>

<fieldset>

<legend>Personal Information</legend>

<div class=”row”>

<div class=”col-md-6β€³>

<div class=”form-group”>

<label for=”first_name”>First Name:</label>

<input class=”form-control” id=”first_name” name=”first_name” type=”text” value=”{{person.first_name}}” />

</div>

</div>

<div class=”col-md-6β€³>

<div class=”form-group”>

<label for=”last_name”>Last Name:</label>

<input class=”form-control” id=”last_name” name=”last_name” type=”text” value=”{{person.last_name}}” />

</div>

</div>Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β  </div>

</fieldset>

<hr />

<input type=”submit” class=”btn btn-primary pull-right” value=”Update Person” /><br /><br /><br />Β Β Β Β Β Β Β Β  </form>

</div>

</div>

Β 

  • Once this is done, update your GET β€œ/person/:id” route according to the following specification

o Use res.render(β€œperson”, { person: data }); inside the .then() callback (instead of res.json) and use res.render(β€œperson”,{message:”no results”}); inside the .catch() callback

  • Test the server (/person/1) – this will get you started on creating / populating the form with user data:

Β 

Β 

  • Continue this pattern to develop the full form to match the completed sample here – you may use the code in the sample to help guide your solution

o Id: type: β€œhidden”, name: β€œid” o Phone: type: β€œtext”, name: β€œphone” o Address (Street): type: β€œtext”, name: β€œaddress” o Address (City): type: β€œtext”, name: β€œcity” o Person’s Vin Number: type: β€œtext”, name: β€œvin”

  • No validation (client or server-side) is required on any of the form elements at this time
  • Once the form is complete, we must add the POST route: /person/update in our server.js file:

Β 

app.post(β€œ/person/update”, (req, res) => {Β Β Β Β  console.log(req.body);

res.redirect(β€œ/people”);

});

This will show you all the data from your form in the console, once the user clicks β€œUpdate Person”. However, in order to take that data and update our β€œpeople” array in memory, we must add some new functionality to the data-service.js module:

Step 2: Updating the data-service.js module

Β 

  • Add the new method: updatePerson(personData) that returns a promise. This method will:

o Search through the β€œpeople” array for a person with an id that matches the JavaScript object (parameter personData). o When the matching person is found, overwrite it with the new person passed into the function (parameter personData) o Once this has completed successfully, invoke the resolve() method without any data.

  • Now that we have a new updatePerson() method, we can invoke this function from our newly created app.post(β€œ/person/update”, (req, res) => { … }); Β  Simply invoke the updatePerson() method with the req.body as the parameter.Β  Once the promise is resolved use the then() callback to execute the res.redirect(β€œ/people”); code.
  • Test your server in the browser by updating Person 21 (Regina Dunphy). Once you have clicked β€œUpdate Person” and are redirected back to the People list, Person 21 should show your changes!

Β 

Part 7: Pushing to Heroku

Once you are satisfied with your application, deploy it to Heroku:

  • Ensure that you have checked in your latest code using git (from within Visual Studio Code)
  • Open the integrated terminal in Visual Studio Code
  • Log in to your Heroku account using the command heroku login
  • Create a new app on Heroku using the command heroku create
  • Push your code to Heroku using the command git push heroku master
  • IMPORTANT NOTE: Since we are using an β€œunverified” free account on Heroku, we are limited to only 5 apps, so if you have been experimenting on Heroku and have created 5 apps already, you must delete one (or verify your account with a credit card). Once you have received a grade for Assignment 1, it is safe to delete this app (login to the Heroku website, click on your app and then click the Delete app… button under β€œSettings”).

Β 

Testing: Sample Solution

Β 

To see a completed version of this app running, visit: https://gentle-earth-90224.herokuapp.com/

Β 

Please note: This solution is visible to ALL students and professors at Seneca College.Β  It is your responsibility as a student of the college not to post inappropriate content / images to the shared solution.Β  It is meant purely as an exemplar and any misuse will not be tolerated.

Β 

Β 

1 file Β· 2.1 MB

  • Assignment-4-szbmsn.zip 2.1 MB