TypeError: Cannot read property 'push' of undefined

Link:
https://www.codecademy.com/courses/introduction-to-javascript/projects/meal-maker?action=resume_content_item

I’ve tried fixing my code a number of times. I’ve thrown it into repl.it mostly, to no avail.
The replit error is the following


TypeError: Cannot read property ‘push’ of undefined
at Object.addDishToCourse:68:36
at eval:100:6
at eval
at new Promise

I’ve checked Meal maker forums, but I haven’t quite found what I’m doing wrong. I’ve stared so long, I’m not sure if it’s just a syntax error, or if I’ve left out a large swath of code. Help, I really need another set of eyes on this :confused:

//#11 Do this next -> Generate Random Meal from Course 
// creates menu object
const menu = {
  _courses : {
    _appetizers:[ 'garlic bread', '$11.50'],
    _mains:['macaroni and cheese', '$23.40'],
    _desserts:['bluebell yogurt', '$62.10'],

// gets coursenames from the menu AkA getter for courses property
  get courses(){
  return this._courses = {
  _appetizers: this._courses._appetizers,
  _mains:this._courses._mains,
  _desserts: this._courses._desserts
  };
  },


//Getter and setter methods for courses *****\/*****
get appetizers(){
  return this._courses._appetizers;
},

get mains(){
    return this._courses._mains;
    },

get desserts(){
    return this._courses._desserts;
    },

set appetizers(appetizerIn){  
  if (typeof appetizerIn === 'string'){ 
  this._appetizers.push(appetizerIn)
  };
},

set mains(mainsIn){  
  if (typeof mainsIn ==='string'){
  this._mains.push(mainsIn)
  }

  else
  console.log('error');

  return

},

set desserts(dessertsIn){ 
  if (typeof dessertsIn ==='string'){
  this._desserts.push(dessertsIn)
  }
  else
    console.log('error');
    return
},

},
//Getter and setter methods for courses *****/\*****


 addDishToCourse(courseName,dishName,dishPrice){
    const dish = {
      _name: dishName,
      _price: dishPrice
    };
    this._courses[this.courseName].push(dish);
  },



 //Generate Random Dish from Course #10 Do this here
getRandomDishFromCourse(courseName){
const dishes = this._courses[courseName];
const randomIndex = [Math.floor(Math.random()*dishes.length)]-1;
return this._courses.courseName[randomIndex];
},

 //Generate Random Meal
 // fix name in "appetizer.name"

generateRandomMeal () {
 const appetizer = this.getRandomDishFromCourse('appetizers');
 const mains = this.getRandomDishFromCourse('mains');
 const desserts = this.getRandomDishFromCourse('desserts');
 const totalPrice = appetizer.price + mains.price + desserts.price;

 return `the total cost of your meal is ${totalPrice}. Your meal includes ${appetizer._name} `
},


};


console.log(menu._courses._appetizers)
console.log(menu._courses._mains)
console.log(menu._courses._desserts)

menu.addDishToCourse('appetizers','soup','$13.22');
menu.addDishToCourse('appetizers','garlic bread','$3.22');
menu.addDishToCourse('mains','rice and chicken','20.00');
menu.addDishToCourse('mains','roti','22.50');
menu.addDishToCourse('desserts','green tea icecream','$2.25');
menu.addDishToCourse('desserts','ice cream','$9.00');

const randomMeal = menu.generateRandomMeal();

console.log(randomMeal);

1 Like

This error message is telling us that the object we are calling it upon does not exist or is undefined. The error traces back to,

 addDishToCourse(courseName,dishName,dishPrice){
    const dish = {
      _name: dishName,
      _price: dishPrice
    };
    this._courses[this.courseName].push(dish);
  },

The question is, do we need backing variables in this temporary object?

2 Likes

by Backing Variable are you referring to the underscore prepended to ‘name’ and ‘price’ properties? I removed them but still have similar results. I also tried removing it from courses. Same result.

1 Like

Yes. There are no getters or setters in that object, so a backing variable is out of place. Just make it a plain object.

Next hint: Does courseName have a context when given as an argument (in this instance)?

I refer to this line in your code…

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

courseName is a string. and the above line treats it like a class instance property.


You may wish to log out your menu.courses object…

{ appetizers: 
   [ { name: 'partytray', price: 100 },
     { name: 'wings', price: 6.5 },
     { name: 'chips', price: 3 },
     { name: 'pretzel', price: 5 } ],
  mains: 
   [ { name: 'pizza', price: 12 },
     { name: 'burger', price: 9 },
     { name: 'pasta', price: 12 } ],
  desserts: 
   [ { name: 'pie', price: 3 },
     { name: 'cake', price: 3 },
     { name: 'cookie', price: 2.5 } ] }

to confirm the structure exists as expected. Note the plain attribute names.

The above has been produced with getters…

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

mtf, you’ve been a great help! I think I’ve fixed/changed some code, but the problem seems to have resurfaced.

My “GenerateRandomMeal” function and “getRandomDishFromCourse” are showing another Type Error I can’t seem to resolve.

TypeError: Cannot read property ‘getRandomDishFromCourse’ of undefined

Why do my functions keep returning undefined? I thought my return commands made sense…but javascript thinks otherwise…:sweat:

//#11 Do this next -> Generate Random Meal from Course 
// creates menu object
const menu = {
  _courses: {
    appetizers:[
      {name:'garlic bread', price:'11.50'},
      {name:'flat bread', price:'13.50'}],
    mains:[
      {name:'macaroni and cheese', price:'23.40'},
      {name:'rice noodles',price:'15.30'}],
    desserts:[
      {name:'bluebell yogurt',price:'62.10'},
      {name:'banana pudding', price:'6.10'}],

// gets coursenames from the menu AkA getter for courses property
  get courses(){
  return this._courses = {
  _appetizers: this._courses._appetizers,
  _mains:this._courses._mains,
  _desserts: this._courses._desserts
  };
  },


//Getter and setter methods for courses *****\/*****
get _appetizers(){
  return this._courses.appetizers;
},

get _mains(){
    return this._courses.mains;
    },

get _desserts(){
    return this._courses.desserts;
    },

set _appetizers(appetizerIn){  
  if (typeof appetizerIn === 'string'){ 
  this.appetizers.push(appetizerIn)
  };
},

set _mains(mainsIn){  
  if (typeof mainsIn ==='string'){
  this.mains.push(mainsIn)
  }

  else
  console.log('error');

  return

},

set _desserts(dessertsIn){ 
  if (typeof dessertsIn ==='string'){
  this.desserts.push(dessertsIn)
  }
  else
    console.log('error');
    return
},

},
//Getter and setter methods for courses *****/\*****


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



 //Generate Random Dish from Course #10 Do this here
getRandomDishFromCourse(courseName){
const dishes = menu._courses[courseName];
const randomIndex = [Math.floor(Math.random()*dishes.length)];//"-1" removed from formula- re-add if needed
return dishes[randomIndex];
},

 //Generate Random Meal
 
generateRandomMeal(){
 //Get Object Properties
 const appetizerName = this.menu.getRandomDishFromCourse('appetizers').name;
 const mainsName = this.menu.getRandomDishFromCourse('mains').name;
 const dessertName = this.menu.getRandomDishFromCourse('desserts').name;
 
 const appetizerPrice = Number(this.menu.getRandomDishFromCourse('appetizers').price);
 const mainsPrice = Number(this.menu.getRandomDishFromCourse('mains').price);
 const dessertPrice = Number(this.menu.getRandomDishFromCourse('desserts').price);

 const totalPrice = appetizerPrice + mainsPrice + dessertPrice;
 

 // return `the total cost of your meal is $ ${totalPrice}. Your meal includes $ ${appetizerName},$ ${mainsPrice},$ ${dessertPrice} `
return  console.log(appetizerName) //dessertPrice totalPrice;
}, 

};

console.log(menu.getRandomDishFromCourse('appetizers').name);
console.log(menu.getRandomDishFromCourse('mains').price);

console.log(menu.getRandomDishFromCourse('desserts').name)
console.log(menu.getRandomDishFromCourse('desserts').price);

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

It looks as though the attributes need to be backing variables.


Bear in mind, an out of the box program wouldn’t have any data stored.

_appetizers: []

Now we use a method to add items to the array. That method will call upon the getter for this attribute.

menu._courses.appetizers.push(item)

It Works!
I had some extra “This” commands in my generateRandomMeal() function this whole time :confounded:

Once I took em out, it worked!! :grin:

Thanks for the guidance. I added data to the courses when I was testing it out and never bothered to remove it.

Thanks again @mtf