Meal Maker undefined and NaN

Hi all,

First post on this forum, so happy new year to all!

I’m having a little trouble with the Meal Maker exercise in the Web Dev pathway (https://www.codecademy.com/paths/web-development/tracks/web-dev-js-arrays-loops-objects/modules/learn-javascript-objects/projects/meal-maker).

I’ve restarted from scratch twice now, but can’t get past the current error, which is that my random meal output returns ‘undefined’ for all selected dishes, and NaN (not a number) for the calculated price. I’ve had a look at four other threads on this topic but sadly not been able to resolve the issue.

I’ve checked the source arrays (_appetizers, _mains, _desserts) to make sure that they contain relevant values, and the console log returns indicate that they’re present.

I’ve added the outputs below, and my code below that - any advice would be greatly appreciated - many thanks in advance! - Mike

CONSOLE OUTPUT

Your meal is undefined, undefined, undefined. The total price is NaN.
[ { name: ‘Salad’, price: 4.95 },
{ name: ‘Soup’, price: 3.95 },
{ name: ‘Pate’, price: 6.95 } ]

CODE

const menu = {
  _courses: {
    _appetizers: [],
    _mains: [],
    _desserts: [],

    get appetizers () {
    return this._courses._appetizers;
  },
    set appetizers (appetizerIn) {
    },
    get mains () {
    return this._mains;
  },
    set mains (mainIn) {
    },
    get desserts () {
    return this._desserts;
  },
    set desserts (dessertIn) {
    },
  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,
    };
    if (courseName === 'appetizer') {
      this._courses._appetizers.push(dish)
    } else if (courseName === 'main') {
      this._courses._mains.push(dish)
    } else if (courseName === 'dessert') {
      this._courses._desserts.push(dish)
    } else {
      return 'Error - Course name must be \'appetizer\', \'main\', or \'dessert\'.'
    }
  },
  getRandomDishFromCourse (courseName) {
    const dishes = [];
    if (courseName === 'appetizer') {
      dishes.push(this._courses._appetizers)
     } else if (courseName === 'main') {
       dishes.push(this._courses._mains) 
     } else if (courseName === 'dessert') {
       dishes.push(this._courses._desserts)
     } else {
       return 'Error - Course name must be \'appetizer\', \'main\', or \'dessert\'.'
     }
    const randomIndex = Math.floor(Math.random() * dishes.length);
    return dishes[randomIndex];
  },
  generateRandomMeal () {
    const appetizer = this.getRandomDishFromCourse('appetizer');
    const main = this.getRandomDishFromCourse('main');
    const dessert = this.getRandomDishFromCourse('dessert');
    const price = appetizer.price + main.price + dessert.price;
    return `Your meal is ${appetizer.name}, ${main.name}, ${dessert.name}. The total price is ${price}.`;
  }
 };

menu.addDishToCourse('appetizer', 'Salad', 4.95);
menu.addDishToCourse('appetizer', 'Soup', 3.95);
menu.addDishToCourse('appetizer', 'Pate', 6.95);
menu.addDishToCourse('main', 'Chicken', 10.95);
menu.addDishToCourse('main', 'Fish', 12.95);
menu.addDishToCourse('main', 'Pasta', 9.95);
menu.addDishToCourse('dessert', 'Ice Cream', 3.95);
menu.addDishToCourse('dessert', 'Apple Pie', 3.95);
menu.addDishToCourse('dessert', 'Pancake', 2.95);

let meal = menu.generateRandomMeal();

console.log(meal)
console.log(menu._courses._appetizers)
1 Like

getRandomDishFromCourse should give a single dish from a specific course.

please read the instructions again (step 10)

lets do this one:

const appetizer = this.getRandomDishFromCourse('appetizer');

this means from your menu.courses.appetizer (which is an array), you need to fetch a single element.

not sure why you would push here, appetizer (and the other two) are already arrays.

1 Like

Many thanks for this - what I was attempting to do was populate the empty const dishes array with a given set of dishes, given the courseName input (i.e. whether ‘appetizers’, ‘mains’ etc.), then, use the random index to pull a random dish from this array (this is how I interpreted Step 10). From your advice it seems like this isn’t an appropriate use of .push. (I assumed .unshift and .push would have equivalent effects on an empty array).

I’ve now had a look at the result of getRandomDishFromCourse using console.log, and I can see that it does in fact return the array that matches menu._courses._appetizers, not a single element of that array. However, when I use console.log to return a single element of the menu._courses._appetizers array (say, [1]), I can pick out single element.

I went back to getRandomDishFromCourse and changed the ‘return dishes[randomIndex]’ to ‘return dishes’, which again gives me a copy of the ‘_appetizer’ array if I pass ‘appetizer’ to it as an argument. But if I change it to ‘return dishes[1];’ it throws an error on line 63.

What I can see is that I’ve basically unnecessarily replicated the same array several times (which if I’m understanding correctly is the point that you’re making) - but I’m not sure from here where to go, and I hope the above made some sense of my thinking here.

(p.s. I’ve tried to learn more about formatting my posts correctly, but when I try to access the following guidance link, I get a ‘You do not have access’ type error - https://discuss.codecademy.com/t/how-do-i-format-code-in-my-posts/51139)

ERROR

/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:63
const price = (appetizer.price + main.price + dessert.price);
^

TypeError: Cannot read property ‘price’ of undefined
at Object.generateRandomMeal (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:63:29)
at Object. (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:78:17)
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)

CODE


const menu = {
  _courses: {
    _appetizers: [],
    _mains: [],
    _desserts: [],

    get appetizers () {
    return this._courses._appetizers;
  },
    set appetizers (appetizerIn) {
    },
    get mains () {
    return this._mains;
  },
    set mains (mainIn) {
    },
    get desserts () {
    return this._desserts;
  },
    set desserts (dessertIn) {
    },
  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,
    };
    if (courseName === 'appetizer') {
      this._courses._appetizers.push(dish)
    } else if (courseName === 'main') {
      this._courses._mains.push(dish)
    } else if (courseName === 'dessert') {
      this._courses._desserts.push(dish)
    } else {
      return 'Error - Course name must be \'appetizer\', \'main\', or \'dessert\'.'
    }
  },
  getRandomDishFromCourse (courseName) {
    const dishes = [];
    if (courseName === 'appetizer') {
    dishes.push(this._courses._appetizers)
     } else if (courseName === 'main') {
    dishes.push(this._courses._mains) 
     } else if (courseName === 'dessert') {
    dishes.push(this._courses._desserts)
     } else {
       return 'Error - Course name must be \'appetizer\', \'main\', or \'dessert\'.'
     }
    const randomIndex = Math.floor(Math.random() * dishes.length);
    return dishes[1];
  },
  generateRandomMeal () {
    const appetizer = this.getRandomDishFromCourse('appetizer');
    const main = this.getRandomDishFromCourse('main');
    const dessert = this.getRandomDishFromCourse('dessert');
    const price = (appetizer.price + main.price + dessert.price);
    return `Your meal is ${appetizer.name}, ${main.name}, ${dessert.name}. The total price is ${price}.`;
  }
 };

menu.addDishToCourse('appetizer', 'Salad', 4.95);
menu.addDishToCourse('appetizer', 'Soup', 3.95);
menu.addDishToCourse('appetizer', 'Pate', 6.95);
menu.addDishToCourse('main', 'Chicken', 10.95);
menu.addDishToCourse('main', 'Fish', 12.95);
menu.addDishToCourse('main', 'Pasta', 9.95);
menu.addDishToCourse('dessert', 'Ice Cream', 3.95);
menu.addDishToCourse('dessert', 'Apple Pie', 3.95);
menu.addDishToCourse('dessert', 'Pancake', 2.95);

let meal = menu.generateRandomMeal();

console.log(meal);
console.log(menu._courses._appetizers);
console.log(menu.getRandomDishFromCourse('appetizer'));
console.log(menu._courses._appetizers[1]);

1 Like

what i am about to tell you for appetizers also applies for main and dessert

appetizers already is an array, so if we want a random appetizer we can just select it from the array:

if (courseName === 'appetizer') {
    	return this._courses._appetizers[randomIndex]

of course, you will still have to calculate randomIndex, but i hope you understand i leave something for you to do :slight_smile:

this seems like a good step, now you need to apply this to getRandomDishFromCourse. And please forget about push

1 Like

of course, you will still have to calculate randomIndex, but i hope you understand i leave something for you to do :slight_smile:

Completely, in fact I appreciate you taking the time to think about the right amount of information so that I still have something to solve (which means I’ll learn from it :slight_smile: ).

So (with some help) I seem to have solved the issue - here’s how I did it:

First step was correcting my understanding of what .push does, and why it isn’t appropriate in this case. I changed getRandomDishFromCourse so that it just gave me the array that my .push method was creating - turns out that it turns the appetizer array into a single object in the main dishes array, which is why dishes.length would return 1.

The main change was declaring dishes as var rather than const so that it was visible in the global scope outside of the object of the if... statements. The other change was taking your advice and picking a random dish from the existing this._courses.{coursetype} array rather than reproducing it unneccessarily using .push. Once I’d done that, I just had to add the randomIndex to each of the if... statements so that they referred to the length of the correct array.

Once this was done the undefined and NaN errors disappeared, and the example output was as below (I’ve also appended the final code). Again, many thanks for your help with this :slight_smile:

Your meal is Soup, Fish, Pancake. The total price is 19.85.

const menu = {
  _courses: {
    _appetizers: [],
    _mains: [],
    _desserts: [],

    get appetizers () {
    return this._courses._appetizers;
  },
    set appetizers (appetizerIn) {
    },
    get mains () {
    return this._mains;
  },
    set mains (mainIn) {
    },
    get desserts () {
    return this._desserts;
  },
    set desserts (dessertIn) {
    },
  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,
    };
    if (courseName === 'appetizer') {
      this._courses._appetizers.push(dish)
    } else if (courseName === 'main') {
      this._courses._mains.push(dish)
    } else if (courseName === 'dessert') {
      this._courses._desserts.push(dish)
    } else {
      return 'Error - Course name must be \'appetizer\', \'main\', or \'dessert\'.'
    }
  },
  getRandomDishFromCourse (courseName) {
    var dishes = [];
    if (courseName === 'appetizer') {
      const randomIndex = Math.floor(Math.random() * this._courses._appetizers.length);
      var dishes = this._courses._appetizers[randomIndex]
     } else if (courseName === 'main') {
      const randomIndex = Math.floor(Math.random() * this._courses._mains.length);
      var dishes = this._courses._mains[randomIndex]
     } else if (courseName === 'dessert') {
      const randomIndex = Math.floor(Math.random() * this._courses._desserts.length);
      var dishes = this._courses._desserts[randomIndex]
     } else {
       return 'Error - Course name must be \'appetizer\', \'main\', or \'dessert\'.'
     }
    return dishes;
  },
 generateRandomMeal () {
    const appetizer = this.getRandomDishFromCourse('appetizer');
    const main = this.getRandomDishFromCourse('main');
    const dessert = this.getRandomDishFromCourse('dessert');
    const price = appetizer.price + main.price + dessert.price;
    return `Your meal is ${appetizer.name}, ${main.name}, ${dessert.name}. The total price is ${price.toFixed(2)}.`;
  }
 };

menu.addDishToCourse('appetizer', 'Salad', 4.95);
menu.addDishToCourse('appetizer', 'Soup', 3.95);
menu.addDishToCourse('appetizer', 'Pate', 6.95);
menu.addDishToCourse('main', 'Chicken', 10.95);
menu.addDishToCourse('main', 'Fish', 12.95);
menu.addDishToCourse('main', 'Pasta', 9.95);
menu.addDishToCourse('dessert', 'Ice Cream', 3.95);
menu.addDishToCourse('dessert', 'Apple Pie', 3.95);
menu.addDishToCourse('dessert', 'Pancake', 2.95);

let meal = menu.generateRandomMeal();

console.log(meal);

var dishes = []; in your getRandomDishFromCourse is now redundant.

but for the rest, nicely done :slight_smile:

1 Like

var dishes = []; in your getRandomDishFromCourse is now redundant.

Ah I see, so it is, thanks :slight_smile: