Maximilian: So let's now make sure
that this addItemToCartHandler is being called,
and for that we need to go to the place
where we wanna call addItem on our context object.
And that's in our MealItemForm in the end.
There we of course wanna handle the form submission,
so when this button is clicked
and when the form is submitted,
we in the end wanna well,
add that item to the cart
because that's what this form is there for.
So as a first step in the MealItemForm Component,
we can add our submitHandler function
where we get the event object,
which is sent as an argument automatically
when we call this function upon a built-in event.
And I wanna call this function
or I wanna have that function called
for the onSubmit event or the submit event
on that form here.
So here I point at the submitHandler.
Now you'll learned that here
we should call event.preventDefault
to make sure that, that browser default of reloading
the page is prevented.
And then I wanna extract the entered amount.
Now I wanna use refs for that.
The alternative would be two way binding
by managing some state,
but I wanna use refs.
Now, the thing is that here,
I actually have a separate Component,
a custom Component.
Normally, we can use refs by importing useRef from react
and then we create a ref and we assign that
with the ref property or with the ref prop to an element.
Generally, we can do that here as well.
I can call useRef
and create my amountInputRef like this.
Now, I would want to parse that to the ref prop
but, since this is a custom Component,
the ref prop doesn't work,
at least not out of the box.
Instead, I also taught you how you can make refs work
on custom Components.
I showed you how this works earlier in the course.
All we have to do is go to the Component
where we wanna receive refs.
In this case, that's the Input Component in the UI folder,
and then make sure you import React in there from react
and wrap your Component function with React.forwardRef.
So that Component function is now our argument
to forwardRef.
Then you get the ref which can now be set
through the ref prop on your Component,
as a second parameter here,
and you can now use it inside of your Component function
to forward that ref to that input here.
So here I can now set the ref prop
on the input element to my ref parameter.
And that's this forwarded ref,
which is the ref which is being set,
here on my Input Component.
With that we can now get access to the Input through refs.
And that allows me to read that entered value
in my submitHandler function.
There we can get the enteredAmount
by accessing amountInputRef.current.
It's always stored current for refs created
with useRef.value,
because amountInputRef.current will point at
the input element which is stored in that ref in the end.
And then every input element
by default has a value property
which holds the currently entered value.
That value is always a string.
Even if the input is of type number,
it's always a string.
So we can convert it to a number
by adding the enteredAmountNumber,
or however you wanna name it,
by simply adding a plus in front of enteredAmount.
And this will convert the string number
to a number, number.
And then we can add a little if check for validation
where we check the entered amount as text,
trim it to remove any white space
and check if that's maybe empty.
So if no value was entered,
or if the entered amount as number is smaller than one,
or if the entered amount as number is greater than five.
That's a little validation I wanna add here.
And if either of these conditions is met,
so if we make it into this if check,
I wanna return and not continue
with this function execution of this submitHandler.
I also wanna output an error message
below my input and button,
and therefore I'll manage some state here,
which is of course optional but which I wanna do.
I'll simply use useState
because it will be a quite simple state.
It will simply control whether this form is valid or not.
And I'll set this to true initially
and then extract my two values
the state snapshot and the state updating function
and I'll name it amountIsValid and setAmountIsValid.
And if we make it into this if check,
we know that the entered input was not valid.
So here I'll call setAmountIsValid and set it to false.
And if this is false,
then I wanna output an error message.
So here below the button,
I'll output some content conditionally
and I will check if not amountIsValid.
and if that's the case,
I will render a paragraph where I say,
Please enter a valid amount one to five.
So that's just a little addition also to practice state
and conditional rendering again.
Most importantly, the form submission is now only completed
or only fully handled if we have valid inputs,
so if we make it past this if check.
And here I then wanna execute my context methods
to add a cart item,
but I will not do this in this Component.
Instead here, I will simply call a function
which I expect to get on props.
And I'll name it onAddToCart.
And I forward my enteredAmountNumber,
because the cart item which I wanna add needs more data
then just the entered amount.
In this MealItemForm though,
we only have that amount.
We don't have the ID or a name or a price of that item.
That's why I'm not calling the context method here
but why I'm just calling some other function
which I expect to get through props to parse the entered
and validated amount number to that function.
And now it's the MealItem Component where
that function will be defined.
Here I'll add addToCartHandler function
where I get that validated amount as a parameter.
And I parse a pointer to that function to the MealItemForm,
on that onAddToCart prop
which I'm executing in that Form Component.
So here to that prop,
I parse a pointer that is addToCartHandler function.
And now in the addToCartHandler function,
I wanna reach out to my context.
So therefore in the MealItem Component,
I also wanna get access to my context.
So here I will import useContext from react
and then simply call useContext.
And we now need to import the context
to which you wanna get access.
So CartContext from going up
and going up, going up again, store/cart-context
the file with a dash in the file name
and parse this to useContext to establish a connection.
And then here we have our CartContext
and in addToCartHandler,
we can now call cartCtx.addItem
which is one of the methods defined in our context.
Here we're pointing at the addItemToCartHandler
and I'm calling that function here.
And to that function we now need to parse this item, right?
That's what we're expecting here.
We expect to get the item,
which we forward to the reducer.
So it's that item which I wanna parse to addItem.
And hence I create a new object on the fly
with an id which I expect to get through props here,
so props.id,
with a name, which I get through props
props.name, which we're already outputting down there.
We don't need to parse on the description
but I do want to set an amount field
which points at the amount we're getting here.
And I do want to add a price field
which points of props.price,
not this formatted price
but the price as a number which we get on props.
So now we just need to make sure that we also get props.id
and therefore in the AvailableMeals Component,
where we render all the meal items,
I will now also set a prop id and forward meal id.
And with that, we should be triggering that context method
whenever that form is submitted.
And that should then add items to the cart.
So if we save this, we reload,
if I lick Add here
you see that batch number updated,
and it updates whenever I click add.
Now the cart logic isn't the final logic I wanna have yet
but at least we can see that
the context is already working out.
Now let's make sure that here,
when we open the cart
we are outputting the actual cart.