I have a PHP generated list of product links that, when clicked, adds a product to a shopping cart. At present, there's a quantity of '1' hard-coded in the links, e.g.
Add To Cart
I'd like to add a quantity field to each item in the list, so a customer can add the quantity they want to the cart.
This list doesn't use a form, so how could I introduce a user input qty field and use it in each link? My searches have turned up nothing, so I take it that it can't be done the way I have it set up now. No matter how I change this list, I need to pass an array to the /shop/checkout PHP script.
I'm probably looking at this the wrong way, so any pointers would be appreciated.
Thanks!
EDIT
It must have something to do with the fact that my product list is in a table. When I change your example to use a table instead of divs, it breaks. Here's a sample:
<table class="products_list">
<tr class="product_list--item">
<td> 12486XC4 </td>
<td> Amount: <span class="item_display--1[qty]">1</span> </td>
<td> <input class="item_qty" id="itm_qty" type="number" min="1" max="100" value="1" size="5" /> </td>
<td> Add to cart </td>
</tr>
<tr class="product_list--item">
<td> 13486XC5 </td>
<td> Amount: <span class="item_display--1[qty]">1</span> </td>
<td> <input class="item_qty" id="itm_qty" type="number" min="1" max="100" value="1" size="5" /> </td>
<td> Add to cart </td>
</tr>
<tr class="product_list--item">
<td> 14486XC6 </td>
<td> Amount: <span class="item_display--1[qty]">1</span> </td>
<td> <input class="item_qty" id="itm_qty" type="number" min="1" max="100" value="1" size="5" /> </td>
<td> Add to cart </td>
</tr>
</table>
Also, 1[sku] and 1[qty] are invariable in the links. They are used in the destination PHP script for each product on this page. The only thing that changes from product to product is the value of the sku.
You can use javascript for this instead of one big form and complex php code. Simply put each link in the wrapper with <input type="number"/> that will allow to add quantity to your product. Then you can change URI for checkout. Working example with comments of how to do this i have add below.
Hope that this will help!
Update
Because you are not showing your code its hard to understand what is not working on your side. So show us what you did and lets find out the issues instead of pin pointing the problem ;)
I don't see any issues with rendering your template using php and putting values of proper variables as a values of html attributes.
You can add name attribute which can be equal to your qty array name for proper sku. Example
<input name="1[qty]" class="item_qty" type=number min="1" max="100" value="1" />.
In php it will look like this (and again this is just an example of how you can achieve your result)
<input name="<?="1[qty]={$qty}";?>" class="item_qty" type=number min="<?=$qty;?>" max="100" value="1" />
<?=?> is an echo tag. You can replace with <?php ?>
Later you can simply grab the value of the attribute using JS and update each corresponding checkout link. Moreover your case didn't work because in RegExp symbols like [ and ] should be escaped -> \[ and \].
function addSlashes(string, vowels) {
let length = vowels.length;
let finalString = "";
let startOffset = 0;
let endOffset = 0;
for (let i = 0; i < length; i++) {
if ((endOffset = string.indexOf(vowels[i])) !== -1) {
finalString += string.substring(startOffset, endOffset) + "\\";
if (endOffset === string.length - 1) {
finalString += string[string.length - 1];
}
startOffset = endOffset;
}
}
return finalString;
}
function updateQueryStringParameter(uri, key, value) {
let escapedKey = addSlashes(key, ["[", "]"]);
let re = new RegExp("([?&])" + escapedKey + "=.*?(&|$)", "i");
let separator = uri.indexOf('?') !== -1 ? "&" : "?";
if (uri.match(re)) {
return uri.replace(re, '$1' + key + "=" + value + '$2');
} else {
return uri + separator + key + "=" + value;
}
}
function displayQuantityForProduct(element, text = "") {
element.textContent = text;
}
const inputs = document.querySelectorAll(".product_list--item .item_qty");
const length = inputs.length;
for (let i = 0; i < length; i++) {
inputs[i].addEventListener("input", function() {
// also add check whenever input value is not an empty string and its an integer which is bigger or equal to 1
if (this.value && parseInt(this.value) >= 1) {
// selfName
let selfName = "1[qty]";
let children = this.closest(".product_list--item").children;
// children will consist of td elements from each tr with class product_list--item in your table
// [0] first element of the array is sku (1) <td> 12486XC4 </td>
// [1] second element of the array is amount with span (2)
// [2] is input with qty (3)
// [3] is Add to cart link (4) and so on...
let displayQty = children[1].firstElementChild;
let addToCartLink = children[3].firstElementChild;
let newUri = updateQueryStringParameter(
addToCartLink.getAttribute("href"),
selfName,
this.value
);
displayQuantityForProduct(displayQty, this.value);
addToCartLink.setAttribute("href", newUri);
}
});
}
<table class="products_list">
<tr class="product_list--item">
<td> 12486XC4 </td>
<td> Amount: <span class="item_display--1[qty]">1</span> </td>
<td> <input class="item_qty" id="itm_qty" type="number" min="1" max="100" value="1" size="5" /> </td>
<td> Add to cart </td>
</tr>
<tr class="product_list--item">
<td> 13486XC5 </td>
<td> Amount: <span class="item_display--1[qty]">1</span> </td>
<td> <input class="item_qty" id="itm_qty" type="number" min="1" max="100" value="1" size="5" /> </td>
<td> Add to cart </td>
</tr>
<tr class="product_list--item">
<td> 14486XC6 </td>
<td> Amount: <span class="item_display--1[qty]">1</span> </td>
<td> <input class="item_qty" id="itm_qty" type="number" min="1" max="100" value="1" size="5" /> </td>
<td> Add to cart </td>
</tr>
</table>
Related
I have following Code which doesn't seems to work correctly when i added the script to add the values in the total that are shown in the total text box
<tbody id='table'>
<tr class="crow">
<td style='width:150px;'>1</td>
<td style='width:350px;'>
<select class="form-control FID" required name="FID[]">
<?php
$options="<option value='' Amount='0' >Select</option>";
foreach($data["challan"] as $row){
$options.="<option value='{$row["FID"]}' Amount='{$row["Amount"]}'>{$row["Feetype"]}</option>";
}
echo $options;
?>
</select>
</td>
<td>
<input type="text" name="Amount[]" class="form-control Amount" required>
</td>
<td>
<input type="button" value="Remove" class="btn btn-link btn-xs rmv" required>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td ><input type='button' class='btn btn-link add' value='+Add Row'></td>
<td colspan="2" class="text-right">Total</td>
<td><input type="text" name="grand_total" id="grand_total" class="form-control" required=""></td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$("body").on("click",".add",function(){
var i=1;
$(".crow").each(function(){
i++;
});
var options="<?php echo $options; ?>";
var row='<tr class="crow"> <td>'+i+'</td> <td> <select class="form-control FID chosen" required name="FID[]">'+options+'</select></td><td> <input type="text" name="Amount[]" class="form-control Amount" required> </td></td><td> <input type="button" value="Remove" class="btn btn-link btn-xs rmv" required> </td></tr>';
$("#table").append(row);
});
$("body").on("click",".rmv",function(){
if(confirm('Are You Sure?')){
$(this).parents('tr').remove();
}
});
$("body").on("change",".FID",function(){
var p=$(this).find(":selected").attr("Amount");
$(this).closest("tr").find(".Amount").val(p);
});
$("body").on("keyup",".Amount",function(){
var Amount=Number($(this).val());
$(this).closest("tr").find(".total").val(Amount*1);
grand_total();
});
function grand_total(){
var tot=0;
$(".total").each(function(){
tot+=Number($(this).val());
});
$("#grand_total").val(tot);
}
});
</script>
I want to get little help that How can show the total amount in the total box, it will add all the values that are shown in the total column to show total in total text box at the end. i try to use the code but some how script doesn't seems to work correctly.
Thanks
I do not use jQuery ( always find it doesn't work as expected ) but with some simple vanilla Javascript this is fairly straightforward, no doubt some of what I wrote here you will be able to port into your jQuery code if you need to but the following example seems to work as you need it to. There are comments in the code to describe what is occurring but essentially a delegated event listener is bound to the document itself ( alternatively it could be the table ) and all button clicks and mouse events are delegated to the correct component thanks to event bubbling.
To help identify which buttons are clicked and the task they are to perform I simply added a dataset attribute to each, other than that the HTML is as per the original though obviously the select menu has been hardcoded with dummy data though the hardcoded row number was replaced with a css counter. Hope you find something of value in the following...
const d=document;
const total=d.querySelector('input[name="grand_total"]');
d.addEventListener('click',e=>{
/* Add new row */
if( e.target.classList.contains('btn-link') && e.target.dataset.action=='add' ){
let tbody=d.querySelector('tbody#table');
let tr=tbody.querySelector('tr:first-of-type');
/* clone the first table row and clear any values previously entered */
let clone=tr.cloneNode( true );
clone.querySelector('input[name="Amount[]"]').value='';
/* add the new row to the table. */
tbody.appendChild( clone );
}
/* Remove existing row - NOT first row though! */
if( e.target.classList.contains('btn-link') && e.target.dataset.action=='remove' ){
if( d.querySelectorAll('tbody#table tr').length > 1 ){
// We need to identify the value entered into 'Amount[]' so that we can remove
// it from the total.
let value=e.target.closest('tr').querySelector('input[name="Amount[]"]').value;
// find and remove the button's parent row
// using closest to move UP the DOM until it finds the TR node.
d.querySelector('tbody#table').removeChild( e.target.closest('tr') );
// subtract this value from the total
total.value-=parseFloat( value )
}
}
});
// tally up all numbers entered by iterating through all input elements
// with the name Amount[]
d.addEventListener('keyup',e=>{
let col=d.querySelectorAll('input[name="Amount[]"]');
// convert nodelist to an array and use regular array methods (map & reduce)
// to return the sum
total.value=[...col]
.map(n=>n.value > 0 ? n.value : 0)
.reduce((a,b)=>parseFloat(a) + parseFloat(b));
});
html{counter-reset:rows}
tr{counter-increment:rows}
tbody td{border:1px dotted grey;padding:0.25rem}
tbody tr td:first-of-type::before{content:counter(rows);display:table-cell}
tfoot td{background:grey;padding:0.5rem;color:white}
<table>
<tbody id='table'>
<tr class='crow'>
<td style='width:150px;'></td>
<td style='width:350px;'>
<select class='form-control FID' required name='FID[]'>
<option value=1>banana
<option value=2>giraffe
<option value=3>hercules
<option value=4>didgeridoo
<option value=5>womble
</select>
</td>
<td>
<input type='text' name='Amount[]' class='form-control Amount' required />
</td>
<td>
<input data-action='remove' type='button' value='Remove' class='btn btn-link btn-xs rmv' required />
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td><input data-action='add' type='button' class='btn btn-link add' value='+Add Row' /></td>
<td colspan='2' class='text-right'>Total</td>
<td><input type='text' name='grand_total' class='form-control' required /></td>
</tr>
</tfoot>
</table>
Hard one to explain in the title, but a bit of code says it all:
<tr class="">
<td>
<input value="9" name="set[122][order]"></input>
<input class="set-id" type="hidden" value="1" name="set[122][ex_id]"></input>
</td>
<td>
<input value="0.00" name="set[122][weight]"></input>
</td>
<td> … </td>
<td>
<img class="deleteRowButton" border="0" title="Toggle Delete Set" alt="Delete Set" src="mysite/images/icons/png/delete-3x.png"></img>
</td>
</tr>
I have a bit of jQuery code that is activated when the img (deleteRowButton) is clicked:
$('.deleteRowButton').click (function() {
$(this).parents("tr").toggleClass( "deleteSet" );
var id = $('.set-id', $(this).closest('td')).val(); // this bit not working
$('.editWoForm').append('<input type="hidden" name="deleteSet[]" value="' + id + '" />');
});
The deleteRowButton code basically just inserts a hidden input tag at the bottom of my form, so i have the ability to process these to remove entries from db.
BUT, what I need to do is grab the value from set[], so in this example 122. It can come from any of the inputs, as the whole tr is related to one entry. 122 is the db id, so that's what I need to grab.
So ideally, when the user clicks on the deleteRowButton, it generates and inserts:
<input type="hidden" name="deleteSet[]" value="122" />
Thanks in advance!
Solution
Thanks to #ArunPJohny for the assistance.
$('.deleteRowButton').click (function() {
var $tr = $(this).parents("tr").toggleClass( "deleteSet" );
var id = $tr.find('.set-id').attr('name').match(/\d+/)[0];
if($tr.hasClass( "deleteSet" )){
$('.editWoForm').append('<input type="hidden" name="deleteSet[]" value="' + id + '" />');
}
else{
$('input[name="deleteSet[]"][value="' + id + '"]').remove();
}
});
This will get the id, append a hidden input field with said id as the value, then if the button is pressed again (to toggle the delete state) the hidden input field is removed.
One way here is to fine the set-id element which is within the current tr element. what you are trying to do is to find an set-id which is within the td which contains the clicked deleteRowButton.
$('.deleteRowButton').click(function() {
//use closest instead of parents
var $tr = $(this).closest("tr").toggleClass("deleteSet");
//find the set-id within the current tr
var id = $tr.find('.set-id').attr('name').match(/\d+/)[0];
//$('.editWoForm').append('<input type="hidden" name="deleteSet[]" value="' + id + '" />');
$('#log').text(id)
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table>
<tr class="">
<td>
<input value="9" name="set[122][order]"/>
<input class="set-id" type="hidden" value="1" name="set[122][ex_id]"/>
</td>
<td>
<input value="0.00" name="set[122][weight]"/>
</td>
<td> … </td>
<td>
<img class="deleteRowButton" border="0" title="Toggle Delete Set" alt="Delete Set" src="mysite/images/icons/png/delete-3x.png"/>
</td>
</tr>
<tr class="">
<td>
<input value="9" name="set[123][order]"/>
<input class="set-id" type="hidden" value="2" name="set[123][ex_id]"/>
</td>
<td>
<input value="0.00" name="set[123][weight]"/>
</td>
<td> … </td>
<td>
<img class="deleteRowButton" border="0" title="Toggle Delete Set" alt="Delete Set" src="mysite/images/icons/png/delete-3x.png"/>
</td>
</tr>
</table>
<div id="log"></div>
I have created a web page where my customers will be able to enter details of all items there return back to my store. I have created in such a way that, 1 customer can enter his personal details once but can add any number of items he is returning. I have created a "add more" button to do this job. But when I am testing my site, database is only taking the last item entered and is not storing previous items.
<script> $(function () {
$('input.more').on('click', function () {
var $table = $('#input_fields');
var $tr = $table.find('tr').eq(0).clone();
$tr.appendTo($table).find('input').val('');
});
});
</script>
<tr>
<td width="33%"><label class="description" for="element_20">Manufacturer, Model, Serial # </label>
</td>
<td width="33%"><label class="description" for="element_10">Tag Number (If Any) </label>
</td>
<td width="33%"><label class="description" for="element_4">Item Description </label>
</td>
</tr>
</table>
<table id="input_fields" width="100%" border="0" cellpadding="4">
<tr>
<td width="33%"><input id="element_20" name="model" class="element text large" type="text" maxlength="255" value="<?php if($action != "add") echo $row["model"]; ?>"/></td>
<td width="33%"><input id="element_10" name="tag" class="element text large" type="text" maxlength="255" value="<?php if($action != "add") echo $row["tag"]; ?>"/></td>
<td width="33%"><input name="itemdesc" type="text" class="element text large" id="element_4" value="<?php if($action != "add") echo $row["itemdesc"]; ?>" /></td>
</tr>
</table>
<input class="more" type="button" value="Add more" name="addmore"/>
<ul>
<li class="buttons">
<input id="saveForm" class="button_text" type="submit" name="Submit" value="Submit" />
In this, when Customer enters a item details and then clicks add more and enter other item details. Only the last enter item details are getting stored. But I want all items to be stored and displayed on DB.
You end up posting only a single model/tag/text to the server because you have the same name property for each copy of the input elements. When PHP tries to map the posted data to $_POST it will only map to a single model/tag/itemdesc key in $_POST because the input names are the same.
The easiest way to resolve this is to use array access notation in your input names like model[], tag[], itemdesc[]. This will allow PHP to assemble an array of values for each model/tag/itemdesc key in $_POST.
Try this. Do a var_dump($_POST) at the beginning of your script before changing your HTML code. Run a multi-item test case and look at the dumped value.
Then change to use array access notation in your HTML and see the difference the var_dump() gives.
I'm currently running an html and jQuery code that works but looks very ugly for me. I would really appreciate suggestion to do this more smarter.
Goal: update cells of a php generated table using an input field. Each cells contains a basic value which should be multiplied by the input.
Currently, I read the value of the input, take the basic value of each cell from an hidden input and rewrite the whole html of each cell ( hidden input + updated data).
Html code:
<table id='tbl'>
<thead>
<tr>
<th colspan="2">Quantity:
<input type="text" id="quantity" name="quantity" value="1">
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input name="1_1" type="hidden" value="11"><span>11</span>
</td>
<td>
<input name="1_2" type="hidden" value="12"><span>12</span>
</td>
</tr>
<tr>
<td>
<input name="2_1" type="hidden" value="21">21
</td>
<td>
<input name="2_2" type="hidden" value="22">22
</td>
</tr>
<tr>
<td>
<input name="3_1" type="hidden" value="31">31
</td>
<td>
<input name="2_2" type="hidden" value="32">32
</td>
</tr>
</tbody>
</table>
Script:
$('#quantity').keyup(function () {
var quantity = parseFloat($(this).val());
if (quantity == "" || isNaN(quantity))
quantity = 1;
$('#tbl tbody tr td').map(function () {
var $row = $(this);
var $refvalue = $row.find(':input[type=hidden]').val();
var $refname = $row.find(':input[type=hidden]').attr('name');
$row.html('<input name="' + $refname + '" type="hidden" value="' + $refvalue + '">' + $refvalue * quantity);
});
});
Fiddle : http://jsfiddle.net/5KKrD/
Is there a better way to do ? I'm able to change both table, js and so on.
Regards
this is my approach - use data attribute (instead of a hidden input) to pass the multiplier, e.g.:
<td class="cell" data-value="11">11</td>
with this - you can grab the value very easily using jquery, e.g.:
$('.cell').data('value')
DEMO
I have refined your code a bit,its working smoothly
JS CODE:
$('#quantity').keyup(function () {
if ($(this).val()) {
var quantity = parseInt($(this).val());
if (quantity == "" || isNaN(quantity)) quantity = 1;
$('#tbl tbody tr td input').each(function () {
var row = $(this);
var mulVal = row.val() * quantity;
$(this).attr('value', mulVal);
$(this).parent().find('span').text(mulVal);
//var $refvalue = $row.find(':input[type=hidden]').val();
//var $refname = $row.find(':input[type=hidden]').attr( 'name' );
//$row.html( '<input name="'+ $refname +'" type="hidden" value="'+ $refvalue + '">' + $refvalue * quantity );
});
}
});
HTML CODE:
<table id='tbl'>
<thead>
<tr>
<th colspan="2">Quantity:
<input type="text" id="quantity" name="quantity" value="1">
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input name="1_1" type="hidden" value="11" /><span>11</span>
</td>
<td>
<input name="1_2" type="hidden" value="12" /><span>12</span>
</td>
</tr>
<tr>
<td>
<input name="2_1" type="hidden" value="21" /><span>21</span>
</td>
<td>
<input name="2_2" type="hidden" value="22" /><span>22</span>
</td>
</tr>
<tr>
<td>
<input name="3_1" type="hidden" value="31" /><span>31</span>
</td>
<td>
<input name="2_2" type="hidden" value="32" /><span>32</span>
</td>
</tr>
</tbody>
</table>
LIVE DEMO
Happy Coding :)
It might be a bit over-kill for your needs, but this is what backbone.js aims to do - remove data from the HTML DOM and instead treats it Models and Views.
http://backbonejs.org/#examples
Apart from that, what's wrong with your current approach - what specifically do you want to improve?
The code cleaned up a bit:
$('#quantity').keyup(function() {
var quantity = parseFloat($(this).val());
quantity = ( quantity == "" || isNaN( quantity ) ? 1 : quantity;
$('#tbl tbody tr td').map(function() {
var $hiddenElement = $(this).find(input[type='hidden']);
$(this).html( '<input name="'+ $(hiddenElement).attr('name') +'" type="hidden" value="'+ $(hiddenElement).val() + '">' + (parseFloat($(hiddenElement).val()) * quantity) );
});
});
I think yours is just fine, the only thing I would personally do to improve it is place html in a var and use it as a template to keep syntax cleaner, I would replace this
$row.html( '<input name="'+ $refname +'" type="hidden" value="'+ $refvalue + '">' + $refvalue * quantity );
with this
var template ='<input name="{name}" type="hidden" value="{refvalue}">{res}</a>';
then
$row.html(template.replace('{name}', $refname) ); // and so on
I wanted to put a checkbox autosum on my website so that anyone who check a box and submit, the values (Points) of those check box are automatically added to my total sum (on home page actually)
I have found this code so far for java script.
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td> <input name="sum_m_1" value="25" type="checkbox" id="sum_m_1" onclick="UpdateCost()"> </td>
<td> ResponseOption_1 </td>
</tr>
<tr>
<td> <input name="sum_m_2" value="15" type="checkbox" id="sum_m_2" onclick="UpdateCost()"> </td>
<td> ResponseOption_2 </td>
</tr>
</table>
<input type="text" id="totalcost" value="">
With JAVASCRIPT:
<script type="text/javascript">
function UpdateCost() {
var sum = 0;
var gn, elem;
for (i=1; i<3; i++) {
gn = 'sum_m_'+i;
elem = document.getElementById(gn);
if (elem.checked == true) { sum += Number(elem.value); }
}
document.getElementById('totalcost' ).value = sum.toFixed(2);
}
window.onload=UpdateCost
</script>
This will add up the values but i wanted to add by checking check boxes --> Submit --> collect the data --> add to my main total.
Any helps would be much appreciated.
Simple changes:
Add a button "calculate cost".
Removed the onclick events from the checkboxes and added the onclick event to the button instead.
Note that "window.onload=UpdateCost" is still there because what you want ideally is for the total cost to be displayed properly as 0.00 when the page loads.
HTML
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td> <input name="sum_m_1" value="25" type="checkbox" id="sum_m_1"> </td>
<td> ResponseOption_1 </td>
</tr>
<tr>
<td> <input name="sum_m_2" value="15" type="checkbox" id="sum_m_2"> </td>
<td> ResponseOption_2 </td>
</tr>
</table>
<input type="text" id="totalcost" value="">
<input type="button" value="update cost" onclick="UpdateCost();">
JavaScript
<script type="text/javascript">
function UpdateCost() {
var sum = 0;
var gn, elem;
for (i=1; i<3; i++) {
gn = 'sum_m_'+i;
elem = document.getElementById(gn);
if (elem. checked == true) { sum += Number(elem. value); }
}
document.getElementById('totalcost' ).value = sum.toFixed(2);
}
window.onload=UpdateCost
</script>
Hope that's the kind of thing you wanted, let me me know what you think.