1

I am working on a small JavaScript application that will users to click on buttons on the page and pass it through to thier basket. The problem I have with doing this is I am unsure as to handle multiple buttons within the same function. I do not want to have to write out different functions for each button.

I am trying to do it OOP and have this so far:

var shop = {};

shop.items = [];

shop.Item = function(item, description, price) {
    this.item = item;
    this.description = description;
    this.price = price;
};

shop.print = function() {
    var itemCon = document.getElementById('items'),
        html = "";
    for(var i = 0; i < this.items.length; i++) {
        html += '<div id="item">';
        for(prop in this.items[i]) {
            html += '<p><span class="title">' + prop + '</span>: ' + this.items[i][prop] + '</p>';
        };
        html += '<button id="' + this.items[i].item + '">Add to Basket</button>'
        html += '</div>';
    };
    itemCon.innerHTML += html;
};

shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");

var basket = {};

basket.items = [];

basket.Item = function(item, description, price) {
    this.item = item;
    this.description = description;
    this.price = price;
};

basket.add = function(data) {
    this.items[items.length] = new Item(data.item, data.description, data.price);
};

basket.costCalculate = function() {
    var cost = 0,
        html = "Total: " + cost;
    for(var i = 0; i < this.items.length; i++) {
        cost += items[i].price;
    };
    return html;
};

basket.print = function() {
    var output;
    for(var i = 0; i < this.items.length; i++) {
        for(prop in this.items[i]) {
            console.log(prop + ":  " + this.items[i][prop]);
        };
    };
};

function init() {
    shop.print()
};
window.onload = init;

How would I determine what item has been clicked in order to run basket.add(data). How would I also pass through the data to that function for each item.

Also how would one go about implementing closure? I understand that it is inner functions having access to the variables of the outer functions, is what I am doing working with closure so far?

hudsond7
  • 666
  • 8
  • 25

1 Answers1

2

Okay, you've made a pretty good start but here are a couple suggestions:

  1. It's probably a good idea to only have one instance of each Item. By that I mean it looks like you create a bunch of Items for to populate your shop's inventory, so for example:

    var coat = new Item("Coat", "Warm", 20);
    shop.items.push(coat);
    

    Now when you click on your UI element, you ideally want this same instance of coat to go into your basket as well, so:

    // User clicks on UI element, which triggers the following to execute:
    basket.add( someItemIdentifier );
    

    So now if you ever decide to increase all your prices by $10, you can simply do:

    shop.increasePricesBy = function(amount) {
        for(var i = 0; i < shop.items.length; i++) {
            shop.items[i].price += amount;
        }
        // execute some function to update existing baskets' totals
    };
    

    I hope this makes sense for why there should be one instance of each item that multiple collections refer to.

    This begs the question how you can tie the customer's interaction to adding the correct item. One solution could be to use arbitrary IDs to track items. For example:

    // Create new item with some randomly generated ID
    var coat = new Item({
        id: "93523452-34523452",
        name: "Coat",
        description: "Warm",
        price: 20
    });
    shop.items = {}; // Use a hash so it's easier to find items
    shop.items[coat.id] = coat;
    

    And your UI element could be some div like so:

    <div class="add-product-button" data-id="93523452-34523452">
    

    Add your click handler:

    // Pure JS solution - untested
    var clickTargets = document.getElementsByClassName("add-product-button");
    for(var i = 0; i < clickTargets.length; i++) {
        var clickTarget = clickTargets[i];
        clickTarget.onClick = function() {
            var itemID = clickTarget.getAttribute("data-id");
            var item = shop.items[itemID];
    
            basket.add(item);
        };
    }
    
    // Equivalent jQuery code
    $(".add-product-button").click(function() {
        var id = $(this).attr('data-id');
        var item = shop.items[id];
        basket.add(item);
    });
    

    While your basket implements add something like:

    basket.add = function(items) {
        this.items.push(item);
    };
    

    And your costCalculate method gets a whole lot easier:

    basket.costCalculate = function() {
        var cost = 0;
        for(var i = 0; i < this.items.length; i++) {
            cost += this.item[i].price;
        }
        return cost;
    };
    
  2. Instead of doing this:

    shop.items[shop.items.length] = new shop.Item("Coat", "Warm", "20");
    

    You can instead do:

    shop.items.push(new shop.Item("Coat", "Warm", "20");
    
  3. Probably a good idea to use a number instead of a string to represent the price.

  4. In your shop.print loop, you probably don't want to hard code <div id="item"> because that will result in multiple divs with the same id.

  5. Finally, I'm not going to try to answer your closure question here because I think that's been answered better than I can already so I'll just link you to some great resources that helped me understand it:


Let me know if you have any questions, I'm totally down to discuss them.

Community
  • 1
  • 1
Vidur
  • 1,442
  • 2
  • 17
  • 37
  • Thank you for the quick reply. I understand almost all that you have said it is very useful. The only part I dont understand is: $(".add-product-button").click(function() { var id = $(this).attr('data-id'); var item = shop.items[id]; basket.add(item); });. Isnt this Jquery? – hudsond7 Nov 24 '14 at 11:14
  • You're right. I didn't read the part of your question that asked for pure JS. Updated my answer to include both, because one just reads better than the other :) – Vidur Nov 24 '14 at 11:26
  • Thank you very much for all the help, you have greatly helped me further my understand of coding practice in JavaScript. – hudsond7 Nov 24 '14 at 11:27
  • Douglas Crockford has some useful things in the articles and videos that are out there but a warning should be given; what he calls "classical inheritance" he never does correctly but instead of doing it right he blaims JavaScript. So it may be better to skip the part about classical inheritance. – HMR Nov 24 '14 at 13:56