"shop"
Bootstrap 3.0.0 Snippet by evarevirus

<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css"> <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script> <script src="//code.jquery.com/jquery-1.11.1.min.js"></script> <!------ Include the above in your HEAD tag ----------> <section class="shop js-shop"> <script> /* * Make sure to read this from the bottom up to see what's going on. */ function Item(name, description, price, photo) { // Make sure that the object is accessible from at any scope inside it var _this = this; (function init() { // Initialise Item object, probably from JSON file _this.name = name; _this.description = description; _this.price = price; _this.photo = photo; // Count and cost start off at 0 _this.count = 0; _this.cost = 0; // Have the wrapper, which is the node for this item _this.wrapper = null; // Their values will need to change, so keep track of them here _this.countView = null; _this.costView = null; _this.countHidden = null; _this.costHidden = null; })(); } // Update the visible and hidden fields for count and cost Item.prototype.update = function() { var _this = this; _this.costView.textContent = poundify(_this.cost); _this.countView.textContent = _this.count; _this.costHidden.value = _this.cost; _this.countHidden.value = _this.count; }; Item.prototype.addItem = function(e) { var _this = this; // Prevent button from submitting the form e.preventDefault(); // Add to the count and price _this.count++; _this.cost += _this.price; // Update the item's markup _this.update(); }; Item.prototype.removeItem = function(e) { var _this = this; // Prevent button from submitting the form e.preventDefault(); // Do not allow count/cost to go negative if (_this.count > 0) { // Subtract from the count and price _this.count--; _this.cost -= _this.price; // Update the item's markup _this.update(); } }; // Prints the item to a container // It's a big function with lots of similar code, but no logic. // Counter is used for creating PHP POST variable Item.prototype.print = function(container, counter) { var _this = this; // Create all elements that will make up the HTML element _this.wrapper = document.createElement("article"); var header = document.createElement("header"); var name = document.createElement("h2"); var nameHidden = document.createElement("input"); var img = document.createElement("img"); var desc = document.createElement("p"); var moneyContainer = document.createElement("div"); var price = document.createElement("span"); _this.costView = document.createElement("span"); var countContainer = document.createElement("div"); var remove = document.createElement("button"); _this.countView = document.createElement("span"); var add = document.createElement("button"); // Add hidden inputs that will post their data with the form _this.countHidden = document.createElement("input"); _this.costHidden = document.createElement("input"); // Using BEM for Object Oriented styling/markup _this.wrapper.classList.add("item"); // Give the item a name and append the name and header to the wrapper name.appendChild(document.createTextNode(_this.name)); name.classList.add("item__name"); nameHidden.setAttribute("type", "hidden"); nameHidden.setAttribute("name", "item["+counter+"][name]"); nameHidden.setAttribute("value", _this.name); header.appendChild(name); header.appendChild(nameHidden); header.classList.add("item__header"); _this.wrapper.appendChild(header); // Give the image a source, alt and title, then append to wrapper img.setAttribute("src", _this.photo); img.setAttribute("alt", _this.name); img.setAttribute("title", _this.name); img.classList.add("item__img"); _this.wrapper.appendChild(img); // Now add the description desc.appendChild(document.createTextNode(_this.description)); desc.classList.add("item__description"); _this.wrapper.appendChild(desc); // Price and cost are displayed together in boxes // Use poundify function to make them into prices price.appendChild(document.createTextNode(poundify(_this.price))); _this.costView.appendChild(document.createTextNode(poundify(_this.cost))); price.classList.add("item__price"); _this.costView.classList.add("item__cost"); moneyContainer.classList.add("item__money-container"); moneyContainer.appendChild(price); moneyContainer.appendChild(_this.costView); _this.wrapper.appendChild(moneyContainer); // These inputs will hold the information to be posted to the php file _this.countHidden.setAttribute("type", "hidden"); _this.costHidden.setAttribute("type", "hidden"); _this.countHidden.setAttribute("name", "item["+counter+"][count]"); _this.costHidden.setAttribute("name", "item["+counter+"][cost]"); _this.countHidden.setAttribute("value", _this.count); _this.costHidden.setAttribute("value", _this.cost); _this.wrapper.appendChild(_this.countHidden); _this.wrapper.appendChild(_this.costHidden); // Now add + and - buttons, and count display remove.appendChild(document.createTextNode("-")); _this.countView.appendChild(document.createTextNode(_this.count)); add.appendChild(document.createTextNode("+")); remove.classList.add("item__remove"); remove.classList.add("js-remove"); _this.countView.classList.add("item__count"); add.classList.add("item__add"); add.classList.add("js-add"); // Add click event listeners remove.addEventListener("click", _this.removeItem.bind(_this), false); add.addEventListener("click", _this.addItem.bind(_this), false); countContainer.classList.add("item__count-container"); countContainer.appendChild(remove); countContainer.appendChild(_this.countView); countContainer.appendChild(add); _this.wrapper.appendChild(countContainer); // Finally, add the wrapper to its container container.appendChild(_this.wrapper); }; // Create an item object and add it to the shop Shop.prototype.addItem = function(element) { this.items.push(new Item( element.name, element.description, element.price, element.photo)); }; function Shop(filename) { // Allows this keyword to be used in all contexts var _this = this; (function init() { // Get the array of items in the JSON file var items = makeXHR(filename, function(s) { return JSON.parse(s); }).items; // Initialise the list of items as an empty array _this.items = []; // Add each element to the shop items.forEach(function (element, index, array) { _this.addItem(element); }); // HTML elements for the shop _this.vatView = document.querySelector("input[name=vat]"); _this.subtotalView = document.querySelector("input[name=subtotal]"); _this.deliveryView = document.querySelector("input[name=delivery]"); _this.totalCostView = document.querySelector("input[name=total_cost]"); })(); } // Print each item in the shop Shop.prototype.print = function(container) { var _this = this; _this.items.forEach(function (element, index, array) { element.print(container, index); }); }; // Although inconsequential, it keeps the code grouped together and scoped (function() { // Get the shop element in the document var shopContainer = document.querySelector(".js-shop"); // Initiate the shop object var shop = new Shop("https://codepen.io/_Billy_Brown/pen/FAucG.js"); shop.print(shopContainer); setCardTypeListener(); addChecks(); highlightRequired(); })(); // Convert amount into pounds function poundify(amount) { return "£" + amount.toFixed(2); } // Make HTTP request to a location and run the callback on its response function makeXHR(loc, callback) { var req = new XMLHttpRequest(); req.open("get", loc, false); req.send(); // Return the result of the callback return callback(req.responseText); } </script>
*, button, input, select { box-sizing: inherit; } html { background: #e5eaee; box-sizing: border-box; font-family: sans-serif; } body { margin: 0; } .shop { align-items: center; display: flex; flex-flow: row wrap; justify-content: space-around; } .item { background: white; box-shadow: 0 2px 5px #c5cacc; flex: 0 auto; margin: 1em; text-align: center; width: 15em; } .item__name { text-transform: capitalize; } .item__money-container, .item__count-container { display: flex; } .item__price, .item__cost, .item__remove, .item__count, .item__add { flex: 1; height: 2.5rem; line-height: 1rem; padding: 0.75rem; } .item__price, .item__cost { position: relative; } /* add a name just above the field */ .item__price::before, .item__cost::before { display: block; font-size: 0.8em; position: absolute; text-align: center; top: -6px; right: 0; left: 0; } .item__price::before { content: "price"; } .item__cost { color: #59b; } .item__cost::before { content: "cost"; } .item__remove, .item__add { appearance: none; border: none; color: white; cursor: pointer; font-size: 1.25em; margin: 0; outline: none; } .item__remove { background: #f77; } .item__count { background: #ed6; } .item__add { background: #6d6; }

Related: See More


Questions / Comments: