Challenge: Solution Review
This lesson will explain the solution to the problem from the last coding challenge.
We'll cover the following
Solution #
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.