Meal maker project

then very likely its not identical. I have been on the forum many years, generally its a small mistake somewhere. Please provide your code, so we can have a look.

1 Like

Thank you for your reply @stetim94 but I checked line by line with the video several times and it was in fact identical. I did however find out why it would not work for me, in the video he uses the following code (which I used originally and was getting an error)
getRandomDishFromCourse(courseName) {
const dishes = this._courses[courseName];

After changing my code to the following:

getRandomDishFromCourse: function (courseName) {
const dishes = this._courses[courseName];

the error went away. Not sure why the first code threw an error but it did.

getRandomDishFromCourse(courseName) { should work, I still really would like to see the code.

1 Like

Hi everyone,

I have been working on this same exercise linked in this very thread which was active up until only 2 days ago, so I thought it would be better for me to post my questions here rather than opening a whole new thread about the same issue. Please let me know if that was not the ideal thing to do, as I did read the rules of the forums and it seemed so. However, if I should post a new thread or do something different, please let me know and accept my apologies for the misunderstanding.

Now, funny enough, I made all work during my first day working on it. Which to be honest made me very happy. :slight_smile:

However, I rapidly noticed that I wasn’t using the setter. And in the hint of one of the steps, it states:

const menu = {
  ...
  addDishToCourse (courseName, ...) {
    const dish = {
      ...
    };
 
    this._courses[courseName].push(dish); // also try using your setter method!
  }
};

Notice that we’re being specifically requested to find a way to do this using the setter here.

1) My first doubt is rather theoretical: does it make sense to use a setter to add data to the already existing data? I mean, we’re not trying to set a property’s value or to set a new property, we’re trying to add an item to the already existing array, right? Aren’t setters used to set a value instead? I’ve been reading around and I can’t find any conclusive explanation about this specific point.

2) My second doubt, more specific, is about my way to do it. While I made it work very fast (considering my newbie circumstances) :slight_smile: once I tried to make the setter work, I found myself in trouble.

In other words, If I try to push the dish object from the method, there should be no problem.

But if I use the setter instead, it will always reassign the dish object, because instead of pushing the object to the array, I am setting it to this new value.

Like, for example, in:

set appetizers (){
        this._courses._appetizers.push(appetizer);
}

...


addDishToCourse (courseName, dishName, dishPrice){
        const dish = {
        name: dishName,
        price: dishPrice
        };
        return this._courses[courseName] = dish; // Whether I return or just assign/set, the result is the same here.
}

Now, there may be something obviously clear for an experienced developer, maybe, but I cannot see what I should do to attain this through the setter. I repeat: I only do this because it was asked in the hint of the project as explained above.

Could anybody be so kind as to shed some light on these two questions of mine?

Thanks in advance!

  1. Using a setter has advantages and drawbacks. You change the default assignment behavior of the property, which means data will always be appended to the array. This prevents accidentally overwriting the array property. However, it might not be immediately clear to someone else reading your code what you are doing.

  2. depends on if you make the setter part of the menu object or courses object. Can I see your full code?

1 Like

First of all, thank you so much for taking the time answer this!

Would you be so kind to explain to me how would it be possible to do (in this case) what you explained me in 1. and if it is better to do it that way or pushing directly from the method? Judging from the last part of your 1. answer, I guess this may not be recommendable?

I have to say, I’ve had various versions of the code by now, trying different things, but what I have right now is this without using the setter:

const menu = {
    _courses: {
      _appetizers: [],
      _mains: [],
      _desserts: []
    },
    get appetizers (){
        return this._courses._appetizers;
    },
    // set appetizers (appetizer){},
    get mains (){
        return this._courses._mains;
    },
    // set mains (main){},
    get desserts (){
        return this._courses._desserts;
    },
    // set desserts (dessert){},
    get courses (){
        const allCourses = this._courses._appetizers.concat(this._courses._mains, this._courses._desserts);
        let arrIndex = 0;
        const allCoursesObj = {};
        for (index of allCourses){
            allCoursesObj[arrIndex] = index;
            arrIndex++;
        }
        return allCoursesObj;
    },
    addDishToCourse (courseName, dishName, dishPrice){
        const dish = {
        name: dishName,
        price: dishPrice
        };
        this[courseName].push(dish);
    },
    getRandomDishFromCourse (courseName){
        let dishes = this.[courseName];
        let numOfDish = Math.floor(Math.random() * dishes.length);
        return dishes[numOfDish];
    },
    generateRandomMeal (){
        const appetizer = this.getRandomDishFromCourse('appetizers');
        const main = this.getRandomDishFromCourse('mains');
        const dessert = this.getRandomDishFromCourse('desserts');
        const totalPrice = appetizer.price + main.price + dessert.price;
        return `The meal includes as an appetizer: ${appetizer.name}, as a main dish: ${main.name}, and as a dessert: ${dessert.name}. The total cost is ${totalPrice}.`;
    }
};
    
menu.addDishToCourse('appetizers', 'salami', 12);
menu.addDishToCourse('appetizers', 'cheese sticks', 10);
menu.addDishToCourse('appetizers', 'french fries', 26);
menu.addDishToCourse('appetizers', 'tortilla', 20);

menu.addDishToCourse('mains', 'pasta', 90);
menu.addDishToCourse('mains', 'beef steak', 120);

menu.addDishToCourse('desserts', 'cake', 25);
menu.addDishToCourse('desserts', 'ice cream', 35);
menu.addDishToCourse('desserts', 'creppe', 40);

const meal = menu.generateRandomMeal();

console.log(meal);

This works perfectly. I’ve tried all the methods and also the getters and all of them work. Problem is, the hint was saying to “try using the setter”, like I said above, so I said, wait, maybe this is the wrong way, and then I tried a lot of things to make the setter work and I can’t. Below I paste the latest code I’ve tried to do it via setter.

Unless, of course, they say to try the setter just for us to see it won’t work? But I don’t think that is likely, right? I have to be missing something in my way of doing it (or trying to!).

This is when trying to use the setter:

Wait! … Actually: thank you for asking me to share the whole code, as when trying to share it with you, I did this: created two files, one doing it via the setter (below) and one doing it via the method (above)… and it seems it now works. This has taught me a new way to debug my own code!

I think I was getting tangled with the this, I had to check and modify each of the appearances of this and it now seems to work. Like you correctly pointed at with this:

Still, would you please tell me if the recommended/favorable way in situations like this one, to update/push or similar stuff via the setter or via a method?

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 (){
        const allCourses = this._courses._appetizers.concat(this._courses._mains, this._courses._desserts);
        let arrIndex = 0;
        const allCoursesObj = {};
        for (index of allCourses){
            allCoursesObj[arrIndex] = index;
            arrIndex++;
        }
        return allCoursesObj;
    },
    addDishToCourse (courseName, dishName, dishPrice){
        const dish = {
        name: dishName,
        price: dishPrice
        };
        this[courseName] = dish;
    },
    getRandomDishFromCourse (courseName){
        let dishes = this[courseName];
        let numOfDish = Math.floor(Math.random() * dishes.length);
        return dishes[numOfDish];
    },
    generateRandomMeal (){
        const appetizer = this.getRandomDishFromCourse('appetizers');
        const main = this.getRandomDishFromCourse('mains');
        const dessert = this.getRandomDishFromCourse('desserts');
        const totalPrice = appetizer.price + main.price + dessert.price;
        return `The meal includes as an appetizer: ${appetizer.name}, as a main dish: ${main.name}, and as a dessert: ${dessert.name}. The total cost is ${totalPrice}.`;
    }
};
    
menu.addDishToCourse('appetizers', 'salami', 12);


menu.addDishToCourse('appetizers', 'cheese sticks', 10);
menu.addDishToCourse('appetizers', 'french fries', 26);
menu.addDishToCourse('appetizers', 'tortilla', 20);


menu.addDishToCourse('mains', 'pasta', 90);
menu.addDishToCourse('mains', 'beef steak', 120);

menu.addDishToCourse('desserts', 'cake', 25);
menu.addDishToCourse('desserts', 'ice cream', 35);
menu.addDishToCourse('desserts', 'creppe', 40);

const meal = menu.generateRandomMeal();

console.log(meal);

Once more, very thankful for your time and help!

you need to be aware of the pros and cons of each approach. Doesn’t mean getter and setters is a bad approach.

Before we continue, you need to understand something. I don’t like certain aspects of JavaScript, so please take that into consideration when reading my answers

the first is that, there is no way (maybe with TypeScript) out of the box, to enforce data types on object properties. So you need a lot of boiler plate code to achieve this.

No proper encapsulation for the properties which are used in getters and setters. We can still access _courses. The language doesn’t enforce the courses getter.

Your approach seems right to me, I would only put a comment here:

// use setter to push element into array
this[courseName] = dish;

Given the assignment operator now essentially does a .push()

1 Like

Big thanks for your time and explanations!

I really value it and learned a lot from it.

I will make sure to take those three aspects (data type checking, artificial encapsulation -if you can call it like that to, I suppose, adding some sort of message, error, or alike to artificially encapsulate properties-, :slight_smile: and the use of proper comments in the proper place, like before the assignment/push here) whenever I actually work with getters/setters in the future.

1 Like

That’s a pretty busy getter, considering the properties are easily accessed…

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

We are returning an object with all three arrays.

1 Like

Good point indeed.

Actually, thank you for pointing that out!

I had totally misunderstood this. I think what tripped me a little bit here was the wording in the instruction. I remember I spent long time thinking about what it was meant by:

return an object that contains key/value pairs for appetizers , mains , and desserts .

At that point, in instruction #6, we still did not create a dish object, so I used some placeholder dishes, like:

_appetizers: ['salami', 'french fries']

I failed to see clearly which was the key and which the value requested, so I went and used the index of the array as the key and the string (later the dish object) as the value.

This was my output when using he courses getter, according to what I could make of the wording in the instruction:

{
  '0': { name: 'salami', price: 12 },       
  '1': { name: 'cheese sticks', price: 10 },
  '2': { name: 'french fries', price: 26 }, 
  '3': { name: 'tortilla', price: 20 },     
  '4': { name: 'pasta', price: 90 },        
  '5': { name: 'beef steak', price: 120 },  
  '6': { name: 'cake', price: 25 },
  '7': { name: 'ice cream', price: 35 },    
  '8': { name: 'creppe', price: 40 }        
}

I now see clearly what they meant: that they wanted an object with each array becoming into a value and the key being the property of _courses.

To be honest, I still think the wording is not incredibly clear there.

Just a question, inside the courses getter, shouldn’t you use the getter of each of course’s properties, instead of accessing the property directly? Like this: mains: this.mains instead of mains: this._mains?

I was trying to do it with

but without the getter, returns undefined, since the this binds I think with menu, so I would need to use something like appetizers: this._courses._appetizers but I think this one would defeat the purpose of the getter itself, right? :slight_smile: Sorry if I sound messy like if I were learning; it’s because I am.

Thanks again!

1 Like

That would be the end goal, perhaps. First, get the above to work as the primary getter. The three properties don’t even need backing prefixes for this purpose.

Given the multiple ways we can encapsulate the getter, try it in all configurations and tweak the bindings accordingly to get it to work. This is something to play with for awhile rather than rush through. From my view there are no pat answers. I’m sure we’ve plenty of variations in this forum. With so open-ended a project one can return to it and discover something new each time.

This is not as much a cry for help as it is feedback regarding the project… I have to say, I took all of the lessons, I did the quizzes, I read the homework… Previous projects have gone OK and I’ve always felt like “I see where this is going!”.

When I opened up this project, I felt completely lost. I don’t think the getters/setters courses leading up to this project has left me with a very good idea of “why do I need this?”. I think I will have to go back and take the last two lessons or so back from scratch.

So my (whiny) feedback is: I have this experience, that this project is disconnected to the learning - or the learning is disconnected to the project. This is the first time, where I have to open up every “get hint” box, and each time I’m a bit surprised… So that’s just my 2 cents - from a guy who has only studied Javascript (through Codecademy) and with no previous coding experience, this particular lesson/project seems very difficult, compared to the other projects leading up to this.

Now, I will go hit the books and take the lessons over to see if any of the getter/setter stuff catches on on the 2nd read…

5 Likes

You are not the first, and very likely not the last person to make such a post. I get your feedback, but I did that discussion couple of times, not really feeling like doing that again. So instead I want to focus on getters and setters, and the consequences for this project.

Lets start at MDN documentation (link), which says:

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

understanding that one line is crucial. The getter is a bit magically if you like. Also going to borrow the example from MDN:

const obj = {
  log: ['a', 'b', 'c'],
  get latest() {
    if (this.log.length === 0) {
      return undefined;
    }
    return this.log[this.log.length - 1];
  }
};

console.log(obj.latest);
// expected output: "c"

so we getter named latest. So now we have a property latest which is bound to a function. so on this line:

console.log(obj.latest);

we access the property, which will call the function. So now we have a property to access the last entry in our log

Another good example for getters and setters is something like this:

const myObj = {
   _example: [],
   get example() {
      return this._example.join('-');
   },
   set example(valIn) {
     this._example.push(valIn);
   }
}

myObj.example = 'a';
myObj.example = 'b';
myObj.example = 'c';

console.log(myObj.example);

We really change the default behavior of a property.

so we have two properties here:

_example, which is prefixed with an underscore. This is a naming convention to tell us that the property shouldn’t be accessed directly. That we should use the getter instead
example, this property is created by the getter.

so now when access example property, we get a string. Even though under the hood, this in array

the setter is where things get very interesting. We change the default assignment behavior. When we assign to the example property, the values are actually appended to the array instead.

Lets this sink in first before we move on to meal maker :slight_smile: any question about this? Does this help to somewhat clarify getters and setters?

1 Like

Hi! I tried going over the concepts of getters and setters again… I think it’s more clear after I took the courses a 2nd time over.

I made my way through thee project, almost entirely on my own… I’ve hit a wall and I’m stuck with an error that I can’t resolve, perhaps you can help me :slight_smile:

Specifically, “dishes” in line 62 is undefined and I can’t figure out why… perhaps an issue with me using my setters?

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

  get appetizers() {
    return this._courses.appetizers
  },
  set appetizers(appetizersIn) {
    this._courses.appetizers = appetizersIn
  },

  get mains() {
    return this._courses.mains
  },
  set mains(mainsIn) {
    this._courses.mains = mainsIn
  },

  get desserts() {
    return this._courses.desserts
  },
  set desserts(dessertsIn) {
    this._courses.desserts = dessertsIn
  },  

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

  addDishToCourse(courseName, dishName, dishPrice) {
    const dish = {
      name: dishName,
      price: dishPrice,
    }

    if (courseName === "appetizers") {
      this.appetizers = this.dish
    }

    else if (courseName === "mains") {
      this.mains = this.dish
    }

    else if (courseName === "desserts") {
      this.desserts = this.dish
    }

    else {
      console.log("What is this course? Course name unknown")
    }
  },

  getRandomDishFromCourse: function(courseName) {
    const dishes = this._courses[courseName];
    const randomIndex = Math.floor(Math.random() * dishes.length);
    return dishes[randomIndex];
  },

  generateRandomMeal: function() {
    const appetizer = this.getRandomDishFromCourse("appetizers");
    const main = this.getRandomDishFromCourse("mains");
    const dessert = this.getRandomDishFromCourse("desserts");
    const totalPrice = appetizer.price + main.price + desserts.price;
    return `As an appetizer you will taste "${appetizer.name}". Your main course will be "${main.name}" followed by "${dessert.name}" for dessert. The total price for this menu is ${totalPrice}. Bon appetit!`
  }
}

menu.addDishToCourse("appetizers", "Chicken soup", 4.10)
menu.addDishToCourse("appetizers", "Ceasar salad", 3.20)
menu.addDishToCourse("appetizers", "Shrimp cocktail", 6.95)

menu.addDishToCourse("mains", "T-bone", 12.33)
menu.addDishToCourse("mains", "Coq au Vin", 10.99)
menu.addDishToCourse("mains", "Sea bass", 11.15)

menu.addDishToCourse("desserts", "Ice cream", 4.10)
menu.addDishToCourse("desserts", "Gateau Marcel", 4.25)
menu.addDishToCourse("desserts", "Banana split", 4.61)

const meal = menu.generateRandomMeal();

console.log(meal);

my first step would be to verify the problem:

const dishes = this._courses[courseName];
console.log(dishes) // gives undefined as expected from the error. 

my second step then would be to inspect the values used when defining dishes:

  getRandomDishFromCourse: function(courseName) {
    console.log(this._courses, courseName);
    const dishes = this._courses[courseName];
    const randomIndex = Math.floor(Math.random() * dishes.length);
    return dishes[randomIndex];
  },

where we can see that this._courses has 3 properties, but all these properties have an undefined as value.

so then I would look at the courses object:

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

which looks fine, so I would move on to the getters:

  get appetizers() {
    console.log(this,  this._courses.appetizers);
    return this._courses.appetizers
  },

seems we found the problem :slight_smile:

I’m sorry, I don’t follow at all - remember, that I don’t have your bug fixing experience. I don’t see the issue with my getters?

I didn’t understand your feedback, but I figured out that the issue was with my addDishToCourse method - I fixed it and managed to complete the course.

Thanks for taking the time to give thorough feedback on my code! :slight_smile:

that is why I am showing you, you can add the .logs to your code, to inspect the state of your program.

here:

  get appetizers() {
    console.log(this,  this._courses.appetizers);
    return this._courses.appetizers
  },

this is the _courses object (you can see this if you add the log to your code), which doesn’t have a _courses property

What is happened in https://pastebin.com/grtynL8s ???

/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:37
return this._courses[courseName].push(dish);
^

TypeError: Cannot read property ‘push’ of undefined
at Object.addDishToCourse (/home/ccuser/workspace/learn-javascript-objects-meal-maker/app.js:37:37)
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)

you could look at the available keys and the keys you attempt to use:

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

you see that use "dessert", while the key is “desserts”. In my opinion, JavaScript should throw an error that you attempt to use a non-existing key, instead of this silently failing undefined crap.

1 Like

Word! I was chasing for information in the forum and was wondering, why it is so so so hard this time. I needed all the hint boxes, went through all the steps and at the final one I failed and couldn’t find my mistake. Finally I was going through the lessons again, because I felt like I must have missed something. Very frustrating. I don’t feel that the getter/setter method is (I’m not a native speaker) well ‘illustrated’ in this project if it is even possible to put it that way. Or maybe I’m just too stupid this time :smiley:

1 Like