Duplicate items appearing in shopping cart - javascript

I'm trying to basically build a shopping cart on a static site. Items are displayed on a table. I built this shopping cart from scratch, no external jQuery shopping cart libraries used.
There's one feature I can't seem to get to work: When a user adds an item that already exists in the shopping cart, it should only increase the quantity instead of adding the item to the table.
Here's a JSFiddle link with everything I've implemented so far and a working demo, but you can also see the code below.
Here's the JS that adds the item:
$( "#addBtn" ).click(function() {
var item = $("#orderMenu option:selected").text();
var qty = $("#orderQty option:selected").text();
var newRowContent = "<tr><td>" + qty + "</td><td>" + item + "</td>";
$("#cart-info tbody").append(newRowContent);
});
Here's the simplified HTML, for the sake of simplicity:
<table class="table" id="cart-info">
<thead>
<tr>
<th>#</th>
<th>Item</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<select id="orderMenu">
<option>Foo</option>
<option>Bar</option>
</select>
<select id="orderQty">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<button id="addBtn">ADD TO CART</button>
Here's the pseudocode I'd like to convert to jQuery but have no idea how.
(Apologies for the weird pseudocode/jQuery hybrid, I'm still learning jQuery)
for each <td> in #cart-info {
if (<td>.html() == item) {
qtyCell = the previous <td>
oldQty = Number(qtyCell.text())
newQty = oldQty + qty
qtyCell.html(newQty)
exit for loop
}
}
The website itself is written purely in HTML/CSS/JS, so it is a completely static site.
Thank you very much in advance!

Check this fiddle
new fiddle
Use the value of each option to determine if it has already been added to the table:
$( "#addBtn" ).click(function() {
var item = $("#orderMenu option:selected").text();
var item_val = $("#orderMenu").val();
var qty = $("#orderQty option:selected").text();
var newRowContent = "<tr><td class='qty'>" + qty + "</td><td data-val='"+item_val+"'>" + item + "</td>";
if ($("#cart-info tbody [data-val='"+item_val+"']").length < 1)
$("#cart-info tbody").append(newRowContent);
else {
var new_qty = parseInt($("#cart-info tbody [data-val='"+item_val+"']").prev('.qty').text())+parseInt(qty);
$("#cart-info tbody [data-val='"+item_val+"']").prev('.qty').text(new_qty);
}
});
EDIT:
fixed fiddle url
EDIT 2
new fiddle updating quantities

You can achieve it on
Maintaining a list
An array which consists of key-pair value(JSON) item ID and it's quantity as field
Ex:-
var items = [
{
itemID:101,
name:"Mobile:"
qty:1
},
{
itemID:102,
name:"Pen Drive"
qty:3
}
]
On adding a new item push the respective itemID, qty, name, etc.. into the list
On already exists then query with itemID and increment the qty field
The cart you are displaying is available in cart-info tbody so in that case make sure you have an unique ID in row(tr)
Ex: <tr id=item-101><td>1</td><td>Mobile</td></tr>
Finally update the text of the respective id with your updated quantity

Related

Reset name attribute array indexes, dynamically add remove rows

I have to post data via ajax and need the name attribute array indexes to reset.
For example:
1st row:
<select data-placeholder="Colours" class="colours chosen-select"
multiple tabindex="4" name="colours[0][]">
<option value="">Red</option>
<option value="">Orange</option>
</select>
2nd Row dynamically added:
<select data-placeholder="Colours" class="colours chosen-select"
multiple tabindex="4" name="colours[1][]">
<option value="">Red</option>
<option value="">Orange</option>
</select>
The name colours array must increment by 1 everytime I add, as well as reset the values when I remove.
I have looked around but not found any solution.
Here is what I have:
Adding:
var tbl = $("#service");
$("#addRowBtn").click(function () {
var count = $('#rowCount tr').length;
$("<tr>" +
"<td>" +
"<select data-placeholder=\"Colours\" class=\"colours chosen-select\"
multiple tabindex=\"4\"\ name=\"colours[" +
count +
"][]\">" +
"<option value=\"\">Red</option>" +
"<option value=\"\">Orange</option>" +
"</select></td>" +
"<td><i style=\"color:#d64830\" class=\"delRowBtn fa fa-minus-
circle\"></i></td></tr>").appendTo(tbl);
Deleting a row:
$(document.body).delegate(".delRowBtn", "click", function () {
$(this).closest("tr").remove();
});
I have added var count to increment the indexes, but I'm not able to reset the values when removing.
Please help!
You can try to cycle all select of your table and change the attribute "name" of each select everytime you delete an item.
$('#rowCount tr td select').each(function(idx, item){
$(item).attr("name", "colours[" + idx + "][]")
});
update
like suggest #ChayimFriedman the cool version of previous suggestion
$('#rowCount select').attr('name', function(idx) { return "colours[" + idx + "][]"; });

How can I perform dynamic operations on dynamically added elements?

My objective:
Filling in the 'performer-payments' table dynamically with JS/Jquery
For each (dynamically added) row in the table, one of the data cells contains a dropdown box.
This dropdown box should, when a certain option is selected, make visible another dropdown box (in the same cell). Otherwise, this second dropdown should be invisible.
Elsewhere I am accomplishing the hide/show dynamics by means of a toggleVisible function, which simply adds custom classes which is marked by css to hide or show the element.
The relevant code:
The table I want to populate:
<table id='performer-payments' class='performer-profile payments-table'>
<tr>
<th> Period </th>
<th> Amount </th>
<th> Paid? </th>
</tr>
</table>
The code that populates the table:
for (period in data['Performers'][performer]['Payments']) {
var amount = utils.calcPerformerCut(data, performer, period);
var row = "<tr>";
row += "<td> " + period + " </td>";
row += "<td> " + amount + " $ </td>";
row += "<td>";
row += "<div class='performer-profile payment-status'>";
row += data['Performers'][performer]['Payments'][period];
row += "</div>";
row += "<select id='payment-status-" + performer + "-" + period + "' class='perfomer-profile hidden-onload displayNone payment-status-menu'>";
row += "<option value='paid'>Paid</option>";
row += "<option value='unpaid'>Unpaid</option>";
row += "<option value='transfer'>Transfer to...</option>";
row += "</select>";
row += "<select id='payment-transfer-period-" + performer + "-" + period + "' class='performer-profile hidden-onload displayNone payment-period-menu'>";
for (var i=0; i < data['Periods'].length; i++) {
row += "<option value='" + period + "'>" + period + '</option>';
}
row += "</select>";
row += "</td>";
row += "</tr>";
$('#performer-payments').append(row);
$('#performer-payments').on('change', {perf: performer, per: period}, function (even) {
if (even.target.value == 'transfer') {
utils.toggleVisible($('#payment-transfer-period-' + even.data.perf + '-' + even.data.per), true);
} else {
utils.toggleVisible($('#payment-transfer-period-' + even.data.perf + '-' + even.data.per), false);
}
});
}
For reference, the code that toggles visibility:
exports.toggleVisible = function (selector, visible) {
if (visible) {
selector.removeClass('displayNone').addClass('displayBlock');
} else {
selector.removeClass('displayBlock').addClass('displayNone');
}
}
There are (at least) two issues with this:
The #payment-transfer-period-... select box is never displayed, even when the 'transfer' option is chosen in the first select box. From debugging efforts it seems to me that it could be that the #payment-transfer-period-.. for some reason is not a valid object yet, or something like that.
(Obviously, really), the on-change event is triggered N times (N=number of periods) because I am just telling the program to trigger whenever something in the table changes. I would like it to trigger only for the relevant dropdown, but when I tried adding the #payment-status-... as a selector to the .on() function, it made it never trigger.
Note: I welcome feedback on this in general - I am an experienced programmer but have very little experience with HTML/JS/Jquery. Further, I have decided to not use templates for this project since I am trying to learn the basics, so if you get pancreatitis from seeing the way I am 'dynamically' adding the rows to the table, I apologize but it is partly intentional.
Other than that, please ask for clarifications if something is not clear here.
Edit: Here is the relevant part of the data structure:
data = {
'Performers': {
'Dira Klaggen': {
'Payments': {
'Q1': 'Paid',
'Q2': 'Paid',
'Q3': 'Unpaid'
},
},
'Holden Bolden': {
'Payments': {
'Q2': 'Transferred to Q3',
'Q3': 'Unpaid'
}
},
'Manny Joe': {
'Payments': {
'Q1': 'Paid',
'Q2': 'Unpaid',
'Q3': 'Unpaid',
}
}
},
'Periods': [
'Q1',
'Q2',
'Q3'
]
}
You do not attach the change handler to the right element. I should be the first select in the row... Instead of the whole table.
Try this change handler:
$('#performer-payments').find('#payment-status-' + performer + '-' + period).on('change', function(){
if ($(this).val() == 'transfer') {
$(this).next('select').show();
} else {
$(this).next('select').hide();
}
});
Second approach:
You could simplify that by using a class instead of a "complicated" unique id for the first select.
Say you use the class "payment-status":
The handler would be:
$('#performer-payments').on('change', '.payment-status', function(){
if ($(this).val() == 'transfer') {
$(this).next('select').show();
} else {
$(this).next('select').hide();
}
});
And this handler can be out of the row appending loop because it uses delegation.
Let's clean up your code by doing the following things:
Use classes instead of ugly IDs.
Use data-attributes or hidden input fields to hold extra information.
Use event delegation to bind dynamically-created elements. Inside the event handler, use tree traversal methods to limit the scope of the search based on the current element this.
Let's apply these things.
Build each row like this. {PLACEHOLDER} is where you put your variable stuff like you have in your code.
<tr>
<td>{PERIOD}</td>
<td>{AMOUNT} $ </td>
<td>
<div class='performer-profile payment-status'>
{SOMETHING-RELATING-TO-PERFORMER-PAYMENT-PERIOD}
</div>
<!-- remove ID -->
<!-- store performer and period in data-attributes -->
<select class='perfomer-profile hidden-onload displayNone payment-status-menu' data-performer='{PERFORMER}' data-period='{PERIOD}'>
<option value='paid'>Paid</option>
<option value='unpaid'>Unpaid</option>
<option value='transfer'>Transfer to...</option>
</select>
<!-- remove ID -->
<select class='performer-profile hidden-onload displayNone payment-period-menu'>
<option value='{PERIOD}'>{PERIOD}</option>
<option value='{PERIOD}'>{PERIOD}</option>
<option value='{PERIOD}'>{PERIOD}</option>
<!-- etc -->
</select>
</td>
</tr>
In your JavaScript, create a delegated event handler. Note the syntax.
$(function () {
// ...
for (period in data['Performers'][performer]['Payments']) {
// build and append row
}
// create delegated event handler once and outside FOR loop
$(document).on('change', '.payment-status-menu', function () {
// get the current status menu
var statusMenu = $(this);
// find its related period menu
var periodMenu = statusMenu.closest('tr').find('.payment-period-menu');
// toggle its visibility
periodMenu.toggle(this.value == 'Transfer');
// of course, this could be a one-liner
//$(this).closest('tr').find('.payment-period-menu').toggle(this.value == 'Transfer');
});
});
It doesn't seem like you need (2.) but if you do, within the event handler, use statusMenu.data('performer') or statusMenu.data('period') to get its performer and period values. You could also do this.dataset.performer or this.dataset.period.

Loop through a form which contains another form

I want to loop through a form with Javascript but my problem is that I have another form in the first form.
I'd like to loop through the first form only, not the inner one. I found this method on an other post :
var table = $("#table_cultures tbody");
table.find('tr').each(function (i) {
var $tds = $(this).find('td'),
productId = $tds.eq(0).text(),
product = $tds.eq(1).text(),
Quantity = $tds.eq(2).text();
// do something with productId, product, Quantity
alert('Row ' + (i + 1) + ':\nId: ' + productId
+ '\nProduct: ' + product
+ '\nQuantity: ' + Quantity);
});
This method works but loop through the both forms.
EDIT 1 :
The html looks like :
<form>
<table>
<tr>
<td>Something here</td>
</tr>
<tr>
<td>
<form>
<table>
//tr td ...
</table>
</form>
</td>
</tr>
</table>
</form>
nesting of <form> elements is not allowed
please see:
https://www.w3.org/TR/html5/forms.html#the-form-element
"...Flow content, but with no form element descendants..."

Get Select Value and Option from Specific Table Row and Column with Javascript or JQuery

I have a table that has rows appended to it. Each row has a select in column 2 {0, 1, [2]}. I am trying to get the text/value/option of the select using JavaScript or JQuery. This seems like it should be something easy but for the life of me I cannot figure out a way to get the select element in the selected row & column. Any help would be greatly appreciated.
Here is my table.
<div id="table_container">
<table id="computer_table" class="service_table">
<thead id="header_container">
<th class="table_header">COMPUTER NAME</th>
<th class="table_header">LIVE/HIDE</th>
<th class="table_header">MODE</th>
<th class="table_header">RUN</th>
</thead>
<tbody id="table_body">
</tbody>
</table>
</div>
Here is my JavaScript that adds rows to the table. Rows contain a select in column 2.
row = $('<tr class="row_white"><td class="tb_pc_name">' + value.pc_name + '</td><td class="tb_live_hide">LIVE</td><td class="tb_mode">' +
'<select id="select_mode" class="select_dropdown">' +
'<option value="0">0 - DEFAULT</option>' +
'<option value="1">1 - CLEAN UP</option>' +
'<option value="2">2 - SIGN IN</option>' +
'<option value="3">3 - SIGN OUT</option>' +
'<option value="4">4 - UPDATE IPSW</option>' +
'<option value="5">5 - OPEN DMG DIRECTORY</option>' +
'</select></td>' +
'<td class="tb_btn"><button type="button" id="btn_run">RUN</button></td></tr>');
$("#computer_table").append(row);
After all rows have been appended, the user can make a selection from the select. There is a button in column 3 that when clicked should show an alert with the select option and value of the select on the same row. The code below should show the selected option and/or value of the select in the row of the cell that is clicked. I can get the row and column but cannot get the value of the select.
$("#computer_table td").click(function() {
var table = document.getElementById('computer_table');
var column_num = parseInt( $(this).index() );
var row_num = parseInt( $(this).parent().index() );
alert('test');
/*Error here.*******************************************************************************************/
var combo = table.rows[row_num + 1].cells[2].getElementById('select_mode');
//$("#select_mode option:contains("?").attr('selected', 'selected');
alert(combo.value);
});
If you changed your buttons to use a class rather than an id they could be triggered with this:
$("#computer_table").on("click", "button.btn_run", function(e) {
alert($(this).parent().prev().children().find(":selected").text());
});
First of all there is something wrong with youre code that add the row. Every ID must be unique and it's not the case. Try using a counter (or something else) to avoid that like this:
var numberRowAdded = 0;
row = $('<tr class="row_white"><td class="tb_pc_name">' + value.pc_name + '</td><td class="tb_live_hide">LIVE</td><td class="tb_mode">' +
'<select id="select_mode'+ numberRowAdded +'" class="select_dropdown">' +
'<option value="0">0 - DEFAULT</option>' +
'<option value="1">1 - CLEAN UP</option>' +
'<option value="2">2 - SIGN IN</option>' +
'<option value="3">3 - SIGN OUT</option>' +
'<option value="4">4 - UPDATE IPSW</option>' +
'<option value="5">5 - OPEN DMG DIRECTORY</option>' +
'</select></td>' +
'<td class="tb_btn"><button type="button" id="btn_run'+ numberRowAdded +'">RUN</button></td></tr>');
$("#computer_table").append(row);
numberRowAdded++;
Then to select what you want :
$("#computer_table td").click(function() {
alert($(this).find(".select_dropdown").val());
});
Hope this help.
try passing in the ID onClick:
$("#computer_table td").click(function(this.id){ }
Just make sure all your cells have an ID.
Here is W3 example on enclosures and encapsulation. This is useful for giving all your elements a different ID. W3 encapsulation example
Adding elements with eventlisteners attached, and passing in a unique id!!
*Note: this is not an exact fix for your code. This should however aid you in understanding.
/*use this function to create unique id's*/
var add = (function () {
var counter = 0;
return function () {return counter += 1;}
})();
/*grab your table*/
var table =document.getElementById("computer_table");
/* create an element, set it's attributes*/
var newRow = document.createElement("th");
newRow.setAttribute("class", "table_header");
newRow.setAttribute("id", "table_header"+add());
/*add the event listener*/
newRow.addEventListener("click",function(this.id){ /* YOUR CODE HERE */ });
/*append to your table*/
table.appendChild(newRow);

Jquery group by td with same class

I have the current table data:
<table>
<tr class="Violão">
<td>Violão</td>
<td class="td2 8">8</td>
</tr>
<tr class="Violão">
<td>Violão</td>
<td class="td2 23">23</td>
</tr>
<tr class="Guitarra">
<td>Guitarra</td>
<td class="td2 16">16</td>
</tr>
</table>
What I want to do is groupby the TDs which are the same, and sum the values on the second td to get the total. With that in mind I´ve put the name of the product to be a class on the TR (don't know if it is needed)
and I've coded the current javascript:
$(".groupWrapper").each(function() {
var total = 0;
$(this).find(".td2").each(function() {
total += parseInt($(this).text());
});
$(this).append($("<td></td>").text('Total: ' + total));
});
by the way the current java scripr doesn't groupby.
Now i'm lost, I don't know what else I can do, or if there is a pluging that does what I want.
</tr class="Violão"> This doesn't make sense. You only close the tag: </tr>. And I'm assuming you know that since the rest of your code is proper (except for your classnames. Check this question out).
If you want to add the values of each <td> with a class of td2, see below.
Try this jQuery:
var sum = 0;
$(".td2").each(function(){
sum = sum + $(this).text();
});
This should add each number within the tds to the variable sum.
<table>
<tr class="Violão">
<td>Violão</td>
<td class="td2 8">8</td>
</tr>
<tr class="Violão">
<td>Violão</td>
<td class="td2 23">23</td>
</tr class="Violão">
<tr class="Guitarra">
<td>Guitarra</td>
<td class="td2 16">16</td>
</tr>
</table>
var dictionary = {};
$("td").each(function(){
if(!dictionary[$(this).attr("class"))
dictionary[$(this).attr("class")] = 0;
dictionary[$(this).attr("class")] += parseInt($(this).html());
});
// declare an array to hold unique class names
var dictionary = [];
// Cycle through the table rows
$("table tr").each(function() {
var thisName = $(this).attr("class");
// Add them to the array if they aren't in it.
if ($.inArray(thisName, dictionary) == -1) {
dictionary.push(thisName);
}
});
// Cycle through the array
for(var obj in dictionary) {
var className = dictionary[obj];
var total = 0;
// Cycle through all tr's with the current class, get the amount from each, add them to the total
$("table tr." + className).each(function() {
total += parseInt($(this).children(".td2").text());
});
// Append a td with the total.
$("table tr." + className).append("<td>Total: " + total + "</td>");
}
Fiddler (on the roof): http://jsfiddle.net/ABRsj/
assuming the tr only has one class given!
var sums = [];
$('.td2').each(function(){
var val = $(this).text();
var parentClass = $(this).parent().attr('class');
if(sums[parentClass] != undefined) sums[parentClass] +=parseFloat(val);
else sums[parentClass] = parseFloat(val);
});
for(var key in sums){
$('<tr><td>Total ('+key+')</td><td>'+sums[key]+'</td></tr>').appendTo($('table'));
}
I would give the table some ID and change to appendTo($('#<thID>'))
The solution:
http://jsfiddle.net/sLysV/2/
First stick and ID on the table and select that first with jQuery as matching an ID is always the most efficient.
Then all you need to do is match the class, parse the string to a number and add them up. I've created a simple example for you below
http://jsfiddle.net/Phunky/Vng7F/
But what you didn't make clear is how your expecting to get the value of the td class, if this is dynamic and can change you could make it much more versatile but hopefully this will give you a bit of understanding about where to go from here.

Categories

Resources