Challenge: Solution Review

This lesson will explain the solution to the problem from the last coding challenge.

We'll cover the following

Solution #

Press + to interact
class ShoppingCartModel
{
constructor(itemNumber,itemName, itemQuantity, itemPrice){
this.itemName = itemName;
this.itemQuantity = itemQuantity;
this.itemPrice = itemPrice;
this.itemNumber = itemNumber
}
getItemName(){
return this.itemName;
}
getItemQuantity(){
return this.itemQuantity
}
getItemPrice(){
return this.itemPrice;
}
getItemNumber(){
return this.itemNumber;
}
}
class ShoppingCartView
{
constructor(){
this.controller = null;
}
registerWith(controller) {
this.controller = controller;
this.controller.addView(this);
}
displayItem(itemNumber,itemName,itemQuantity,itemPrice)
{
console.log(`Item Number: ${itemNumber}\nItem: ${itemName}\nQuantity: ${itemQuantity}\nPrice: ${itemPrice}`);
}
buyItem(itemNumber,itemName, itemQuantity, itemPrice) {
this.controller.buyItem(itemNumber,itemName, itemQuantity, itemPrice);
}
changeItemQuantity(itemNumber,newQuantity){
this.controller.setItemQuantity(itemNumber,newQuantity);
}
}
class ShoppingCartController
{
constructor(){
this.model = null;
this.view = null;
this.itemList = [];
}
addView(view) {
this.view = view;
}
addModel(model) {
this.model = model;
}
setItemQuantity(itemNumber,newQuantity){
if(this.itemList[itemNumber]){
this.itemList[itemNumber].itemQuantity = newQuantity;
this.updateView();
}
}
updateView()
{
for( let i in this.itemList)
this.view.displayItem(this.itemList[i].getItemNumber(),this.itemList[i].getItemName(), this.itemList[i].getItemQuantity(), this.itemList[i].getItemPrice());
}
buyItem(itemName, itemQuantity, itemPrice) {
this.itemList.push(new ShoppingCartModel(this.itemList.length,itemName, itemQuantity, itemPrice));
this.updateView();
}
}
var view = new ShoppingCartView();
var controller = new ShoppingCartController();
view.registerWith(controller);
view.buyItem("Popcorn", 3, 2.50);
console.log("\n");
view.buyItem("Soap", 5, 10.00);
console.log("\n");
view.changeItemQuantity(0,6);

Explanation

The program simply displays information about the items in the shopping cart. As discussed, it is divided into three components:

  • The shopping cart object is represented by the model ShoppingCartModel.

  • The information about the items in the cart is displayed by the view component ShoppingCartView.

  • The model and view components are connected through the controller ShoppingCartController.

Let’s take a look at each component one-by-one.

ShoppingCartModel

class ShoppingCartModel
{ 
    constructor(itemNumber,itemName, itemQuantity, itemPrice){
        this.itemName = itemName;
        this.itemQuantity = itemQuantity;
        this.itemPrice = itemPrice;
        this.itemNumber = itemNumber
    }

    getItemName(){
        return this.itemName;
    }

    getItemQuantity(){
        return this.itemQuantity
    }

    getItemPrice(){
        return this.itemPrice;
    }

    getItemNumber(){
        return this.itemNumber;
    }
} 

The ShoppingCartModel presents a shopping cart object which has the following properties: the item number, name, quantity, and the price. It also has get functions to retrieve the values of these properties.

ShoppingCartView

class ShoppingCartView  
{
    constructor(){
        this.controller = null;
    }
    //code...
} 

The view is responsible for displaying the data, that is, the cart information on the user interface. It must show the updated information if a change occurs in the model or if a user makes an edit in the view when interacting with the interface.

As discussed, the controller acts as the mediator between the model and the view. Hence, for the controller to be able to communicate with the view, we initialize the current view for the controller by first setting the controller property and then adding the view to it:

registerWith(controller) {
        this.controller = controller;
        this.controller.addView(this); 
}

Next, let’s look at the scenario when a user makes an edit in the view. In this case, let’s assume a person buys an item by invoking the buyItem function in view (you can think of it as a “buy” button they click). So now that there has been an edit in the view, the controller will register that user action and make changes on the model side accordingly.

buyItem(itemNumber,itemName, itemQuantity, itemPrice) {
        this.controller.buyItem(itemNumber,itemName, itemQuantity, itemPrice);
}

We’ll discuss the changes the controller makes in detail, later on. For now, all you need to know is that as a result of the user action on the view side, the controller invoked its own buyItem function to make updates at the model side.

Another scenario is when the data in the model changes and the view updates itself accordingly. For example, a person changes the quanitity of an item they want to buy. This change in the model will need to be reflected on the view side. Here again, the controller will act as the mediator between the two:

changeItemQuantity(itemNumber,newQuantity){
        this.controller.setItemQuantity(itemNumber,newQuantity);       
}

We’ll look into how the updated information of an item is communicated and reflected on the view side later on.

Lastly, since the view needs to display the information, it also has a displayItem function that displays the itemNumber, name, quantity and, price of an item.

displayItem(itemNumber,itemName,itemQuantity,itemPrice) 
{ 
   console.log(`Item Number: ${itemNumber}\nItem: ${itemName}\nQuantity: ${itemQuantity}\nPrice: ${itemPrice}`); 
}   

ShoppingCartController

class ShoppingCartController  
{ 
    constructor(){
        this.model = null;
        this.view = null;
        this.itemList = [];
    }
    
    addView(view) {
        this.view = view;
    }
    addModel(model) {
        this.model = model;
    }
    //code...
} 

The controller has the methods addView and addModel to initialize the model and the view components. It also initializes the property itemList, which stores the list of shopping cart model objects.

The controller has a buyItem function of its own that it calls when a person calls the buyItem function on the view side.

buyItem(itemName, itemQuantity, itemPrice){
     this.itemList.push(new ShoppingCartModel(this.itemList.length,itemName, itemQuantity, itemPrice));
     this.updateView();
}

The function creates a new instance of the ShoppingCartModel, passing it the information of the item it wants to buy. It then adds it into the itemList. Now that an update has been made to the cart, the controller updates the view by making a call to the updateView function.

updateView() 
{
   for( let i in this.itemList)      
      this.view.displayItem(this.itemList[i].getItemNumber(),this.itemList[i].getItemName(), this.itemList[i].getItemQuantity(), this.itemList[i].getItemPrice()); 
} 

The function iterates through the list of items and calls the dsiplayItem function for each item.

Next, the controller also has a setItemQuantity function:

setItemQuantity(itemNumber,newQuantity){
      if(this.itemList[itemNumber]){
            this.itemList[itemNumber].itemQuantity = newQuantity;
            this.updateView();
    }
} 

Whenever data (quanitity of item) in the shopping cart model is to be updated by a person, the setItemQuantity function in the controller is invoked. It finds the itemNumber of the item whose information is to be changed. If the item exists, it updates its quantity. Since the data in the model has changed, the view is also updated by invoking the updateView function.


Let’s discuss the MVP pattern in the next lesson.