Coding

NodeJS / Express / MongoDB – Build a Shopping Cart – #12 Cart Model

  • 00:00:00 so I want to add new items to the card
  • 00:00:04 so a great place to start probably is my
  • 00:00:07 shopping page where I have this add to
  • 00:00:09 shopping cart link here I want you let's
  • 00:00:13 say Target a route which I'll name Add
  • 00:00:16 to Cart of course named is however you
  • 00:00:19 want to name it and I also have to
  • 00:00:21 create this route I'll do it in my index
  • 00:00:23 chess file for now so in here I'll
  • 00:00:26 configure a new route I get routed ubi
  • 00:00:29 and I'll give it the same path as in my
  • 00:00:32 view add to cart and I'll expect the
  • 00:00:35 idea of the product I want to add to my
  • 00:00:38 card here this of course has the default
  • 00:00:41 middleware function here and as a side
  • 00:00:46 note you can always leave out the next
  • 00:00:48 part if you are not using it since it
  • 00:00:50 gets passed a seafood argument so I'm
  • 00:00:53 just writing it too well kind of a
  • 00:00:55 convention I adapted but you don't have
  • 00:00:58 to you can all just call this function
  • 00:01:00 like this and it should still work
  • 00:01:02 unless I'll leave next year so in here
  • 00:01:06 basically what I want to do is I want
  • 00:01:08 you push my product DoD product I want
  • 00:01:12 to add to my card kind of into my
  • 00:01:15 session but I also want to store it in a
  • 00:01:17 card object of course I don't want to
  • 00:01:20 push it into my session like a list of
  • 00:01:24 products just like that now I want you
  • 00:01:26 have a card object in my session so I'll
  • 00:01:29 come back to this card object in a
  • 00:01:31 second
  • 00:01:32 for now I'll first retrieve my ID so
  • 00:01:36 product ID will just be retrieved from
  • 00:01:38 the parents this request has the ID
  • 00:01:41 parameter here of course and with that
  • 00:01:44 as I said I want to create a new card
  • 00:01:46 for that I'll create a new model in my
  • 00:01:49 models folder here I'll name it
  • 00:01:52 cartouches now for now i won't create a
  • 00:01:58 mongoose model since i'm not restoring
  • 00:02:01 this card in database at least for now i
  • 00:02:03 might add this later when i want to
  • 00:02:06 store cards for logged in users maybe
  • 00:02:08 but right now I don't want you so I'll
  • 00:02:11 just write well a classical JavaScript
  • 00:02:14 constructor function here and of course
  • 00:02:18 export it with module exports to make it
  • 00:02:20 available outside of this fall too and
  • 00:02:23 this card constructor function of which
  • 00:02:27 I'll be able to create card objects
  • 00:02:29 later on is now very important to get
  • 00:02:32 right and on the other hand there are a
  • 00:02:34 thousand of ways to do it so here's my
  • 00:02:38 suggestion on how to implement it this
  • 00:02:42 card here should have some items in it
  • 00:02:46 and I'll change this later for now I'll
  • 00:02:49 set it to an empty array just to the so
  • 00:02:51 that we have something to work with I
  • 00:02:52 also want to store the total quantity
  • 00:02:55 I'll set this to zero by default for a
  • 00:02:58 newly created card and total price of my
  • 00:03:01 card items or yeah what all the items
  • 00:03:05 together cost now I want to be able to
  • 00:03:09 add new items to my card so I'll add
  • 00:03:12 this add function here which allows me
  • 00:03:16 to do just that and now here this one is
  • 00:03:20 an important one if I add a new item I
  • 00:03:23 won of course I want to get the item and
  • 00:03:26 let's say I also want to get the ID of
  • 00:03:29 this item because I will well of course
  • 00:03:33 always expand my card with each new item
  • 00:03:38 I'll add and you add a but here is an
  • 00:03:40 important thing I also want to group my
  • 00:03:43 items i if i add harry potter harry
  • 00:03:46 potter book here if over at videogames
  • 00:03:50 here okay so if I add a cough cutie
  • 00:03:52 three times then I don't want to have
  • 00:03:55 just three items in my card free times
  • 00:03:58 Call of Duty but I want to group them
  • 00:03:59 because it's one and the same product so
  • 00:04:03 I want to have called cutie quantity
  • 00:04:05 three times I still want to have the
  • 00:04:07 individual game informations only priced
  • 00:04:10 title and so on but I also want to have
  • 00:04:12 the aggregated information therefore I
  • 00:04:15 can't just push items on an array and
  • 00:04:18 then what list is arraigned I could do
  • 00:04:21 this but this will lead to a shopping
  • 00:04:22 cart where we might have such a list of
  • 00:04:24 well chess
  • 00:04:26 the same game for example instead of one
  • 00:04:29 row where we have game title and then
  • 00:04:31 quantity 10 or whatever so this is an
  • 00:04:35 important thing to get right
  • 00:04:37 therefore what I'll do is whenever I
  • 00:04:40 access my card so whenever I add a new
  • 00:04:43 item I'll take my old card and create a
  • 00:04:46 new card off this old card and I want to
  • 00:04:49 be able to check if a certain product ID
  • 00:04:53 like from the Call of Duty game for
  • 00:04:55 example already exists in this card and
  • 00:04:58 if yes then I will only well update the
  • 00:05:02 quantity and so on so that I will not
  • 00:05:05 push a new product in there so to make
  • 00:05:07 this bit less theoretical if I add an
  • 00:05:12 item here I'll first create a new
  • 00:05:14 variable name it store item and this
  • 00:05:18 should be mic system in items where I
  • 00:05:20 want to see if this ID already exists
  • 00:05:23 now rightfully you would say well this
  • 00:05:24 items is an array how the ID here
  • 00:05:28 probably won't exist since the array
  • 00:05:30 index probably won't be matching any
  • 00:05:32 MongoDB D ID and you would be right so
  • 00:05:36 items here shouldn't be an empty array
  • 00:05:40 but as I said I always want to recreate
  • 00:05:43 my card so items will indeed be an
  • 00:05:46 object or more specifically it will be
  • 00:05:50 my old cards items so I'll name this
  • 00:05:54 init items and I'll pass those items to
  • 00:05:58 my constructor so with that whenever I
  • 00:06:01 create my card I pass my old card into
  • 00:06:05 it this old cards items will be while
  • 00:06:09 assigned here to my items and with that
  • 00:06:13 I'm able to check if my items which is
  • 00:06:16 an object in the end where the key is
  • 00:06:18 the product ID if they already have this
  • 00:06:22 key this product ID if yes I know the
  • 00:06:24 product already was added to the card
  • 00:06:27 and I'll then work with that so here are
  • 00:06:30 basically retrieving this and of course
  • 00:06:33 I don't know if I'll get a stored item
  • 00:06:35 because the item might not not have been
  • 00:06:38 added to the card yet in this case it
  • 00:06:39 would have to be added newly so I'll
  • 00:06:41 check if I'm able to get this if not
  • 00:06:46 this is this case here if I'm not
  • 00:06:47 retrieving the stored item I'll create a
  • 00:06:51 new one so then I'll set it equal to
  • 00:06:53 items ID still but both will be assigned
  • 00:06:57 to a new object where I'll have my item
  • 00:07:02 to be my item the one I add here the
  • 00:07:08 quantity it should be Cyril because I'll
  • 00:07:11 increment it in the next step and the
  • 00:07:13 price should also be zero because I'll
  • 00:07:16 also increment or add deeper eyes in the
  • 00:07:18 next step so with that I'm creating a
  • 00:07:21 new entry I'll give it a key to be the
  • 00:07:25 product ID here in this step I'm also
  • 00:07:28 assigning it to the stored items sub
  • 00:07:30 chest to involve in one step here so in
  • 00:07:33 the next step here I'll then increase
  • 00:07:36 the quantity by one and I'll of course
  • 00:07:39 also change my price to be equal to my
  • 00:07:44 items price and then of course times my
  • 00:07:49 quantity just to make sure that the
  • 00:07:55 price of the screw and that is referring
  • 00:07:59 to the group here is the price of the
  • 00:08:01 individual item times D well quantity of
  • 00:08:04 the this individual item of course I
  • 00:08:07 also have to go to my total quantity and
  • 00:08:11 increase this by one and the same is
  • 00:08:15 true for the total price which should be
  • 00:08:19 stored item price so D prior or which
  • 00:08:25 gets added the aggregated price of this
  • 00:08:29 product group so hope this is clear how
  • 00:08:31 this works that I'm even adding a new
  • 00:08:34 product group if the product hasn't been
  • 00:08:36 added to the cart before or if it has
  • 00:08:38 been added then I'm skipping this step
  • 00:08:40 here and I'm only increasing quantity
  • 00:08:42 and price this is all I'm doing here in
  • 00:08:44 this ad function now back to the top
  • 00:08:47 here since I'm adding my old cart
  • 00:08:51 currently I'm only adding the old items
  • 00:08:53 however I can improve this I can change
  • 00:08:56 this to be old card and then access the
  • 00:08:59 items of my old card and here of course
  • 00:09:02 the total quantity and then here the
  • 00:09:06 total price and as I explained this is I
  • 00:09:09 only needed because I'm recreating the
  • 00:09:11 card whenever I do something with it
  • 00:09:13 whenever I add new items so therefore
  • 00:09:17 I'm passing the old card I'm well
  • 00:09:19 basically fetching all the old data
  • 00:09:21 fetching all the items already in the
  • 00:09:24 car total quantity a price of course
  • 00:09:26 and then I am able to call my ad
  • 00:09:28 function here to add a new item to my
  • 00:09:31 card here that's all I'm doing here now
  • 00:09:34 I want to add another function here I'll
  • 00:09:37 name it generate array and what this
  • 00:09:40 function will allow me to do is it will
  • 00:09:43 give me my card items as an array
  • 00:09:46 because remember currently items will be
  • 00:09:49 an object it needs to be an object
  • 00:09:51 because my arm my items here are stored
  • 00:09:56 with a key B of being the product ID so
  • 00:09:59 I need to be able to have kind of well a
  • 00:10:02 JavaScript object because anion area
  • 00:10:04 would not allow me to do this I can't
  • 00:10:06 set my own key in an array so therefore
  • 00:10:09 I only to be able to transform it into
  • 00:10:13 an array if I want to output it in a
  • 00:10:15 list or something like this so I'll
  • 00:10:16 write a helper function for this I'll
  • 00:10:18 write my rule the empty array which I
  • 00:10:21 will return in the end and then I will
  • 00:10:23 have a simple for loop where I'll loop
  • 00:10:26 through my items for the keys in my
  • 00:10:32 items here specifically and I will push
  • 00:10:35 an element on my array and the element I
  • 00:10:38 want to push of course is the value of
  • 00:10:42 each of my item so D individual item
  • 00:10:45 itself and then I will return my array
  • 00:10:50 and remember this is just needed to be
  • 00:10:53 able to then output a list of my product
  • 00:10:55 groups later on so that's the card
  • 00:11:00 constructor and
  • 00:11:02 to sum it up what it does is it
  • 00:11:05 basically gets the old card when we
  • 00:11:09 created every creator the first time
  • 00:11:11 this will be an empty JavaScript object
  • 00:11:13 we will then assign the values of the
  • 00:11:16 old cards so items quantity and price we
  • 00:11:19 have a function to be able to add a new
  • 00:11:21 item to the card and here we have to
  • 00:11:25 check if this item already or this item
  • 00:11:27 group this product group already exists
  • 00:11:30 in the card if not we create a new one
  • 00:11:33 if yes what we don't we then just access
  • 00:11:36 to the old one existing group in both
  • 00:11:39 ways after this first step we increase
  • 00:11:43 the quantity by one and we will adjust
  • 00:11:46 the price and of course we also update
  • 00:11:48 the total quantity in price so with all
  • 00:11:51 that done I'll head over to the index
  • 00:11:53 chess routes file here where I will have
  • 00:11:56 my Add to Cart route here and here I'll
  • 00:12:01 create my chart as explained a new card
  • 00:12:03 will be created each time we add a new
  • 00:12:06 item but of course I want to pass my old
  • 00:12:08 card if I do have this
  • 00:12:10 so I'll access my session and here our
  • 00:12:13 latest or even a card property so I
  • 00:12:16 check if this card property exists with
  • 00:12:19 a ternary expression here and if it does
  • 00:12:22 exist then I will pass my old card
  • 00:12:25 otherwise as explained I'll pass an
  • 00:12:28 empty JavaScript object so that's all
  • 00:12:31 I'm doing here just making sure that if
  • 00:12:33 I already have a card in a session I'm
  • 00:12:35 passing that otherwise well empty object
  • 00:12:38 with that all next use Mongoose to find
  • 00:12:44 my product here find it by ID I'm
  • 00:12:46 getting the product ID through the
  • 00:12:48 parameter here and of course I'll also
  • 00:12:52 specify my callback here and inside this
  • 00:12:59 callback here you would of course also
  • 00:13:02 check if we have an error and in this
  • 00:13:06 case you want to return a response let's
  • 00:13:09 simply say we return a redirect to the
  • 00:13:13 root page of course in a real
  • 00:13:14 application you probably
  • 00:13:15 wanted to a little bit more show some
  • 00:13:17 error message and so on but I want to
  • 00:13:19 focus on the other part here so if we
  • 00:13:22 don't have an error and that's the case
  • 00:13:25 I'm assuming here then I will add
  • 00:13:28 approach product product to my card here
  • 00:13:32 so call the add method on my card object
  • 00:13:35 which I created here and of course I
  • 00:13:39 need to pass my product the one I just
  • 00:13:41 fetched from the database and the
  • 00:13:43 product ID to identify it or to create
  • 00:13:46 the identifier and yes of course you
  • 00:13:48 could only pass the product and extract
  • 00:13:50 the ID in the add method but this way
  • 00:13:53 it's written a bit more generic and you
  • 00:13:56 could also use it if the product you
  • 00:13:58 passed doesn't have the ID itself so
  • 00:14:02 here I'm next storing this in my card
  • 00:14:06 object in my session just like that and
  • 00:14:09 the Express session will automatically
  • 00:14:12 save with each response we sent back so
  • 00:14:16 we don't have to save this it will be
  • 00:14:17 saved as soon as the response has been
  • 00:14:20 sent and therefore our session is safe
  • 00:14:23 and then I'll also redirect duty let's
  • 00:14:27 say product page so with all that um
  • 00:14:33 would probably have a working session
  • 00:14:37 and card but you wouldn't be able to see
  • 00:14:40 this right so in order to see this what
  • 00:14:43 I'll do is I'll just log my session card
  • 00:14:48 here and increase the size of my console
  • 00:14:53 restart the server and then just have a
  • 00:14:58 look I wanted to say but we don't have
  • 00:15:00 to have a look because I forget forgot
  • 00:15:02 one thing I just remember that of course
  • 00:15:05 also need to import my card here at the
  • 00:15:07 top so require models cart that's of
  • 00:15:13 course important otherwise we will would
  • 00:15:15 get an error for sure so now with that
  • 00:15:19 I'll restart the server
  • 00:15:23 reload this page and I'll click on add
  • 00:15:26 to shopping cart to get a not found page
  • 00:15:29 now the reason for that is that I forgot
  • 00:15:34 something in my shop your Add to Cart of
  • 00:15:36 course also expects to get the parameter
  • 00:15:39 so here when I access my Add to Cart
  • 00:15:43 route I should probably add this so
  • 00:15:47 enter handlebars here to simply access
  • 00:15:50 the ID of my product so with that I
  • 00:15:54 don't even need to restart the server
  • 00:15:56 because I only changed my template I'll
  • 00:15:58 navigate back to the product page and
  • 00:16:01 I'll try this again now at least you get
  • 00:16:04 a real error so let's see what happened
  • 00:16:06 you probably got here is maybe a bit
  • 00:16:10 hard to spot you could think that this
  • 00:16:13 line would be the errors the problem
  • 00:16:14 since we try to access something on an
  • 00:16:17 undefined object however this items only
  • 00:16:20 undefined because if I pass old-car to
  • 00:16:22 be an empty java script object then of
  • 00:16:28 course old card items is undefined
  • 00:16:30 instead of an old in instead of an empty
  • 00:16:33 JavaScript object because items doesn't
  • 00:16:36 exist on that empty object
  • 00:16:38 so when fix would be to not pass an
  • 00:16:41 empty object but instead to set the
  • 00:16:45 items key here like this and make this
  • 00:16:49 an empty object as well and this should
  • 00:16:51 work but another way of course is to fix
  • 00:16:55 it in here to basically check if old
  • 00:16:59 card is an empty object and then assign
  • 00:17:02 it so I'll go with the first fix here by
  • 00:17:09 setting items equal to an empty
  • 00:17:11 javascript object and now if I rerun my
  • 00:17:15 server here and I can just refresh here
  • 00:17:19 to try to re add this this kind of
  • 00:17:22 seemed to work so let's have a look if I
  • 00:17:27 can see it and you can see the console
  • 00:17:30 that we printed our card here however
  • 00:17:33 till quantity until
  • 00:17:35 don't look necessarily right the
  • 00:17:39 individual object here looks fine though
  • 00:17:42 we got the object quantity and the price
  • 00:17:44 but total quantity and price weren't
  • 00:17:47 updated so if you have a look at our
  • 00:17:49 card these two functions here where
  • 00:17:54 these two lines failed now we have this
  • 00:17:58 failure for the same reason as why the
  • 00:18:00 items had problems when we pass an empty
  • 00:18:04 object to create this new card or as an
  • 00:18:08 old card then we set the total quantity
  • 00:18:11 and price to these fields in the old
  • 00:18:13 card which is undefined at the beginning
  • 00:18:15 now then we would try to increment and
  • 00:18:18 you find an add a new price to undefined
  • 00:18:20 them that of course won't work so in
  • 00:18:22 order to fix this we also need to change
  • 00:18:26 this here and now I'm going to show you
  • 00:18:30 the other way I was mentioning before
  • 00:18:34 currently I'm passing this empty card
  • 00:18:39 with the empty items and I could do the
  • 00:18:42 same for passing quantity and price to
  • 00:18:44 be equal to zero but I don't really like
  • 00:18:46 that approach I don't want to have the
  • 00:18:47 logic in this fall so but go back to
  • 00:18:50 passing an empty object here instead
  • 00:18:53 I'll go back to my cart and I'll use
  • 00:18:56 another operator I'll use the boolean
  • 00:18:58 over here to say either do this but this
  • 00:19:02 if this is undefined use an empty object
  • 00:19:04 and I'll do the same here if the Sun you
  • 00:19:07 find well then use zero and the same for
  • 00:19:11 the price and with that I'm giving my
  • 00:19:13 card to flexibility to assign the right
  • 00:19:16 values depending on whether it's brand
  • 00:19:19 new and an old card isn't existing or
  • 00:19:21 not so that is certainly a great way to
  • 00:19:24 solve this issue now with that I'm
  • 00:19:28 saving this and I'll restart my server
  • 00:19:30 now the issue you'll probably have is
  • 00:19:34 you already have a session because it
  • 00:19:37 was created but it's kind of broken it
  • 00:19:40 does have this not a number quantity or
  • 00:19:43 stuff like that so in order to easily
  • 00:19:46 reset it you may open up your developer
  • 00:19:48 tools and
  • 00:19:49 Chrome for example go-to cookies
  • 00:19:51 localhost and simply delete this cookie
  • 00:19:55 here does connect Mongo cookie that's
  • 00:19:57 the cookie of the session and now if you
  • 00:19:59 load your page your session will be gone
  • 00:20:02 so now if I add a new shopping cart item
  • 00:20:05 and I'll go back to my project let's
  • 00:20:08 have a look now this looks much better
  • 00:20:10 we got this item we got a quantity of 1
  • 00:20:12 a price of 40 and this matches the
  • 00:20:15 overall quantity and price now if I add
  • 00:20:18 the second time and I go back well that
  • 00:20:22 looks almost good
  • 00:20:25 we got quantity to price 80 total
  • 00:20:28 quantity and till Bryce is wrong and the
  • 00:20:32 reason for that is of course that we
  • 00:20:34 have an error here when we increase the
  • 00:20:39 total price we take it the old total
  • 00:20:41 price plus the store title price now
  • 00:20:44 that is of course not correctly because
  • 00:20:46 the store item price is also quantity
  • 00:20:49 times price so therefore I'm adding too
  • 00:20:52 much but of course a very easy fix is to
  • 00:20:56 simply take the item price so now I'm
  • 00:21:02 not taking the aggregate price but only
  • 00:21:04 the price of the single item which was
  • 00:21:05 added so now if i restart this and of
  • 00:21:10 course i'll also reset my session again
  • 00:21:15 by deleting this cookie if i now reload
  • 00:21:19 i'll add this to shopping cart we'll
  • 00:21:22 have a look this looks good if i added a
  • 00:21:25 second time this now also looks good now
  • 00:21:28 if i add another item let's say well the
  • 00:21:30 for craft you see we now get two items
  • 00:21:32 quantity two price 80 thank you and the
  • 00:21:36 overall also looks great
  • 00:21:38 so that has been quite some work but i
  • 00:21:40 hope you saw how we got there and i hope
  • 00:21:43 these little errors helped you to
  • 00:21:46 understand where the difficult parts
  • 00:21:49 here are and how to get them right and
  • 00:21:51 how to also well think about this
  • 00:21:55 process of while creating this card
  • 00:21:58 brand new each time and having to
  • 00:22:01 consider
  • 00:22:02 the aspect of ever having an empty cart
  • 00:22:05 or existing items adding the price
  • 00:22:07 correctly and so on it's more difficult
  • 00:22:11 than you think but in the end also not
  • 00:22:13 that difficult if you look at that code
  • 00:22:15 here so that has been the creation of
  • 00:22:18 the cart the next step of course is to
  • 00:22:20 also well see it somewhere on the page
  • 00:22:22 and not only here in our console