Meal maker project

https://www.codecademy.com/paths/build-web-apps-with-react/tracks/bwa-javascript-iterators-objects-and-classes/modules/learn-javascript-objects/projects/meal-maker

I am trying to make this work but when I solve an error I get a new one. Can anyone help me out?

Here is my code

const menu = {
  _courses: {
    appetizers:[ ], 
    mains:[ ], 
    desserts:[ ]},
  get appetizers(){
    return this._courses.appetizers
  },
  set appetizers(appetizer){
    this._courses.appetizers.push(appetizer)
  },
  get mains(){
    return this._courses.mains
  },
  set mains(main){
    this._courses.mains.push(main)
  },
  get desserts(){
    return this._courses.desserts
  },
  set desserts(dessert){
    this._courses.desserts.push(dessert)
  },
  get _courses(){
    return{
      appetizers: this.appetizers,
      mains: this.mains,
      desserts: this.desserts
    }
  },
  addDishToCourse(courseName,dishName,dishPrice){
    const dish = {
      name: dishName,
      price: dishPrice,
    }
    return this._courses[courseName].push(dish);
  },
  getRandomDishFromCourse(courseName){
    const dishes = this._courses[courseName];
    let num = Math.floor(Math.random() * dishes.length);
    return dishes[num]
  },
  generateRandomMeal(){
    let appetizer = getRandomDishFromCourse('appetizers');
    let main = getRandomDishFromCourse('mains');
    let dessert = getRandomDishFromCourse('dessert');
    let totalPrice = appetizer.price + main.price + dessert.price;
    return `Your meal will consist of ${appetizer.name} for an appetizer, ${main.name} as the entree, and ${dessert.name} for dessert. The total price for this meal will be ${totalPrice}`
  }
}
menu.addDishToCourse('appetizer', 'dumplings', 10.50)

And this is my error

/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:25
return{
^

RangeError: Maximum call stack size exceeded
at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:25:5)
at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:7:16)
at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:26:23)
at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:7:16)
at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:26:23)
at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:7:16)
at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:26:23)
at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:7:16)
at Object.get _courses [as _courses] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:26:23)
at Object.get appetizers [as appetizers] (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:7:16)

Hi @lucandiray,

I’d love to help you however please make use of the </> to format your post where there’s code and describe exactly what problem you’re facing, thanks!

5 Likes

you have recursion, as you can see from the stack trace, this is caused by the getter endlessly calling itself

the reason we prefix the property (_courses) with an underscore is a convention to indicate the usage of a getter, and preventing recursion by having the getter without underscore (get courses())

5 Likes

It’s quite funny that the easiest way to correct this code is to simply remove this part of the code (it does nothing, really):

get appetizers() {
    return this._courses.appetizers
},
set appetizers(appetizer) {
    this._courses.appetizers.push(appetizer)
},
get mains() {
    return this._courses.mains
},
set mains(main) {
    this._courses.mains.push(main)
},
get desserts() {
    return this._courses.desserts
},
set desserts(dessert) {
    this._courses.desserts.push(dessert)
},
get _courses() {
    return {
        appetizers: this.appetizers,
        mains: this.mains,
        desserts: this.desserts
    }
},

:smiley:

For the Record

const menu = {
  _courses: {
    appetizers:[], 
    mains:[], 
    desserts:[]
  },
  get appetizers () {
    return this._courses.appetizers
  },
  set appetizers (appetizer) {
    this._courses.appetizers.push(appetizer)
  },
  get mains () {
    return this._courses.mains
  },
  set mains (main) {
    this._courses.mains.push(main)
  },
  get desserts () {
    return this._courses.desserts
  },
  set desserts (dessert) {
    this._courses.desserts.push(dessert)
  },
  get courses () { // _courses(){
    return {
      appetizers: this.appetizers,
      mains: this.mains,
      desserts: this.desserts
    }
  },
  addDishToCourse(courseName,dishName,dishPrice){
    const dish = {
      name: dishName,
      price: dishPrice,
    }
    //return 
    this._courses[courseName] = dish;//.push(dish);
  }
}
menu.addDishToCourse('appetizers', 'dumplings', 10.50)
console.log(menu.courses.appetizers)
{ name: 'dumplings', price: 10.5 }
1 Like

Thanks to everyone!:grinning: I feel kinda stupid for not using the obvious solution :sweat_smile: Any ideas for dishes?

New problem

const menu = {
  _courses: {
    appetizers:[], 
    mains:[], 
    desserts:[]},
  get appetizers(){
    return this._courses.appetizers
  },
  set appetizers(appetizer){
    this._courses.appetizers.push(appetizer)
  },
  get mains(){
    return this._courses.mains
  },
  set mains(main){
    this._courses.mains.push(main)
  },
  get desserts(){
    return this._courses.desserts
  },
  set desserts(dessert){
    this._courses.desserts.push(dessert)
  },
  get courses(){
    return{
      appetizers: this.appetizers,
      mains: this.mains,
      desserts: this.desserts
    }
  },
  addDishToCourse(courseName,dishName,dishPrice){
    const dish = {
      name: dishName,
      price: dishPrice,
    }
    return this._courses[courseName] = dish;
  },
  getRandomDishFromCourse(courseName){
    const dishes = this._courses[courseName];
    let num = Math.floor(Math.random() * dishes.length);
    return dishes[num]
  },
  generateRandomMeal(){
    let appetizer = this.getRandomDishFromCourse('appetizers');
    let main = this.getRandomDishFromCourse('mains');
    let dessert = this.getRandomDishFromCourse('dessert');
    const totalPrice = appetizer.price + main.price + dessert.price;
    return `Your meal will consist of ${appetizer.name} for an appetizer, ${main.name} as the entree, and ${dessert.name} for dessert. The total price for this meal will be $${totalPrice}`
  }
}
menu.addDishToCourse('appetizer', 'tempura vegetables', 6.50)
menu.addDishToCourse('appetizer', 'spring rolls', 6.00)
menu.addDishToCourse('appetizer', 'crab legs', 14.00)
menu.addDishToCourse('main', 'california rolls', 5.50)
menu.addDishToCourse('main', 'crab sashimi', 13.00)
menu.addDishToCourse('main', 'albacore sushi', 10.00)
menu.addDishToCourse('dessert', 'tiramisu', 10.00)
menu.addDishToCourse('dessert', 'sesame cookies', 7.00)
menu.addDishToCourse('dessert', 'cheesecake', 15.00)
menu.generateRandomMeal()

error

/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:47
const totalPrice = this.appetizer.price + this.main.price + this.dessert.price;
^

TypeError: Cannot read property ‘price’ of undefined
at Object.generateRandomMeal (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:47:38)
at Object. (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:60:6)
at Module._compile (module.js:571:32)
at Object.Module._extensions…js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.runMain (module.js:605:10)
at run (bootstrap_node.js:427:7)
at startup (bootstrap_node.js:151:9)

An error, yeah. Did you read it?

Does this:
TypeError: Cannot read property ‘price’ of undefined
Say anything about:

const totalPrice = this.appetizer.price
                   ^^^^^^^^^^^^^^

Be sure to pluralize so the names match existing attributes.

'appetizers'
'mains'
'desserts'
2 Likes

I pluralized the names and added the this. to the plurals and this is what it gives me.

Your meal will consist of undefined for an appetizer, undefined as the entree, and undefined for dessert. The total price for this meal will be $NaN

1 Like

I don’t get what you are saying

In the randomMeal method, appetizer, main and dessert are local variables that reference objects with a name and price attribute. No this needed.

Got rid of ‘this.’ Still not working found another forum that helped a little bit still have problems.

here is code

const menu = {
  _courses: {
    appetizers:[], 
    mains:[], 
    desserts:[]},
  get appetizers(){
    return this._courses.appetizers
  },
  set appetizers(appetizer){
    this._courses.appetizers.push(appetizer)
  },
  get mains(){
    return this._courses.mains
  },
  set mains(main){
    this._courses.mains.push(main)
  },
  get desserts(){
    return this._courses.desserts
  },
  set desserts(dessert){
    this._courses.desserts.push(dessert)
  },
  get courses(){
    return{
      appetizers: this.appetizers,
      mains: this.mains,
      desserts: this.desserts
    }
  },
  addDishToCourse(courseName,dishName,dishPrice){
    const dish = {
      name: dishName,
      price: dishPrice,
    }
    return this._courses[courseName] = dish;
  },
  getRandomDishFromCourse(courseName){
    const dishes = this._courses[courseName];
    console.log(dishes, courseName)
    const num = Math.floor(Math.random() * dishes.length);
    return dishes[num]
  },
  generateRandomMeal(){
    let appetizer = this.getRandomDishFromCourse('appetizers');
    let main = this.getRandomDishFromCourse('mains');
    let dessert = this.getRandomDishFromCourse('desserts');
    const totalPrice = appetizer.price + meal.price + dessert.price;
    return `Your meal will consist of ${appetizer.name} for an appetizer, ${main.name} as the entree, and ${dessert.name} for dessert. The total price for this meal will be $${totalPrice}`
  }
}
menu.addDishToCourse('appetizers', 'tempura vegetables', 6.50)
menu.addDishToCourse('appetizers', 'spring rolls', 6.00)
menu.addDishToCourse('appetizers', 'crab legs', 14.00)
menu.addDishToCourse('mains', 'california rolls', 5.50)
menu.addDishToCourse('mains', 'crab sashimi', 13.00)
menu.addDishToCourse('mains', 'albacore sushi', 10.00)
menu.addDishToCourse('desserts', 'tiramisu', 10.00)
menu.addDishToCourse('desserts', 'sesame cookies', 7.00)
menu.addDishToCourse('desserts', 'cheesecake', 15.00)
console.log(menu.generateRandomMeal())

now error

/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:48
    const totalPrice = appetizer.price + meal.price + dessert.price;
                                ^

TypeError: Cannot read property 'price' of undefined
    at Object.generateRandomMeal (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:48:33)
    at Object.<anonymous> (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:61:18)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.runMain (module.js:605:10)
    at run (bootstrap_node.js:427:7)
    at startup (bootstrap_node.js:151:9)```

return not needed. Just write the assignment.

As it turns out, that line is problematic (it’s not using the setter) so revert to your old code.

this._courses[courseName].push(dish);

Some time ago I had the setters and getters working but that code is not backed up in the lesson and I’m on a different computer. Hopefully this will work for you.

2 Likes

why? Understanding why you do something is very important.

Got it done! Thank you all! :grinning:

1 Like

Can anybody explain the reason for having us add the getters/setters? Or an alternate method of doing this using getters / setters would be very helpful. Having them in there just confused me for a bit - removed them all together to have success with the following:

const menu = {
  _courses: {
  appetizers: [],
  mains: [],
  desserts: []
},
  addDishToCourse: function (courseName,dishName,dishPrice) {
    let dish = {name: dishName, price: dishPrice}
    this['_courses'][courseName].push(dish);
  },
  getRandomDishFromCourse: function(courseName){
    let dishes = this['_courses'][courseName]
    let randomSelector = Math.floor(Math.random()*dishes.length)
    return dishes[randomSelector]
  
  },
  generateRandomMeal: function() {
    let appetizer = this.getRandomDishFromCourse('appetizers')
    let main = this.getRandomDishFromCourse('mains')
    let dessert = this.getRandomDishFromCourse('desserts')
    let bill = appetizer.price + main.price + dessert.price
    return `Your meal will begin with the ${appetizer.name} to be followed by the ${main.name} and finished with the ${dessert.name}.  The total bill will be $${bill}`
  }
}

menu.addDishToCourse('appetizers','Salad', 9)
menu.addDishToCourse('appetizers','Soup', 7)
menu.addDishToCourse('appetizers','Snack Plate', 12)
menu.addDishToCourse('mains','Duck',30)
menu.addDishToCourse('mains','Eggplant Parm', 22)
menu.addDishToCourse('mains','Roast Lamb', 35)
menu.addDishToCourse('desserts','Cake', 10)
menu.addDishToCourse('desserts','Pie', 9)
menu.addDishToCourse('desserts','Ice Cream', 7)
console.log(menu._courses)

const meal = menu.generateRandomMeal();

console.log(meal)

Thanks

Well because it is good habit to do so. You might forget them the next time :wink: .

in this exercise, the getters and setters implement mostly default behavior, so they do indeed not add much value. However, getters and setters do enable us to change the default behavior, for example you could do:

const example = {
   _a = [],
  get a(){ return this._a.join(' ') }
}

now a string is returned for representation purposes, while under the hood its an array. Can be useful

use getters and setters when you need them, just like everything else in programming, there isn’t one size fits all solution