This example has multiple products (instruments) and each one has a purchase button, when i click on the purchase button of a product its supposed to send the quantity value extracted from the html spinbox to the function myfunction.
Problem : --I always end up getting the value of the first product in the myfunction with the the variable used 'a' (because all the products have the same id)
anyway to access the value of the spinbox of each HTML individually?
{% for post in posts %}
<article >
<div >
<div >
<a href="#">{{ post.type " " post.instrument }}</a>
<small >{{ post.date_posted }}</small>
</div>
<h2><a href="#">{{ post.name }} : {{post.brand}}</a></h2>
<div >
{% if post.type not in "Guitar" or "bass" %}
<p >{{"effects : " post.frets "\nColor : " post.color "\nportability : " post.bridge}}</p>
{% else %}
<p >{{"Bridge : " post.bridge "\nColor : " post.color "\nFrets : " post.frets}}</p>
{% endif %}
</div>
<a href="#">{{"Quantity"}} : {{post.quantity}}</a>
<form>
<input name="quant" id="a" type="number" min="1" max={{post.quantity}} required>
<br>
<a>{{"Price:"}}</a>
<a href="#">{{post.price "$"}}</a>
<button type="submit" onclick="myFunction({{post.quantity}},'{{post.brand}}', '{{post.name}}', '{{post.price}}')">Purchase</button>
</form>
</div>
</article>
{% endfor %}
<script>
function ajaxcall(quantity, brand, name){
$.ajax({
url : "{{ url_for('quantity_update') }}",
type: 'POST',
data: {new_quantity: JSON.stringify(quantity), brand: JSON.stringify(brand), name: JSON.stringify(name)}
});
}
function myFunction(quant, brand, name, price) {
var a = document.getElementById('a').value;
prix = parseInt(price) * a
let text = "Press a button!\n--OK to Purchase (Total price : " prix ")\n--Cancel to cancel.";
if (a) {
if(confirm(text)){
alert("Congrats, the product has been bought");
quantity = quant - a;
ajaxcall(quantity, brand, name);
}
} else {
alert("Please insert a value before buying")
}
document.getElementById("demo").innerHTML = text;
}
</script>
CodePudding user response:
Since you are already using a form
tag, I would suggest outputting all of your values inside of hidden input
elements. This way you can store each value nicely in its own tag and retrieve the values later by the name of each input.
<form >
<input type="hidden" name="brand" value="{{post.brand}}" />
<input type="hidden" name="name" value="{{post.name}}" />
<input type="hidden" name="price" value="{{post.price}}" />
<input type="hidden" name="quantity" value="{{post.quantity}}" />
<input type="number" name="amount" min="1" max="{{post.quantity}}" required>
<button type="submit" >Purchase</button>
</form>
Forms have the submit
event, which is triggered whenever you click the submit button inside of a form
tag. By listening to this event and adding our own handling logic we can extract all the value from the inputs and assert our logic.
With the help of the FormData API we can easily extract all the values that are present in the form. These values can be retrieved by the name
attribute value of the corresponding input.
const forms = document.querySelectorAll('.article-form');
for (const form of forms) {
form.addEventListener('submit', event => {
event.preventDefault();
const formData = new FormData(form);
const amount = formData.get('amount');
if (amount === null || amount === '') {
alert("Please insert a value before buying");
return;
}
const brand = formData.get('brand');
const name = formData.get('name');
const quantity = formData.get('quantity');
const price = formData.get('price');
const total = parseInt(price) * amount;
const text = `Press a button!\n--OK to Purchase (Total price : ${total})\n--Cancel to cancel.`;
alert("Congrats, the product has been bought");
const newQuantity = quantity - amount;
ajaxCall(newQuantity, brand, name);
});
}
CodePudding user response:
The reason the first quantity is being accessed is because having multiple elements with the same id
is invalid HTML - and typically browsers will return the first element in the document matching an id
value supplied to document.getElementById
.
One solution would be remove the id
value from the quantity input and instead, locate the input box as child of its parent form. The parent form of a button (and other form elements) is supplied as the form
property of nested form elements.
This example passes the form
element to function myFunction
from the click handler instead of the quantity
argument, and adds a type="button"
attribute to purchase buttons to stop them generating a submit event by default.
"use strict";
function myFunction(form, name, brand, price) {
let quantity = form.querySelector(".quant");
console.log("quantity for purchase is " quantity.value);
}
<form name="whatever">
<label>quantity: <input value="1"></label>
<button type=button onclick='myFunction( this.form, "name", "brand", "price")'>Purchase</button>
</form>
<form name="whatever">
<label>quantity: <input value="42"></label>
<button type=button onclick='myFunction( this.form, "name", "brand", "price")'>Purchase</button>
</form>
Note that supplying event handlers in HTML is discouraged, and Emiels's excellent answer shows an approach to reworking the code to supply the click event listeners in JavaScript.