patternjavascriptMinor
Simple restaurant menu
Viewed 0 times
menusimplerestaurant
Problem
As stated in the title, the code produces a simple drop-down menu that allows you to select your
`$(document).ready(function() {
//Variables
var selectedStarter = {
dish: "(None)",
price: 0
};
var selectedMain = {
dish: "(None)",
price: 0
};
var selectedDessert = {
dish: "(None)",
price: 0
};
var starter = {
firstDish: "Salad",
firstDishPrice: 15,
secondDish: "Soup",
secondDishPrice: 7,
thirdDish: "Fish rolls",
thirdDishPrice: 12
};
var main = {
firstDish: "Steak",
firstDishPrice: 17,
secondDish: "Salmon",
secondDishPrice: 12,
thirdDish: "Rissotto",
thirdDishPrice: 9
};
var dessert = {
firstDish: "Sorbet",
firstDishPrice: 4,
secondDish: "Fruit salad",
secondDishPrice: 6,
thirdDish: "Apple pie",
thirdDishPrice: 5
};
function total() {
return selectedStarter.price + selectedMain.price + selectedDessert.price;
}
function selectedStarterFnc(dish, price) {
selectedStarter.price = price;
selectedStarter.dish = dish;
$("#total").html(total());
return dish + "(" + price + ")";
}
function selectedMainFnc(dish, price) {
selectedMain.price = price;
selectedMain.dish = dish;
$("#total").html(total());
return dish + "(" + price + ")";
}
function selectedDessertFnc(dish, price) {
selectedDessert.price = price;
selectedDessert.dish = dish;
$("#total").html(total());
return dish + "(" + price + ")";
}
// Instantiating HTML Button Elements
// Starter Elements
document.getElementById("btStarter1").value =
starter.firstDish + ": " + starter.firstDishPrice;
document.getElementById("btStarter2").value =
starter.secondDish + ": " + starter.secondDishPrice;
document.getElementById("btStarter3").value =
starter.thirdDish + ": " + starter.thirdDishPrice;
// Mai
Starter, Main and Dessert courses, and will show your order in a small box underneath (like a bill).`$(document).ready(function() {
//Variables
var selectedStarter = {
dish: "(None)",
price: 0
};
var selectedMain = {
dish: "(None)",
price: 0
};
var selectedDessert = {
dish: "(None)",
price: 0
};
var starter = {
firstDish: "Salad",
firstDishPrice: 15,
secondDish: "Soup",
secondDishPrice: 7,
thirdDish: "Fish rolls",
thirdDishPrice: 12
};
var main = {
firstDish: "Steak",
firstDishPrice: 17,
secondDish: "Salmon",
secondDishPrice: 12,
thirdDish: "Rissotto",
thirdDishPrice: 9
};
var dessert = {
firstDish: "Sorbet",
firstDishPrice: 4,
secondDish: "Fruit salad",
secondDishPrice: 6,
thirdDish: "Apple pie",
thirdDishPrice: 5
};
function total() {
return selectedStarter.price + selectedMain.price + selectedDessert.price;
}
function selectedStarterFnc(dish, price) {
selectedStarter.price = price;
selectedStarter.dish = dish;
$("#total").html(total());
return dish + "(" + price + ")";
}
function selectedMainFnc(dish, price) {
selectedMain.price = price;
selectedMain.dish = dish;
$("#total").html(total());
return dish + "(" + price + ")";
}
function selectedDessertFnc(dish, price) {
selectedDessert.price = price;
selectedDessert.dish = dish;
$("#total").html(total());
return dish + "(" + price + ")";
}
// Instantiating HTML Button Elements
// Starter Elements
document.getElementById("btStarter1").value =
starter.firstDish + ": " + starter.firstDishPrice;
document.getElementById("btStarter2").value =
starter.secondDish + ": " + starter.secondDishPrice;
document.getElementById("btStarter3").value =
starter.thirdDish + ": " + starter.thirdDishPrice;
// Mai
Solution
Let me first warn you that you have fallen into a classic anti-pattern. When you see yourself tempted to write code that starts naming variables/objects/item with names like
Also you have a lot of repetitive code that you can refactor out.
You need to begin to come to terms that jQuery is especially powerful at dealing with collections of DOM elements. So again, when you begin doing things like make element ID's like
Finally, you really haven't embraced an "object oriented" paradigm at all, which is something that could really help organize your code. I will show you an alternate implementation that you might find helps prompt some different thinking.
This may seem like a lot of code, but you might find this sort of approach helpful over the long term with regards to being able to more easily maintain and reuse this code.
The approach:
Example:
```
// build Dish class
function Dish(name, price) {
// not shown - you should validate proper data types and values
// for name(string) and price(int or float, positive value, etc.)
this.name = name;
this.price = price;
// in future you might add other properties here (ingredients, picture URL's, etc.)
}
// add methods to the Dish prototype to expose dish behavior
Dish.prototype = {
// not currently used
};
// build Menu class to store menu information
function Menu() {
this.categories = [];
this.menuTree = {};
}
// add methods to the Menu prototype to expose menu behavior
Menu.prototype = {
addCategory: function addCategory(category) {
// not shown - you should validate proper data type
// for category(string)
// add category to menu tree
this.menuTree[category] = [];
// add category to list of categories on Menu
this.categories.push(category);
// return the object for method chaining
return this;
},
addDish: function addDish(dish, category) {
if(dish instaceof Dish === false) {
console.log('Need to pass a Dish object.');
return null;
}
// if category was not passed, use last category added
if(category === undefined) {
var lastCatArray = this.categories.slice(-1);
category = lastCatArray[0];
}
this.menuTree[category].push(dish);
return this;
}
}
// build object to define an orderable Meal
// we will later use this class when rendering the menu selection
// this simple example assumes that the meas consists of one item from
// each menu category
function Meal(menu) {
// not shown - validate valid menu object is passed
// set menu object in this class
this.menu = menu;
// object to store current menu selections
this.menuSelections = {};
// build out "slots" to hold menu selections
this.menu.categories.forEach(function (value, index) {
this.menuSelections[value] = null;
});
}
// add methods to Meal
Meal.prototype = {
selectCourseOption: function(course, dish) {
// not shown - validate course and dish parameters
this.menuSelections[course] = dish;
return this;
},
getMealCost: function() {
var totalCost = 0;
for (course in this.menuSelections) {
totalCost += this.menuSelections[course].price;
}
return totalCost;
}
}
// create class to render HTML view necessary for meal selection
function MealSelectionHTMLFactory(meal, config) {
// not shown - validate valid Meal object passed
this.meal = meal;
// extend/override default config if if anything passed
// not currently used
this.config = $.extend(this.config, config);
}
MealSelectionHTMLFactory.prototype = {
// store some base config for rendering
// we apply this at prototype level,
// as we want to apply to all instances of this class
this.config = {
// Not used currently. It could be good idea to put things
// such as default DOM element id and class names into this
// config such that they are not hard coded into the jQuery
// DOM element generation code in this class.
},
renderMenuDOM(targetSelector) {
// local variable to use as handle to menu tree
var menuTree = this.meal.menu.menuTree;
// start building elements for DOM inserting
btStarter (with being numbers), usually this means you should be thinking of these things as an array.Also you have a lot of repetitive code that you can refactor out.
You need to begin to come to terms that jQuery is especially powerful at dealing with collections of DOM elements. So again, when you begin doing things like make element ID's like
btStarter* this probably means you should be dealing with the collections of buttons logically using the same class.Finally, you really haven't embraced an "object oriented" paradigm at all, which is something that could really help organize your code. I will show you an alternate implementation that you might find helps prompt some different thinking.
This may seem like a lot of code, but you might find this sort of approach helpful over the long term with regards to being able to more easily maintain and reuse this code.
The approach:
- Put your logic into classes and import via include file that you load in document header. This also enables this logic to be transportable. You need to create another menu page? Just include this file.
Example:
```
// build Dish class
function Dish(name, price) {
// not shown - you should validate proper data types and values
// for name(string) and price(int or float, positive value, etc.)
this.name = name;
this.price = price;
// in future you might add other properties here (ingredients, picture URL's, etc.)
}
// add methods to the Dish prototype to expose dish behavior
Dish.prototype = {
// not currently used
};
// build Menu class to store menu information
function Menu() {
this.categories = [];
this.menuTree = {};
}
// add methods to the Menu prototype to expose menu behavior
Menu.prototype = {
addCategory: function addCategory(category) {
// not shown - you should validate proper data type
// for category(string)
// add category to menu tree
this.menuTree[category] = [];
// add category to list of categories on Menu
this.categories.push(category);
// return the object for method chaining
return this;
},
addDish: function addDish(dish, category) {
if(dish instaceof Dish === false) {
console.log('Need to pass a Dish object.');
return null;
}
// if category was not passed, use last category added
if(category === undefined) {
var lastCatArray = this.categories.slice(-1);
category = lastCatArray[0];
}
this.menuTree[category].push(dish);
return this;
}
}
// build object to define an orderable Meal
// we will later use this class when rendering the menu selection
// this simple example assumes that the meas consists of one item from
// each menu category
function Meal(menu) {
// not shown - validate valid menu object is passed
// set menu object in this class
this.menu = menu;
// object to store current menu selections
this.menuSelections = {};
// build out "slots" to hold menu selections
this.menu.categories.forEach(function (value, index) {
this.menuSelections[value] = null;
});
}
// add methods to Meal
Meal.prototype = {
selectCourseOption: function(course, dish) {
// not shown - validate course and dish parameters
this.menuSelections[course] = dish;
return this;
},
getMealCost: function() {
var totalCost = 0;
for (course in this.menuSelections) {
totalCost += this.menuSelections[course].price;
}
return totalCost;
}
}
// create class to render HTML view necessary for meal selection
function MealSelectionHTMLFactory(meal, config) {
// not shown - validate valid Meal object passed
this.meal = meal;
// extend/override default config if if anything passed
// not currently used
this.config = $.extend(this.config, config);
}
MealSelectionHTMLFactory.prototype = {
// store some base config for rendering
// we apply this at prototype level,
// as we want to apply to all instances of this class
this.config = {
// Not used currently. It could be good idea to put things
// such as default DOM element id and class names into this
// config such that they are not hard coded into the jQuery
// DOM element generation code in this class.
},
renderMenuDOM(targetSelector) {
// local variable to use as handle to menu tree
var menuTree = this.meal.menu.menuTree;
// start building elements for DOM inserting
Code Snippets
// build Dish class
function Dish(name, price) {
// not shown - you should validate proper data types and values
// for name(string) and price(int or float, positive value, etc.)
this.name = name;
this.price = price;
// in future you might add other properties here (ingredients, picture URL's, etc.)
}
// add methods to the Dish prototype to expose dish behavior
Dish.prototype = {
// not currently used
};
// build Menu class to store menu information
function Menu() {
this.categories = [];
this.menuTree = {};
}
// add methods to the Menu prototype to expose menu behavior
Menu.prototype = {
addCategory: function addCategory(category) {
// not shown - you should validate proper data type
// for category(string)
// add category to menu tree
this.menuTree[category] = [];
// add category to list of categories on Menu
this.categories.push(category);
// return the object for method chaining
return this;
},
addDish: function addDish(dish, category) {
if(dish instaceof Dish === false) {
console.log('Need to pass a Dish object.');
return null;
}
// if category was not passed, use last category added
if(category === undefined) {
var lastCatArray = this.categories.slice(-1);
category = lastCatArray[0];
}
this.menuTree[category].push(dish);
return this;
}
}
// build object to define an orderable Meal
// we will later use this class when rendering the menu selection
// this simple example assumes that the meas consists of one item from
// each menu category
function Meal(menu) {
// not shown - validate valid menu object is passed
// set menu object in this class
this.menu = menu;
// object to store current menu selections
this.menuSelections = {};
// build out "slots" to hold menu selections
this.menu.categories.forEach(function (value, index) {
this.menuSelections[value] = null;
});
}
// add methods to Meal
Meal.prototype = {
selectCourseOption: function(course, dish) {
// not shown - validate course and dish parameters
this.menuSelections[course] = dish;
return this;
},
getMealCost: function() {
var totalCost = 0;
for (course in this.menuSelections) {
totalCost += this.menuSelections[course].price;
}
return totalCost;
}
}
// create class to render HTML view necessary for meal selection
function MealSelectionHTMLFactory(meal, config) {
// not shown - validate valid Meal object passed
this.meal = meal;
// extend/override default config if if anything passed
// not currently used
this.config = $.extend(this.config, config);
}
MealSele$(document).ready(function() {
// build your actual menu
var menu = new Menu();
menu.addCategory('Starter')
.addDish(new Dish('Salad', 15))
// repeat for other dishes in this category
.addDish(...);
menu.addCategory('Main')
// add dishes to this category as shown above
.addDish(...);
menu.addCategory('Dessert')
// add dishes to this category as shown above
.addDish(...);
// create Meal instance
var meal = new Meal(menu);
// render menu view
var factory = MealSelectionHTMLFactory(meal);
factory.renderMenu('body');
}<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Restaurant Menu With JQuery</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://yourdomain/path/to/jsincludes.js"></script>
</head>
<body></body>Context
StackExchange Code Review Q#131875, answer score: 3
Revisions (0)
No revisions yet.