1. HTML and Styles
That’ll leave us with a very barebones HTML file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
Note that our head now includes a
data.js file. For our example we’re going to type our inventory data right into
data.js, but when doing it "for real" this file could retrieve the data from anywhere (a file, database, the web, etc).
application.js file and just start it with the document ready wrapper:
1 2 3
The create a
styles.css and paste in this style code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
Load the page in your browser and you won’t see much! It’ll just be a header and an empty cart.
2. Loading External Data
We’re going to store the inventory information in
1 2 3 4 5 6 7
]. Each object in the array is marked with
}. Then inside the objects there are key/value pairs for the keys price, name, stock, and product_id.
Loading the Data
Go over to your
application.js. Let’s prove that
inventory exists by putting this inside your document ready block:
We’re taking the
rawInventory data and turning it into a jQuery object so it’s easier to work with, then storing that into
inventory. Then we alert the size of that object which should display 5. If that works then we know the data is loaded and accessible!
Building a Prototype
index.html and add this prototype inside the inventory DIV:
1 2 3 4 5 6 7 8
application.js, try this:
Refresh your browser and the blank inventory item is gone. We’ve got it loaded into
prototypeItem, so now we can create our actual product listings.
Building Products from the Prototype
We’ve got the
prototypeItem, we’ve got the
inventory, now we need to iterate through the inventory and inject a copy of the prototype into our listing for each one. That’s complex, so let’s do it one step at a time.
each method call inside your document ready:
1 2 3
this refers to the OLN object inside of
inventory. We can access the attributes using a dot notation like
this.name. Try this in your browser and ensure each of your items is alerted.
The first step is to create a copy or a
clone of the
prototypeItem. Add this inside your
That creates a "deep clone" of
prototypeItem. Let’s set the first attribute:
Within the object
item, find any H3s and replace their
text with the value of
this.name. Then insert it into the inventory DIV:
Refresh your browser and your items should all appear. They’ll have names, but the other attributes are blank.
One thing you’ll want to change is the item’s DIV id. Use the
attr method to set it to a unique id like "product_6" for each item. The
attr method takes two parameters: the name of the attribute to change and the value to change it to. The attribute you want to change is just
Once you’re setting the name, price, quantity, id and displaying them in the inventory, then this iteration is done.
3. Adding Items to the Cart
Those "Add to Cart" links are mocking us. They don’t do anything!
We need to add a
click listener. Each link will need it’s own listener, so it’s easiest to add it within your
inventory.each loop. Start with this:
1 2 3
Try it in your browser. What’s up with that "undefined"?
this isn’t what we think it is. When the function actually gets executed,
this refers to the item’s DIV, not the data we pulled out of the
inventory array. Hmmm. What can we do with that? Try changing you
alert to this:
Try it in the browser. Looks promising, right? That’s pulling the id that we set which holds the product id from the data array. Our cart could use that information to find the item in the inventory, get its price, etc.
Building Up the Cart
It looks like we can get enough information when the "Add to Cart" link is clicked, but what are we going to do with it? The cart is basically a blank DIV right now. Let’s set it up like a spreadsheet where each inventory item has a row and a quantity ordered.
We can use the same prototype style we did for the inventory listings. Add this plain HTML into your cart DIV:
1 2 3 4 5
Go back to your
application.js and look at how we worked with
prototypeItem. Add a similar set of instructions to build up
append it to the cart DIV. Refresh your browser and make sure a line shows up for each of your products.
Connecting the Click to the Cart
Now we need to connect the click action to the cart. When a user clicks on an add to cart link we need to…
- Find the link’s DIV’s ID
- Find the DIV in the cart with the same ID
- Increment the quantity in the cart item
alert line finds the proper
id value. Let’s store that into a variable named
targetId. Then find the actual target DIV in the cart like this:
Then the only thing left is to properly update the quantity. That math is a little tricky, so let’s take a smaller step:
Refresh your browser and click the Add to Cart links. You should see the associated cart quantity change from
Dealing with Strings and Numbers
Our cart quantity is just a string. We want to increase it by one when the user clicks, but if we add a 1 to the contents of quantity it’ll just add strings resulting in "111" instead of "3". We need to…
- Find the current value in QTY
- Convert it to an integer
- Add one to it
- Store it back into QTY
Let’s first find the SPAN itself and store that into a variable:
We can pull out the
parseInt method to convert it to an integer:
From there it’s just one more line to add
current and stick it back into
quantity – you figure it out.
Then refresh your browser, click some links, and your cart quantities should increase numerically.
4. Cart Math
We’re plunking items into the cart. Let’s add a little more intelligence there to update the total items count and give the user a total price.
I thought I just made up the word prefactoring, but Wikipedia says that it exists.
Let’s apply the same pattern we used in JSTasker to group methods into a name space. I want to collect a few methods that will be responsible for tending the cart, just like we did with the To-Do list. Up at the top of your
application.js, let’s start with this:
1 2 3 4 5 6 7 8
Again we’re using the "Object Literal Notation" here to namespace three methods. We’ll call
updateCart from our click instruction, and it’ll call
updateCartTotal for us.
Calling the Updaters
Let’s start by inserting an
alert line within
updateCart that says "Updating the cart", one in
updateCartItemCount that says "Updating the item count", and one in the
updateCartTotal that says "Updating the total".
Refresh your browser and nothing should happen. Why do I bother with putting in these
updateCart and instead just put instructions, your script would either fail to load OR it’d execute the
alert as soon as it was read (when the page was loaded). This would be quick clue that something was wrong.
But our methods aren’t getting called yet which is correct. Go down you
application.js and find the
item.on('click'...) listener. As the last instruction there, add a call to
Refresh your browser, click an add to cart link, and the three alerts should pop up. If you’re satisfied that things are wired together properly, remove the three alert lines.
updateCartItemCount function should now be blank. Here’s what we need it to do:
- Find all the items in the cart
- Gather the quantities specified for each one
- Add them together
- Save the result into the text span "X items in cart"
Finding the Items
Each item type has it’s own DIV with the class name "cart_item". Write a selector that finds them all and stores them into a variable named
Try popping an alert that tells you how many items there are. It should be the same as your number of products in the inventory.
Gathering the Quantities
We’ll need to iterate through the list of items, detect their
"qty" SPAN, get it’s contents, convert it to an integer, then add that to the total. Here’s the basic structure:
1 2 3 4 5 6
Storing the Value
Then you just need to find the SPAN with ID
'cartQuantity' and store
total into it’s
Refresh your browser and confirm that things are working. Make sure your count is accurate!
Having completed the
updateCartItemCount, it becomes apparent that we’re currently setup to do things twice. The
updateCartTotal function needs to do almost the same thing. The only difference is that instead of adding the quantity into total we want to multiply quantity times price and add that.
Refactoring necessary? Probably. But let’s do it the simple way first. Copy & Paste! Grab the body of
updateCartItemCount and paste it into
updateCartTotal count. Then we need to make a few changes:
valuefeels like the wrong name, rename it to
quantityis found, find
- Change the text inserter to put
totalinto the SPAN with ID
I think you can do this on your own, go to it! One little note: when you pull out the price string and want to convert it to a number, use
parseFloat so the cents don’t get truncated.
I Hate Floats
Dealing with floating point numbers is always a pain. At least in my experimenting, every once in awhile my total would jump to having really small fractions after the decimal. Ugh! In general, when working with prices, I recommend you store prices in cents so you can use integers. But let’s just leave these as floats and fix this presentation issue.
Find the line where you’re inserting
total into the
cartQuantity SPAN. Instead of just inserting
toFixed like this:
This project, like most shopping carts, could go a hundred directions. Here are some ideas to try adding on:
- Add a clickable link that clears the cart
- Add a keyboard shortcut that clears the cart
- Alphabetize the items in the inventory
- Decrease the number of items in inventory when they’re added to the cart
- When stock is low, change the listing to say "Only X Left!"
- When an item is out of stock, grey out or remove it from the inventory
- Prevent the cart from having more of an item than are in stock
- Add a link to remove individual items from the cart
- Change the cart to use a text field so the quantity could be easily manipulated and the totals updated
- Implement Drag & Drop so the items can be dragged and dropped in the cart