Course Banner

Select Inventory Items

Overview

When a site administrator needs to update or delete a inventory item from the database it is helpful if a list of potential items is provided. This allows for quick identification prior to beginning the actual update or delete process. This activity will do just that, it will select a list of vehicles in inventory from the database based on the classification_id, using an AJAX request and then display a mechanism to begin the update and/or delete process from the content stored in the returned JSON object.

Video Demonstration

The video provides a general overview of the activity, but does not contain the detail needed to complete each process. Watch the video to obtain a general idea, but follow the written steps to complete the activity. This is the Transcript of the video.

Inventory Model

You already have a function in the inventory model that will return all inventory items based on a classification_id. You will reuse this function. You may want to open the model, find the function, and refresh your knowledge of its name for use again in the inventory controller.

Inventory Controller

Earlier you built into the invController the ability to deliver a Inventory Management view. It is in the Inventory Management view that we will display the list of inventory items based on the classification to which they belong. By doing this we limit the number of items displayed, keeping things somewhat manageable. In addition, it provides a means of introducing the ability of Node / Express to generate JSON data and allows a review of AJAX interactions which you should have been introduced to in your earlier frontend development course.

Deliver Inventory Management Function

  1. Locate and open the invController.
  2. Within the controller find the function that is responsible for delivering the inventory management view.
  3. Create some space between where the navigation bar is built and res.render is used to deliver the management view. In my code the created space looks like this (your names may be different):
    invCont.buildManagementView = async function (req, res, next){
      let nav = await utilities.getNav()
      ... This is the empty space ...
      res.render("./inventory/management", {
      ... remaining render code is not shown ...
  4. Within the empty space we will call a function and store the results that will create a select list to be displayed in the inventory management view. The function to create the select list is the same one used in the "Add New Inventory" form. My code looks like this and should be found in the function that delivers the Add New Inventory view, in this same controller.
    const classificationSelect = await utilities.buildClassificationList()
  5. With the code to create the select list in place, be sure to add it to the render data object, so it is passed on to the view.
  6. Ensure that no warnings or errors exist in the file.
  7. Save the file.

The Inventory Management View

With the controller and model ready, we're ready to turn our attention to the Inventory Management view. The view itself will contain a few added items:

  1. Below the links to add new classification or add a new vehicle to inventory, add a <h2> heading, to manage inventory (e.g.<h2>Manage Inventory</h2>).
  2. Below the heading add a paragraph that tells the user to select a classification from the list to see the items belonging to the classification.
  3. Below the paragraph, add an EJS code block to display the classification list.
  4. Below where the list will be displayed, create an empty HTML table. It is within this table that inventory items returned from the controller will be displayed. Like so:
    <table id="inventoryDisplay"></table>

    Typically when an HTML table is built it consists of the <table> element, then inside you may find <thead>, <tfoot> and <tbody> elements. In our case, the view will only contain the basic <table> element. All the interior elements and content will be created by JavaScript, then "injected" into the table element — this is known as DOM manipulation.

    Note the id attribute and its value. They will be used as a JavaScript hook to know where to inject the inventory data.

  5. Below the empty table, add a <noscript> element that will display a message if JavaScript is disabled, like so:
    <noscript>JavaScript must be enabled to use this page.</noscript>
    If the browser detects that JavaScript is disabled, it will show the <noscript> element and its contents. If JavaScript is enabled the <noscript> element is hidden.
  6. Next, you will create and hook up a JavaScript file that will watch for changes in the select list and request data from the application. When the data is returned, it will wrap it up in HTML and inject it into the table created in #4 above.
  7. Ensure that no warnings or errors exist in the file.
  8. Save the file.

The JavaScript File

Hopefully you'll remember from the Frontend development class that best practice is to write HTML, CSS and JavaScript in separate files, then connect them together. You already have HTML within the EJS file, layout and partial files, and a CSS file, and they are separate from one another but connected using a <link> element. We want to create a JavaScript file and connect it to the management view.

  1. Scroll to the bottom of the management view.
  2. Add the following HTML code:
    <script src="../../js/inventory.js"></script>
    Don't worry that the file doesn't exist. We'll create it next.

The JavaScript File

Our JavaScript file will do two things for us: 1) listen to the classifications select element to detect when a new classification is selected. When a change occurs it will send a request which will ask the inventory controller to fetch the items from inventory based on the classification and send them back, and 2) when the inventory data is returned, it will send the data, as a JavaScript object, to a new JavaScript function to build the table structure around it, then inject it into the table that we just added to the inventory management view.

Create inventory.js

Inside the "public > js" folder, create a new file named "inventory.js". As always, we want our files to represent what they do. In this case, the file will work with inventory items.

The eventListener

Modern JavaScript has what is called an "eventListener" method. It does what it sounds like, it listens for an event to occur. In our case, the event will be when the select element "changes".

Beginning at the top of the new JavaScript file, add the following code:

'use strict' 
 
 // Get a list of items in inventory based on the classification_id 
 let classificationList = document.querySelector("#classificationList")
 classificationList.addEventListener("change", function () { 
  let classification_id = classificationList.value 
  console.log(`classification_id is: ${classification_id}`) 
  let classIdURL = "/inv/getInventory/"+classification_id 
  fetch(classIdURL) 
  .then(function (response) { 
   if (response.ok) { 
    return response.json(); 
   } 
   throw Error("Network response was not OK"); 
  }) 
  .then(function (data) { 
   console.log(data); 
   buildInventoryList(data); 
  }) 
  .catch(function (error) { 
   console.log('There was a problem: ', error.message) 
  }) 
 })

An Explanation

In short, the function shown above requests the data, based on the classification_id and catches any errors if they exist, and sends the retrieved data to the buildInventoryList function for building it into HTML and then displays it into the management view.

The buildInventoryList Function

Finally, let's build the function that will parse the JavaScript object and wrap it up into HTML, then inject it into the inventory management view.

Add a few empty lines beneath the eventListener that you just created. Add the following function to the bottom of the "inventory.js" file.

// Build inventory items into HTML table components and inject into DOM 
function buildInventoryList(data) { 
 let inventoryDisplay = document.getElementById("inventoryDisplay"); 
 // Set up the table labels 
 let dataTable = '<thead>'; 
 dataTable += '<tr><th>Vehicle Name</th><td>&nbsp;</td><td>&nbsp;</td></tr>'; 
 dataTable += '</thead>'; 
 // Set up the table body 
 dataTable += '<tbody>'; 
 // Iterate over all vehicles in the array and put each in a row 
 data.forEach(function (element) { 
  console.log(element.inv_id + ", " + element.inv_model); 
  dataTable += `<tr><td>${element.inv_make} ${element.inv_model}</td>`; 
  dataTable += `<td><a href='/inv/edit/${element.inv_id}' title='Click to update'>Modify</a></td>`; 
  dataTable += `<td><a href='/inv/delete/${element.inv_id}' title='Click to delete'>Delete</a></td></tr>`; 
 }) 
 dataTable += '</tbody>'; 
 // Display the contents in the Inventory Management view 
 inventoryDisplay.innerHTML = dataTable; 
}

An Explanation

Ensure that no warnings or errors appear in the JavaScript file.

Save the file.

Edit the Inventory Routes

For this entire process to work, a new route needs to be added to the "inventoryRoute" file.

  1. Open the "inventoryRoute" file in the "routes" folder.
  2. Add a new route, that works with the URL in the JavaScript file that you just built:
    /inv/getInventory/:classification_id
    [Remember: the "inv" portion already exists in the "server.js" file. You only need to account for the rest in the route.]
  3. Be sure to use a function from the inventory controller to process the route and return the data as JSON. For example:
    router.get("/getInventory/:classification_id", utilities.handleErrors(invController.getInventoryJSON))
  4. Ensure there are no warnings or errors.
  5. Save the file.

Build the Controller Function

Finally, return to the inventory controller, to add the function that will return the JSON data.

  1. Open the "inventory controller" file, if it is not already open.
  2. Scroll to the bottom of the file and add some empty lines beneath the last function and before the module.exports statement.
  3. Add the following function in the empty space:
    /* ***************************
     *  Return Inventory by Classification As JSON
     * ************************** */
    invCont.getInventoryJSON = async (req, res, next) => {
      const classification_id = parseInt(req.params.classification_id)
      const invData = await invModel.getInventoryByClassificationId(classification_id)
      if (invData[0].inv_id) {
        return res.json(invData)
      } else {
        next(new Error("No data returned"))
      }
    }
  4. An Explanation

    • Lines 1-3 - a multi-line comment for the function.
    • Line 4 - the opening of the function.
    • Line 5 - collects and stores the classification_id that has been passed as a parameter through the URL. Uses the JavaScript parseInt() function to cast it as an integer, which is also a security step.
    • Line 6 - calls the model-based function to get the data based on the classification_id.
    • Line 7 - checks to make sure there is a value in the first element of the array being returned.
    • Line 8 - if data is present, returns the result set as a JSON object.
    • Line 9 - ends the "if" check and opens an "else" structure.
    • Line 10 - throws an error for the Express error handler if no data is found.
    • Line 11 - ends the "else" structure.
    • Line 12 - ends the function.
  5. Ensure that no warnings or errors exist.
  6. Save the file.

Time to Test

  1. Save all files if you haven't already done so.
  2. Make sure the local server is running and go the local site in a browser.
  3. If you are not logged in as an employee or adminstrative user, do so.
  4. Once logged in, alter the URL to point to the inventory control process (e.g. http://localhost:5500/inv/) and press the "Enter" key.
  5. If things worked correctly, you should be looking at the management view and a heading and paragraph should appear indicating that you should choose a classification item from the select list.
  6. The select list should appear below the heading and paragraph.
  7. When you change the list to select a classification, there should be a very short pause and then the table of vehicles from inventory, based on the classification selected, should appear immediately below the select list.
  8. Every time you change the list to a different classification, the table of items should change too.
  9. If you open the browser inspect tools, and then click the "Console" tab you should see the log items that were part of the JavaScript eventListener and function.
  10. You will need to add some CSS to your external style sheet to dress up the table and make things easier to view.
  11. If things worked as planned you are ready to move on. If they didn't work, get help from your learning team, from the TA or your professor. But it has to work before moving to the next activity.