Okay, so let's now implement
the feature of updating recipe servings.
And this time, we're actually starting in the controller,
just so we can outline what we want to happen.
So let's come down here and add yet another controller.
So control servings, let's say.
And I keep calling these functions here, controllers,
but that's just because we're using
the model view controller pattern.
So they could also be called handlers, because in the end,
that's what they are, they are simply event handlers,
that will run whenever some event happens.
Now, in this case, this controller here
will eventually be executed when the user clicks
on one of these buttons here.
So either to decrease, or to increase the servings.
And so that will then increase or decrease this number here,
and also adjust all of these ingredients, right?
So this controller is actually going to be very simple.
All we have to do here is to update the recipe servings,
so in the state.
So basically updating the underlying data.
And then all we have to do is to update the view as well.
So actually updating the recipe view,
because that is of course, the view that will be impacted
by controlling the servings, right?
So in this case, we will actually have no,
like servings view, because these buttons,
and everything that happens when we click on them
is already in the recipe view, all right?
So here, updating the servings in the state
has of course to do with the model.
And so in the model, we would like to have
some method which does that for us.
So as always, we will not want to manipulate data
directly here in a controller,
instead we delegate that task to the model,
which is all about the data.
So again, in the model, we will like to have
a method called update servings,
and then we can pass in the new servings.
So let's just say six here, for experimenting.
And so let's, now go to the model
and actually implement this.
So load recipe, then results,
then here, we will have the update servings function.
And so this will then take in the number of servings,
let's call it new servings, actually.
Now what this function will do is to reach into the state,
and in particular into the recipe ingredients,
and then change the quantity in each ingredient.
So we have state.recipe,
and then we have that ingredients array, ingredients.
And so again, in each ingredient,
we now want to change the quantity property.
So just to remember, again, our data, because I know
this can be quite confusing, let's do a search here,
because that will then change us,
or actually it will show us here some real data.
So here is a recipe.
Ah, this is actually only the search data.
But this is the actual data here, so for the entire recipe.
And so remember that we have two ingredients in there
and each ingredient is an object,
which contains the quantity.
And so this is the quantity we want to change.
For example, here this quantity two is four four servings,
but if we had eight servings,
then the quantity should become eight, right?
So the servings doubled,
and so the quantity needs to double as well.
And so that's the kind of logic that we will write now.
And so, yeah, this was just to show you
that it is the quantity property
inside of the ingredient that we will want to mutate.
So we want to do something for each of these ingredients.
So we don't want a new array, and we could do that also.
So we could create a new array,
and then override state.recipe.
But let's just do it like this.
So basically with side effects.
So in each iteration of the loop,
we have the current ingredient.
And then here, we want to do something with it.
So basically, we want to change it.
So ingredients.quantity, should become something new.
And now how do we calculate this new quantity?
Well, we will basically use this formula.
So let me write that here.
So new quantity equals the old quantity
times the new servings divided by the old servings.
And let's use the example that I mentioned earlier.
So changing from four servings to eight servings.
And I think we had the quantity of two.
So two times, and then the new servings again,
were eight divided by four.
And so this would then be eight divided by four is two,
times two is four.
So again, if we double the servings like this,
then we also need to double the quantity.
So we then multiply the original quantity
by this ratio here, basically.
Now okay, so just basic mathematics here.
And so let's not put this formula here.
So the old quantity is in this case,
also ingredients.quantity, so the original one,
and then times the new servings.
So the one we are getting here,
divided by state.recipe.servings, now, okay.
So with this, we are changing all the ingredients.
In order to finish, of course,
we also need to update the servings in the state.
Because otherwise, if we tried to update the servings twice,
then by the second time, we would still be using
the old value of two servings.
And so of course, we need to update this value.
So state.recipe.servings, needs to be the new servings.
And we're doing that here at the end of the function,
because otherwise, we could not preserve this old.
So this original value here, okay?
So this, we update the servings of the current recipe.
And again, that works because we already have
the recipe in the state.
Okay, and so then we need to simply update the recipe view.
And by now what we will do is to actually simply overwrite
the complete recipe.
So basically, we will simply render it again.
So exactly what we had here actually, in control recipes.
So taking the recipe out of the state,
and then simply rendering it.
So let's copy this down here.
So we do that, because we don't want to
like manually go ahead and
change all these values here one by one.
So we would have to select this element and this element,
and this one, and then manually change all of that.
And the same here for this value, right?
And so we don't want to have all of that work.
And so for now, we will simply,
well update this entire element here again,
so this entire view, okay?
And now let's actually call this controller here,
without having to create the event listener just yet.
So just to test if everything is working.
And so let's do that, after all of this.
So here in the init function at the end,
we call control servings.
And so with this, we can guarantee
that there is already a recipe loaded.
So let's actually use the example of eight here
so that we double the values.
Not well, that's not really working.
There seems to be some kind of bug here.
Oh, and for each is of course, wrong here.
But we also have some other problem here apparently,
which is that we are trying to read for each on undefined.
So let's first fix that small error.
So it's called for each.
And then that other problem actually comes from the fact
that we are doing it wrong.
So we are not taking into account the asynchronous nature
of our application here.
So, basically, here, we are trying to control the servings
simply after registering these handler functions here.
But by that time, no recipe has yet arrived from the API.
And so therefore, state.recipe is not yet defined.
And so here we are then trying to read ingredients
from the recipe that doesn't exist, okay?
Does that make sense?
And this is actually a great demonstration of the pitfalls
of working with Asynchronous JavaScript.
So if we really wanted to test this here right now,
we could probably do that right here,
after we control the recipes.
So basically, after the recipe is loaded.
So let's just temporarily put this here,
or probably even better, right here.
Let's just mark this very clearly as a test, all right?
And let's see what happens now.
Oh, and now we have the eight servings that we want.
And here, these values, they should have changed.
Well, I'm not sure what they looked like before.
But we can reach here now,
but here we also already have the eight servings.
So this is not a good comparison.
But let's try it here with four.
And so we have four.
And yeah, these values are actually half
of what they were before.
And so that means that our update servings function
is already doing its job, so that's great.
So we can remove that from here
because now we will actually want the controller to run
whenever we click one of the buttons in the recipe view.
And so what we will do now is to create
a new event listener in the recipe.
So here in this recipe view.
And again, that's because that's
where these buttons already are.
And so there is no need to create a new, like servings view.
So here, I will simply create a new method.
And as always, it's called add handler and then something.
So here, let's call it update servings,
to make its purpose really clear
and then as always the handler function.
And again, that handler function will of course,
then be debt controller that we just wrote here, okay?
Now, how will we actually do this?
So the parent element here is this whole recipe,
but the elements that we are interested in,
are these two buttons.
So these buttons increase servings,
end button decrease servings.
And the class that they have both in common,
is this button tiny, right
Now, each of these buttons also
has some elements inside of it.
And so yeah, the best way of doing this
is actually once again, doing event delegation.
So we already have the parent element.
And so we can listen for events on that one.
And then check if the click target was one of those buttons.
And so this is actually going to be very similar
to what we did in the last video
with the pagination buttons.
So add event listener, click.
And then here again, we want to actually select
that button element that was clicked or not.
So here we then use again, event.target,
which is the clicked element.
And then once again, we use the closest method,
which is, I think I've said it before, an amazing method,
which is really, really useful for event delegation.
And so again, we are looking for
elements with the button tiny class.
So button tiny and that is important because
the user might click, actually on this.
So on this SVG element instead of the button element itself,
and so then that will basically look
for the closest button tiny, right?
But of course, if we're clicking outside
of any of these buttons, then this closest
will not return any element, it will return null.
And so we need to check for that, just like before.
So if null button, then return.
But otherwise, let's simply for now login to the console.
And so now we need to connect this here with a controller.
And so let's do that.
So that's, and let's actually do this here.
So keep it close to the other recipe view.
So recipe view.add handler update servings,
which will then receive control servings,
so that it can execute our controller function.
And so if we now put some value here, let's say eight,
then that should actually already update the servings
and re render the recipe view.
So let's see.
Let's take a look here at this value and these values here.
Oh, and nothing happened because of course, we didn't call.
So here, we didn't call control recipes yet, right?
So we didn't call the handler function.
But let's actually do that, now, right.
And you see that the number here change to eight.
And here all the values changed as well.
So that's great means again,
that our update servings function is doing its job.
And the same can be set for control servings.
Now, we can also see that
the correct button here was selected.
Now it's actually not showing it anymore, here.
But that's probably because the DOM was re rendered here.
And so this new button is not exactly
this button that we have here.
But that doesn't really matter
because all I wanted was to check
if the selection was correct here, and it was.
So let's try that again now with the increase button,
and watch again what happens with ingredients, okay?
And so here, we got the button increased servings.
Now okay, so we're almost done here.
Now, all we want to do is, of course,
to decrease the value when we click here,
and increase the value when we click the plus button.
And so we don't want to always set the value to eight,
but instead, do that dynamically.
And there are multiple ways in which we can do that.
So let's think about this a little bit.
So we could do it right in the controller
because right here, we already know
what the current number of servings is.
And so then here, we could simply take that,
and decrease or increase that value by one.
And so that would then yield the effect that we want.
However, I would like to keep this controller here
as flexible and as robust as possible.
And so I don't want this controller
to be the one responsible for telling,
which should be the next serving.
So the next number of servings.
So that should come from the view,
and not from the controller, because it is in the view
where the user is actually updating the servings.
And so in order to keep this controller
as flexible as possible, we can simply pass in,
basically the new servings,
and then pass that new servings into update servings.
Okay, so new servings here.
And then use that here as well.
And so now we will determine this new servings in the view,
and pass that value down into this controller, all right?
But now here in this function,
how will we determine the new servings?
Well, once again, here we will need to connect
the user interface with decode.
And as always, for that we use the special data properties.
So let's come to our button or both our buttons
and then add a new property here.
And so then we can read the value from that property
in the Add event listener function.
So let's say data, update, to.
And then here the value should be the current servings,
and plus one, right, because this is the button
to increase the servings,
while actually both are called increase,
but this one has a minus sign.
So this icon here is called icon minus.
So that means that we are decreasing the value.
But anyway, what we want here
is basically the current servings minus one, right?
And then in the other button,
we want the same, but plus one.
So as I said, in the beginning,
this is pretty similar to the pagination buttons,
until let's actually change the increase
that we have in both to update.
Okay, and let's then actually use this class
to select the buttons.
Because button tiny is a class
that is actually more about styling,
and this button update servings
is more about the functionality, so let's use that one here.
And so now we can read, now, of course, that value.
So const update, two equals the button.data set.update to.
Alright, so here updates two as well.
And it has this camel case here,
because when there is a dash in the property name,
then that will be converted to camelcase notation like this.
And here, we can actually use destructuring,
so that makes the code even cleaner.
Then we can pass that value here to update to,
and that's it, right?
Now, here, we just need to convert that to a number,
but besides that, we should be good to go.
So it should be working now.
So instead of changing to the hard coded value of eight
we had before, let's see what happens now.
Now we get undefined servings.
So let's try to understand what's happening.
But at least the button here was correct.
So the value used to be four,
and so the plus button that we clicked
had the data update to, set to five.
Okay, so here, let's simply check the value of update to,
maybe we did something wrong in getting that value.
Yeah, it looks like there is undefined.
So let's go back and check what's going on here.
But it looks correct.
So update to is not spelled wrong, am I right?
Update to, man, so,
well, let's try to get rid of destructuring,
but that shouldn't be the cause, update to,
Oh, and actually, that should be the cause
because of this conversion that we have here.
So I was trying to convert plus a button data set,
and then trying to get update to from there.
So I'm sure that now it will work, but let's see.
And yes, it does, so now we get the number there.
So beautiful, and you see the values changing down there.
And everything works correctly.
Now there's just this flickering of the image here.
But we will take care of that in the next lecture.
For now let's experiment
and see what happens here at a certain point.
So here we reach zero servings,
and then we go even further down.
And so this of course doesn't make any sense.
And so we need to add a check here.
So basically, we only want to call the handler,
if the number we will update to is greater than zero.
So we don't want to update to zero or anything below.
And so then in that case, we simply don't call the handler.
Okay, now here, let's put it back to the structuring
like we had it before.
So I really prefer that.
And then I will simply do the conversion from the string.
So right now this is a string.
So I will simply convert that here, and also here.
I can also get rid of this console.log here
to make the function a bit cleaner, and so let's see again.
So it keeps working here.
But then as we reach one, it doesn't go any further down.
Okay, so beautiful, that works.
But we're still using this kind of hack of updating
the entire view here at once.
So remember, here in the controller,
in order to basically update the recipe view,
we are simply rendering it all over again.
And so that takes some time,
especially noticeable here in the image.
So you see, I think it's basically trying to download
the image again, and so that means, of course, trouble.
And so in the next lecture,
we will develop a simple algorithm,
which will basically only update the DOM in places
where we actually want to update the markup.
So only, for example, this number here, and these numbers,
and leaving everything else the same,
so without re rendering everything,
and that will be a lot of fun.
And so let's go do that next.