Objects: Meal Maker - setters don't fill arrays with objects

My question is: why my setters are not working? They seem not to push new objects but instead reassing whole appetizers, mains and desserts objects…

exercise: https://www.codecademy.com/paths/web-development/tracks/web-dev-js-arrays-loops-objects/modules/learn-javascript-objects/projects/meal-maker

const menu = {
  _courses: {
    appetizers: [],
    mains: [],
    desserts: [],
  },
  
  get appetizers() {
    return this.appetizers;
  },
  set appetizers(appetizer) {
    this.appetizers.push(appetizer);
  },
  
  get mains() {
    return this.mains;
  },
  set mains(main) {
    this.mains.push(main);
  },
  
  get desserts() {
    return this.desserts;
  },
  set desserts(dessert) {
    this.desserts.push(dessert);
  },
  
  get courses() {
    return {
      appetizers: this._courses.appetizers,
      mains: this._courses.mains,
      desserts: this._courses.desserts,
    };
  },
  
  addDishToCourse(courseName, dishName, dishPrice) {
    const dish = {
      name: dishName,
      price: dishPrice,
      };
    //this._courses[courseName].push(dish);
    this._courses[courseName] = dish;
  },
  
  getRandomDishFromCourse(courseName) {
    const dishes = this._courses[courseName];
    const index = Math.floor(Math.random() * dishes.length);
    return dishes[index];
  },
  
  generateRandomMeal() {
    const appetizer = this.getRandomDishFromCourse('appetizers');
    const main = this.getRandomDishFromCourse('mains');
    const dessert = this.getRandomDishFromCourse('desserts');
    const totalPrice = Math.round((appetizer.price + main.price + dessert.price) * 100) / 100;
    return (`Your meal:\n${appetizer.name}: ${appetizer.price}$;\n${main.name}: ${main.price}$;\n${dessert.name}: ${dessert.price}$;\nTotal price: ${totalPrice}$`);
  },
};

menu.addDishToCourse('appetizers', 'Salad', 1.25);
menu.addDishToCourse('appetizers', 'Panini', 3.15);
menu.addDishToCourse('appetizers', 'Ham', 2.10);
menu.addDishToCourse('mains', 'Chicken', 10.10);
menu.addDishToCourse('mains', 'Fish', 15.25);
menu.addDishToCourse('mains', 'Rabbit', 22.99);
menu.addDishToCourse('desserts', 'Panna cotta', 7.99);
menu.addDishToCourse('desserts', 'Rice', 3.99);
menu.addDishToCourse('desserts', 'Ice Cream', 3.50);
console.log(menu);
meal = menu.generateRandomMeal();
console.log(meal);

Output:

{ _courses: 
   { appetizers: { name: 'Ham', price: 2.1 },
     mains: { name: 'Rabbit', price: 22.99 },
     desserts: { name: 'Ice Cream', price: 3.5 } },
  appetizers: [Getter/Setter],
  mains: [Getter/Setter],
  desserts: [Getter/Setter],
  courses: [Getter],
  addDishToCourse: [Function: addDishToCourse],
  getRandomDishFromCourse: [Function: getRandomDishFromCourse],
  generateRandomMeal: [Function: generateRandomMeal] }
/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:56
    const totalPrice = Math.round((appetizer.price + main.price + dessert.price) * 100) / 100;
                                            ^

TypeError: Cannot read property 'price' of undefined
    at Object.generateRandomMeal (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:56:45)
    at Object.<anonymous> (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:71:13)
    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)

this in the above is in menu context, not _courses.

this._courses.appetizers.push(appetizer);

@mtf thanks for reply! :slight_smile: still this line didn’t fix my problem - only last items are being added to _courses - please see below console log.

Maybe you can run this code yourself and confirm issue still exists? :slight_smile:

console.log(menu)

{ _courses: 
   { appetizers: { name: 'Ham', price: 2.1 },
     mains: { name: 'Rabbit', price: 22.99 },
     desserts: { name: 'Ice Cream', price: 3.5 } },
(...)

Below is my code that includes your idea this._courses.appetizers.push(appetizer);

const menu = {
  _courses: {
    appetizers: [],
    mains: [],
    desserts: [],
  },
  
  get appetizers() {
    return this.appetizers;
  },
  set appetizers(appetizer) {
    this._courses.appetizers.push(appetizer);
  },
  
  get mains() {
    return this.mains;
  },
  set mains(main) {
    this._courses.mains.push(main);
  },
  
  get desserts() {
    return this.desserts;
  },
  set desserts(dessert) {
    this._courses.desserts.push(dessert);;
  },
  
  get courses() {
    return {
      appetizers: this._courses.appetizers,
      mains: this._courses.mains,
      desserts: this._courses.desserts,
    };
  },
  
  addDishToCourse(courseName, dishName, dishPrice) {
    const dish = {
      name: dishName,
      price: dishPrice,
      };
    //this._courses[courseName].push(dish);
    this._courses[courseName] = dish;
  },
  
  getRandomDishFromCourse(courseName) {
    const dishes = this._courses[courseName];
    const index = Math.floor(Math.random() * dishes.length);
    return dishes[index];
  },
  
  generateRandomMeal() {
    const appetizer = this.getRandomDishFromCourse('appetizers');
    const main = this.getRandomDishFromCourse('mains');
    const dessert = this.getRandomDishFromCourse('desserts');
    const totalPrice = Math.round((appetizer.price + main.price + dessert.price) * 100) / 100;
    return (`Your meal:\n${appetizer.name}: ${appetizer.price}$;\n${main.name}: ${main.price}$;\n${dessert.name}: ${dessert.price}$;\nTotal price: ${totalPrice}$`);
  },
};

menu.addDishToCourse('appetizers', 'Salad', 1.25);
menu.addDishToCourse('appetizers', 'Panini', 3.15);
menu.addDishToCourse('appetizers', 'Ham', 2.10);
menu.addDishToCourse('mains', 'Chicken', 10.10);
menu.addDishToCourse('mains', 'Fish', 15.25);
menu.addDishToCourse('mains', 'Rabbit', 22.99);
menu.addDishToCourse('desserts', 'Panna cotta', 7.99);
menu.addDishToCourse('desserts', 'Rice', 3.99);
menu.addDishToCourse('desserts', 'Ice Cream', 3.50);
console.log(menu);
meal = menu.generateRandomMeal();
console.log(meal);

The setters are the culprit. For now, revert to using push inside the add meal to course method and forget the setters.

I finally did it! :slight_smile: The correct solution is simple and so obvious now! We need to change last line in addDishToCourse() to properly use defined setters:

this[courseName] = dish; // not this._courses[courseName] = dish;

And it works!

1 Like

Great that you didn’t give up and kept digging into the context issue.

@design0971970542 Thanks for posting this. I was encountering the same issue when trying to use my setter methods.

@mtf can you possibly explain why his solution works? what was the issue and why does the bracket notation following the “this” reference fix the issue? Why didn’t the “this._courses[courseName] = dish;” work?

It depends where the _courses object is closed. In the example here, it closes immediately after the property list.

  _courses: {
    appetizers: [],
    mains: [],
    desserts: [],
  },

That puts the getters and setters in menu context. So long as the getter/setter are referencing the properties of _courses they will still work from that context.

It is one way of writing this code, but not the only way. Context is a primary concern.

1 Like