Now, how do we get to this product
in this cart controller action here?
Well, we'll need to get it from the database.
So here we'll actually import my product model because that
has to methods for talking to the database
and fetching product data.
So I'll import this,
turn add cart item into an async function.
Since we'll perform an asynchronous operation.
And the asynchronous operation I want to perform
is that I use product find by ID
to find a specific product by ID,
and then use that product to add it to the cart.
Now for that here,
the ID which I expect to get
should be found in the request body,
because I won't send a get request,
but a post request for adding a new cart item.
Post makes sense because we're adding,
creating new data on the server.
That's a typical case for a post,
and therefore we'll have a request body
attached to the incoming request, because post requests
do have bodies, unlike get requests.
And in this post request body,
I expect to find the product ID.
I can use that here therefore,
and then await this,
to get the product that should be added.
As always, this might fail,
So let's try this,
and catch this error,
and now we do need the next parameter value,
not for add item to cart, but for fetching a product.
So in the catch case here,
I want to call next error and then return,
So to know ever code executes thereafter.
And I want to use the product down here
and I could move that line into the try block,
but to keep that block leaner,
I will actually add a product helper variable,
and set that in a try block.
This variable is now scoped to the function,
not to the try block.
And hence, I can use that down here
for adding this product to my cart.
That's the idea here.
Now, once I did that,
I also want to make sure that the updated cart
is saved back into the session.
That means I'll access my session,
and they to cart property.
And there, I will store res locals cart.
So that data which had just updated,
we can also add a utility constant here,
which has res locals cart as a value
so that we can actually
work with that constant and don't type
res locals cart all the time.
But the idea is the same. I use that cart to add the item,
and now that the cart is updated, I set it back,
I override the cart in my session with that new cart.
The cart in the session, not in res locals.
The session cart, is the cart
that will survive this request response cycle,
and that will be stored in the session database collection.
So that is my session-based data,
which I now update after the cart was updated.
We don't need to call req session save,
because that will be called automatically.
We would only have to call that,
if we then perform an action, like a redirect,
which relies on that data to be updated.
So which needs to guarantee that this update was
saved to the database.
I don't need that here though, because
I actually don't plan on submitting a regular forum here,
and then in the end,
redirecting back to this page thereafter,
even though we could do that,
but instead, I want to use another Ajax request here,
so that we handle a click on this button
with front-end browser site, JavaScript code,
and we send such a JavaScript driven request to the backend.
And therefore, I will then update my request session data,
but I don't redirect here,
instead I sent back adjacent response,
where I will actually set the status code to 201,
which is a success status code that also says
successfully added data, so to say.
Setting it is optional, 200 would be the default.
You don't need to set that,
you can use 201 to be very clear that the
add a resource action succeeded.
Just want to show it to you,
that's why I'm including it here.
And with that, we then sent back our data.
Now the data I do want to send back here,
could be a little message like
cart updated, but more importantly,
I want to send back data about the cart
that I can then reflect on this user interface.
And here, I got one thing that I want to reflect.
Next to this cart item here in the navigation,
I want to show a little badge,
a little number that increases
as I add more items to the cart.
And that's the part of the UI,
which I want to update with front end JavaScript
once I added an item to the cart.
Therefore, what I want to return here,
as part of this response, is a key named new total items,
the name is up to you though,
where I do return to number of items
that are now stored in the cart.
And this is now tricky,
because I can't just say cart items length
to just count the number of items into cart,
because you have to remember that in our cart model,
when we add item,
we don't always push a new item onto the array,
instead we might've just updated an existing item.
So therefore in the cart model,
I actually also want to have some cart wide metadata
that tells me the number of items in the cart
across all product groups that I might have in there,
and that tells me the total price for the entire cart.
And that's then the data I want to return.
So back in cart controller, I want to return, let's say,
cart dot quantity or total quantity.
This is a property that doesn't exist yet,
but it is a property which we'll add now.
So we want to return a total quantity,
or we want to have a total quantity in the cart that sums up
all the quantities of all the products we have in the cart.
And that's a feature we don't have yet.
To do that, We could go to our cart
and here in the constructor,
I now don't just expect to get an items array,
but also a total quantity,
which by default is zero, let's say,
and the total price, which is zero initially.
And that's then also data,
which I want to set up for my entire cart
to total quantity and the total price.
So this should be cart wide data.
Now of course, items might not be an empty array.
And in that case,
the total quantity and total price also have to be provided
correctly to the constructor,
but we also need to update it whenever we add a new item.
In that case, we need to update it both
when we pushed on new item,
and also when we just increased the quantity
of an already existing item.
Now in this case, that we increased the quantity
of already existing item,
I want to reach out to this total quantity
of the entire cart,
and set this equal to this total quantity plus one.
By the way, the shortcut for this would be
this total quantity plus plus.
Because we increased the quantity
of this single product by one,
hence the quantity of the overall cart
has to increase by one.
Now for the price, it's this total price
that should be set equal to this total price,
plus the price of that product
of which we increased the quantity by one,
so product dot price.
The shortcut for this by the way, would be plus equal.
Now that is correct if we increased the quantity like this,
if we pushed a brand new cart item onto the cart,
it's the same.
It's the same, because we then still want to increase the
quantity by one because we pushed one product onto the cart,
and we also want to increase the price
by the price of that product that we added.
So it's the same logic either way.
Therefore now, We ensure that
these properties exist the cart,
and hence we should be able to work with them
in the cart controller as we do here,
when I returned the updated total quantity,
after adding an item to the cart.
Now to see whether that works,
we need to do a couple of things.
We need to add this badge here,
which shows the number of items, and then most importantly,
we have to connect this button to send that post request
to the backend and to then update the dom after we did that.
Hence, now I do actually start with the styling,
and I'll go to the public styles folder,
and they're into the base CSS file,
because I want to add another base style,
which I'll use in other parts of the page as well.
I'll add it here at the very bottom,
and it's the badge class selector, which I want to add here.
We're not using this class yet, but we'll soon do so,
and we'll also do so in different parts of this page.
That's why I'll make it a class,
it's not guaranteed to be unique.
Now this batch class will get a margin
left of, let's say, var space two,
then a little bit of padding
where I actually won't use one of my predefined spaces,
but instead zero dot one five rem,
because I need a super tiny padding top and bottom,
but then left and right, I will use var space four,
and you can mix fixed hard-coded values
with dynamic variable based values like this.
I'll add a border radius of 10 rem,
also not using one of my variables,
because I need a super large border radius here
to achieve this badge look,
which should have totally rounded corners
as you'll see in a second,
and I'll use a background color of
var color dash primary dash 500,
and set a text color to
var color dash primary dot 500 dash contrast.
That's my badge,
and that's all I want to do for the badge here.
And now I want to use that badge here in my navigation.
So in the shared includes folder in nav items,
and they're next to the cart.
Here after the word cart,
I want to add a little span with a class of badge,
which is that class we just worked on,
which will include the number of items in the cart.
And that might be zero initially,
though we will soon set that dynamically,
but initially, if I reload, you'll see it's zero.
Now I actually got an error here,
we'll look into that in a second,
but you see the badge here.
Now let's see why I'm getting an error here.
I do get that because cart is not a constructor.
That has to occur in my custom middleware.
Let's see what's wrong there.
Cart require models, cart model?
If I have a look at the cart model,
yeah, I should export it there.
That's of course missing in the cart model dot JS file,
we should add module exports equals cart.
Otherwise you see what's happening
If you try to use a feature defined in another file,
that's not being exported.
You can't use it, but with that, reloading works again.
And now of course the batch number should be set
with the real cart data.
So they offer back in nav items.
Instead of hard coding zero here,
I'll use ejs to output local dot cart.
Remember, we set res locals cart in our custom cart,
middleware dot total quantity.
This brand new property we added a couple of minutes ago.
I'll use it here.
And if I reload,
this is still zero, because initially it's zero.
But now we can make this button work
to send the request to our add item controller action
so that we are able to add items and then update that dom.