Meal Maker project Error

Working on the meal maker project in the objects portion of the javascript course. https://www.codecademy.com/courses/introduction-to-javascript/projects/meal-maker

const menu = {
  _courses: {
    appetizers: [],
    mains: [],
    desserts: [],
  },

  get appetizers () {
    return this._courses.appetizers;
  },
  set appetizers(appIn){
    this._courses.appetizers = appIn;
  },
  get mains () {
    return this._courses.mains;
  },
  set mains (mainIn) {
    this._courses.mains = mainIn;
  },
  get desserts () {
    return this._courses.desserts;
  },
  set desserts (dessertIn) {
    this._courses.desserts = dessertIn;
  },
  get _courses() {
    return {
      appetizers: this.appIn,
      mains: this.mainIn,
      desserts: this.dessertIn
    }
  },
  addDishToCourse: function (courseName, dishName, dishPrice) {
    const dish = {
      name: dishName,
      price: dishPrice,
    };
    return this._courses[courseName].push(dish);
  },
  getRandomDishFromCourse: function (courseName) {
    const dishes = this._courses[courseName];
    const index = Math.floor(Math.random() * dishes.length)
    return dishes[index];
  },
  generateRandomMeal: function () {
    let randApp = this.getRandomDishFromCourse('appetizers');
    let randMain = this.getRandomDishFromCourse('mains');
    let randDessert = this.getRandomDishFromCourse('desserts');
    let totalPrice = randApp.price + randMain.price + randDessert.price;

    return `Your meal for this evening is ${randApp.name} to start, followed by ${randMain.name}, and a lovely ${randDessert.name} to finish! This lovely meal for only ${totalPrice}.`;
  },
};


menu.addDishToCourse ('appetizers', 'Medjool Dates', 8);
menu.addDishToCourse ('mains', 'Roasted Half Chicken', 25);
menu.addDishToCourse ('desserts', 'Tres Leches Cake', 9);
menu.addDishToCourse ('appetizers', 'Brown-Butter Sage Gnocchi', 12);
menu.addDishToCourse ('mains', 'Glazed Beef Short-Rib', 30);
menu.addDishToCourse ('desserts', 'Lemon Semi-Fredo', 8);
menu.addDishToCourse ('appetizers', 'Roasted Squash and Kale Salad', 7);
menu.addDishToCourse ('mains', 'Bone-In Pork Chop', 20);
menu.addDishToCourse ('desserts', 'Cheesecake', 9);

const meal = menu.generateRandomMeal();
console.log(meal);

I keep getting an error on line 38:

addDishToCourse: function (courseName, dishName, dishPrice) {
    const dish = {
      name: dishName,
      price: dishPrice,
    };
    return this._courses[courseName].push(dish);

“TypeError: Cannot read property ‘push’ of undefined
at Object.addDishToCourse”

My code is identical to the guide, as far as I can tell, outside of me changing some variable names so that I dont have 8 freaking ‘appetizers.’ Can’t figure out why it thinks dish is undefined.

I believe I caught an error, my getter for courses was using the variable I set in my setters, so I changed that, but now it is giving me an error that basically means I have a recursive function somewhere??? What is wrong with my code. Here is the change I made:

get _courses() {
    return {
      appetizers: this.appetizers,
      mains: this.mains,
      desserts: this.desserts
    }
  },

This line:

invokes your getter:

There are a few problems here. First, your getter should not have the same name as the backing variable it is accessing. By convention, you would name the getter the same as the backing variable without the _. Naming it exactly the same, including the underscore, will result in a call stack error once you fix the code inside the getter which is the second problem.

When you look at your getter code, what is this referring to? It refers to menu, so is there such a property as menu.appetizers?

Edit: I didn’t fully read your most recent comment until after I finished this original reply. As currently written, when this.appetizers is reached, it invokes your appetizers getter, which then calls the _courses getter, which then calls the appetizers getter which then calls the _courses getter …

no, appetizers are a property of _courses, not menu. However, my getter is identical to the guide video, so what did he do differently to not run into this problem?

edit —
So I removed the underscore from my getter name and now my code runs perfectly. So if there is an issue with my getter code then is there a bug with the website? Also how exactly is return this._courses[courseName].push(dish); calling the getter when I use the name of the object and not the name of the getter method?

Hi @cvphelan!

You have an extra underscore on the courses getter!

If you remove that underscore like the one below, it should solve your problem :slight_smile:

get courses() {
    return {
      appetizers: this.appetizers,
      mains: this.mains,
      desserts: this.desserts
    }
  },

I hadn’t watched the video until just now (skimmed through it), but the video does not show including the underscore in the getter method for get courses(). Doing so would result in a call stack error as you’ve seen.

right, fixed the underscore, but the rest of my getter content is identical, but you’re saying that it shouldn’t work?

Also how exactly is return this._courses[courseName].push(dish); calling the getter when I use the name of the object and not the name of the getter method?

To answer your question:

The get syntax binds an object property to a function that will be called when that property is looked up.

more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get

In this case, when you are calling this._courses you are saying that you want it to then take the dish and use the courses function to populate the _courses keys.

I hope that helps!

sorry, I was always kinda fuzy on getters and setters when learning c# and now my brain is short circuiting because of how javascript does some things differently.

So, any time I call an object that has a getter, the get function is just automatically run, even though I am not specifically using the get functions name?

You are correct! Through all previous setters and getters, you have linked everything by telling your code how each function goes into the object. For example when you look at this snippet from your code you have linked everything to the object itself.

get desserts () {
    return this._courses.desserts;
  },
  set desserts (dessertIn) {
    this._courses.desserts = dessertIn;
  },
  get courses() {
    return {
      appetizers: this.appIn,
      mains: this.mainIn,
      desserts: this.dessertIn
    }
  }

You are telling the code to “get” the course function and use the desserts function to update the desserts properties in the object to the value that has been pushed in. Its a chain of functions that you have pre-programmed in the previous lines of code.

1 Like

Actually, this code:

bypasses the courses getter, and accesses menu._courses directly. It could use the getter though which would work just as well, and be more consistent.

that is what the course told me to do, so how would you do it differently? And how do we verify what exactly a “this” is referencing?

This project has been revamped since first introduced (it didn’t use the getters at all previously), but it could still use some tweaking in my opinion. this refers to the encompassing object, so in the case of your code, each use of this refers to menu. You could use the courses getter like so:

get appetizers() {
  return this.courses.appetizers;

You would have to re-write the courses getter though, or we’d be back to a circular reference. As written, the courses getter re-builds the _courses object by calling the individual getters. A bit silly in my opinion, when we could simply return the existing _courses object:

get courses() {
  return this._courses;
}

Don’t mind me though. It appears that you’ve written your code following the video and the instructions. The important thing is to gain an understanding of objects, backing variables, getters and setters.