0

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>
asked Feb 21, 2012 at 12:23
1
  • 1
    Instead of those dozen .parent()s, you should try .closest(). Commented Feb 21, 2012 at 12:27

4 Answers 4

2

There are a couple of issues with your code:

  • array_of_items is 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 if statement is useless, you don't do anything with the return value.

  • I think you want += 1 instead of = +1 inside the if branch. += 1 increases the current value by one whereas = +1 is the same as = 1, i.e. it is setting the value to one.

  • In your else branch, you also have to set the counter (your array entry) to 1, 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].

answered Feb 21, 2012 at 12:37
Sign up to request clarification or add additional context in comments.

5 Comments

this one works well, but only with one product.. if I add another - different one, then count for both products are set to 1 and increases +1 to each when I add something..
@Guy: Products must have different titles, i.e. <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.
They do heve different titles.
@Guy: Then it should work, maybe something else is wrong with your code. Please create a jsfiddle.net demo.
@Guy: Ah, now I see... the problem is not the items are counted wrongly, but that each .quantity field is updated. You have to select the specific one. I updated the code. This was not clear from the code you provided.
0

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/

answered Feb 21, 2012 at 12:28

Comments

0

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
});
answered Feb 21, 2012 at 12:33

Comments

0

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]);
 }
 });
});
answered Feb 21, 2012 at 12:41

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.