What I want to do is make some sort of shopping cart. The idea is that there a are several products in the page with a "buy" button below them. When you press buy, the item is added to the list in the sidebar. If there is such a product already then only the amount (number) increases.
buy prod1 -> 1 x prod1
buy prod1 -> 2 x prod1
etc.
I can't get my array done. How can I add a product to it?
Here's my code:
HTML
<div class="product">
<div class="product_img">
<img src="images/s1.png" alt="s1" width="180" height="110" />
</div>
<div class="product_descr">
<div class="descr_title">
TITLE1
</div>
<div class="descr_text">
Aliquam sed est diam lorem, iaculis malesuada enim quis nequ
</div>
<div class="descr_buy_price">
<div class="price">
2.40 Ls
</div>
<div class="buy">
<a href="#">BUY</a>
</div>
</div>
</div>
<div class="hidden">
<div class="list_item" title="i1">
<div class="item_name"> <span class="quantity"></span> x Produkts1</div>
<div class="item_price">8.99 Ls</div>
<div class="item_x">
<a href="#">
<img src="images/x.png" alt="x" />
</a>
</div>
</div>
</div>
</div>
JS
<script type="text/javascript">
$(document).ready(function() {
$('.buy a').click(function() {
var array_of_items = {};
array_of_items[$(this).parent().parent().parent().parent().find('.list_item').attr('title')] == 1;
if(array_of_items[$(this).parent().parent().parent().parent().find('.list_item').attr('title')] > 0){
array_of_items[$(this).parent().parent().parent().parent().find('.list_item').attr('title')] = +1;
$('.quantity').text(array_of_items[$(this).parent().parent().parent().parent().find('.list_item').attr('title')]);
}
else {
$(this).parent().parent().parent().parent().find('.list_item').clone().appendTo('#all_items');
$('.quantity').text(array_of_items[$(this).parent().parent().parent().parent().find('.list_item').attr('title')]);
}
});
});
</script>
4 Answers 4
There are a couple of issues with your code:
array_of_itemsis not persistent, it only exists during one execution of the event handler. You want to make it persistent over multiple clicks, so you have to declare and initialize it outside the handler.The comparison above the
ifstatement is useless, you don't do anything with the return value.I think you want
+= 1instead of= +1inside theifbranch.+= 1increases the current value by one whereas= +1is the same as= 1, i.e. it is setting the value to one.In your
elsebranch, you also have to set the counter (your array entry) to1, otherwise an item is never added to the list.You are accessing the products title multiple times. Store its value in a variable to avoid calling
....parent().parent()...repeatedly. That will make your code easier to read. Also have a look at.closest()[docs].
Here is an improved version of your code:
var items = {}; // needs to be outside
$('.buy a').click(function() {
var $item = $(this).closest('.product').find('.list_item'),
title = $item.attr('title');
if(typeof items[title] === 'undefined') { // item was not added yet
items[title] = 0;
$item.clone().appendTo('#all_items');
}
items[title] += 1; // increase quantity
$('#all_items') // update the correct quantity field
.find('.list_item[title="' + title + '"]')
.find('.quantity').text(items[title]);
});
As additional note: You are actually using an object, not an array, but that is correct in this situation. Arrays associate consecutive numerical indexes with values whereas objects can be used to associate any kind of keys (well, in JS they are all strings) with values, like a hash table [Wikipedia].
5 Comments
<div class="list_item" title="i1"> must be different for each product. Or use another value to identify them, it does not have to be this one. Also make sure that each product is in its own <div class="product"> element.First of all, as you initiate array_of_items as {} — it is an object, not an array.
And as well as it is the object, you can use $.extend(). http://api.jquery.com/jQuery.extend/
Also you should really think about to use $.parentsUntil() instead of all that parent() mess. http://api.jquery.com/parentsUntil/
Comments
The best way to tackle this sort of thing is to use a template system. The simplest form of template would be a string.
var cartItem = '<div class="cart-item" id="cart-item-$ID">'+
'<p class="cart-item-name">$NAME</p>'+
'<p class="cart-item-price">$PRICE</p>'+
'</div>';
To populate the template, you would:
cartItem.
replace('$ID', identifier).
replace('$NAME', productName).
replace('$PRICE', productPrice)
You can store the product details as raw data in each button by using the data-$KEY attribute on the button element. So, when creating the button, you:
<button data-id="002" data-name="My Product" data-price="12ドル">buy</button>
To read the data, you use jQuery's .data() method:
$('button').on('click', function(e) {
e.preventDefault(); // if it's in a form
$this = $(this);
var id = $this.data('id');
var name = $this.data('name');
var price = $this.data('price');
// now populate template, and append to cart
});
Comments
The underlying problem is that you keep resetting array_of_items each time you click. In order to persist meaningful information it needs to be initialised outside the click handler. Everyhting inside a click handler is called every time you click so you need to be careful to put anything that doesn't need running outside. Anything you have outside the handler will still be accessible within it (it's a bit more complex than that, but for a simple case like your example it's more or less true)
There are a few other improvements I've included below, and the code could still be improved further. My advice is to have a really good read through the jQuery docs (at the very least the Manipulation, Traversing and selector sections) as then you can make better use of jQUery's very useful set of features.
$(document).ready(function() {
var array_of_items = {};
$('.buy').delegate("a", "click", function() {
var $this = $(this),
$item = $(this).closest(".product").find('.list_item'),
itemName = $item.attr('title');
if(array_of_items[itemName] > 0){
array_of_items[itemName] = array_of_items[itemName] + 1;
$('.quantity').text(array_of_items[itemName]);
}
else {
array_of_items[itemName] = 1;
$item.clone().appendTo('#all_items');
$('.quantity').text(array_of_items[itemName]);
}
});
});
.parent()s, you should try.closest().