[英]Why does my JavaScript forEach muliplication of two elements then setAttribute value to a third element code only run once?
Background: I am creating a simple html order form for around 30 items using pure vanilla JavaScript ( no jQuery) and basic CSS.背景:我正在使用纯原版 JavaScript(无jQuery)和基本的 CSS 为大约 30 件商品创建一个简单的 html 订单。 It will not involve any online payments.它不会涉及任何在线支付。 New items may be added by my client and they will simply copy paste a block of code for an existing item in the html of the article and give it a new item name.我的客户可能会添加新项目,他们会简单地将现有项目的代码块复制粘贴到文章的 html 中,并给它一个新的项目名称。 They will not have access to the JavaScript.他们将无法访问 JavaScript。 To avoid potential unwanted duplicates I am using only CSS classes and no element IDs.为了避免潜在的不需要的重复,我只使用 CSS 类并且没有元素 ID。 The form consists of a item name (text), a price and two input fields - one for quantity and one for total, with total being based dynamically on price*quantity as the form is filled.该表格由一个项目名称(文本)、一个价格和两个输入字段组成 - 一个用于数量,一个用于总计,在填写表格时,总计动态基于价格*数量。
My query: The quantity and form fields are pre-filled with zeros using a forEach loop and that works fine for all elements as expected.我的查询:数量和表单字段使用 forEach 循环预填充零,并且按预期对所有元素都有效。 What I cannot get to work is a second loop which calculates the total price based on price x quantity for anything other than the first one it finds.我无法开始工作的是第二个循环,它根据价格 x 数量计算总价,而不是它找到的第一个循环。
What am I missing?我错过了什么? Is it something to do with the onblur="calculate"
command in the quantity input element?与数量输入元素中的onblur="calculate"
命令有关吗? I have to admit I found this part in someone else's code and haven't used it before.我不得不承认我在别人的代码中发现了这部分并且之前没有使用过它。 Perhaps I should be using something else.也许我应该使用别的东西。
I have looked at other questions in a similar vein on here (and elsewhere) but they're either using jQuery or other types of JS or tables and so on.我在这里(和其他地方)以类似的方式查看了其他问题,但他们要么使用 jQuery 或其他类型的 JS 或表格等。
The code is below.代码如下。 TIA: TIA:
if (document.querySelector('.order-form')) { let qty = document.querySelectorAll('.qty'); let total = document.querySelectorAll('.total'); [].forEach.call(qty, function(zero) { zero.setAttribute('value','0'); }); [].forEach.call(total, function(zero) { zero.setAttribute('value','0'); }) } calculate = function() { let qty = document.querySelectorAll('.qty'); [].forEach.call(qty, function() { let price = document.querySelector('.price').innerText; let newprice = parseFloat(price).toFixed(2); let qty = document.querySelector('.qty').value; let newtotal = parseFloat((newprice)*(qty)).toFixed(2); let total = document.querySelector('.total'); total.setAttribute('value',newtotal); }); }
.order-form { margin: 16px; width: 100%; }.row { width: 100%; }.prod { margin-top: 16px; }.price { width: 10%; display: inline-block; }.price:before { content: "Price: £"; }.input-style { width: 70%; display: inline-block; } label { padding: 0 16px; }
<div class="order-form"> <div class="prod">Subscription Receipt Book</div> <div class="row"> <div class="price" style="width: 10%; display: inline-block;">4.50</div> <div class="input-style"> <label for="qty">Qty:</label><input class="qty" type="text" name="qty" onblur="calculate()" /> <label for="total_amt">Total: £</label><input class="total" type="text" name="total_amt" /></div> </div> <div class="row" style="width: 100%;"> <div class="prod">General Receipt Book</div> <div class="price" style="width: 10%; display: inline-block;">4.00</div> <div class="input-style"> <label for="qty">Qty:</label><input class="qty" type="text" name="qty" onblur="calculate()" /> <label for="total_amt">Total: £</label><input class="total" type="text" name="total_amt" /> </div> </div> <div class="row" style="width: 100%;"> <div class="prod">Minutes book</div> <div class="price" style="width: 10%; display: inline-block;">5.50</div> <div class="input-style"> <label for="qty">Qty:</label><input class="qty" type="text" name="qty" onblur="calculate()" /> <label for="total_amt">Total: £</label><input class="total" type="text" name="total_amt" /> </div> </div> </div>
The issue is because you're selecting all the .price
, .qty
and .total
elements in the DOM in the calculate()
function, not only the ones in the same row as the field which was updated.问题是因为您在calculate()
function 中选择了 DOM 中的所有.price
、 .qty
和.total
元素,而不仅仅是与已更新字段位于同一行的元素。
To fix this you can simply use closest()
to get the .row
element relative to the .qty
which the user updated, and select the necessary fields from there.要解决此问题,您可以简单地使用closest()
来获取相对于用户更新的.qty
的.row
元素,并从那里获取必要的字段 select 。
Also note that there's several other improvements which should be made to your code.另请注意,您的代码还应进行其他几项改进。
onblur
, onclick
etc. They are outdated and not good practice. onblur
, onclick
等。它们已经过时并且不是好的做法。 Bind your events unobtrusively in the JS using addEventListener()
instead.改为使用addEventListener()
在 JS 中不显眼地绑定您的事件。forEach()
directly on the collections returned by querySelectorAll()
.您可以直接在querySelectorAll()
返回的 collections 上调用forEach()
) 。 This is now well supported so you don't need to mess around converting them to arrays first.这现在得到了很好的支持,因此您无需先将它们转换为 arrays。value
of the inputs at the time you generate them and append them to the DOM.在生成输入时设置输入value
,并将 append 设置为 DOM。 If you do this after the elements have been created it's likely that they will appear empty for a split second which is unsightly, and should be avoided.如果您在创建元素之后执行此操作,则它们可能会在一瞬间显得空无一物,这是难看的,应该避免。.total
fields default value should be set to 2dp, ie. .total
字段默认值应设置为 2dp,即。 0.00
, not just 0
. 0.00
,而不仅仅是0
。style
attribute.不要将它放在您的 HTML 中的style
属性中。value
property.使用value
属性更新输入的值。 You don't need to use setAttribute()
for this.您不需要为此使用setAttribute()
。for
attributes on your label
elements won't do anything as their values don't match the id
of any of the inputs. label
元素上的for
属性不会做任何事情,因为它们的值与任何输入的id
都不匹配。 To workaround this, remove the for
attributes and wrap the label
elements around the input
.要解决此问题,请删除for
属性并将label
元素包裹在input
周围。.total
fields readonly
, otherwise users can edit them and set whatever price they like.将.total
字段设为readonly
,否则用户可以编辑它们并设置他们喜欢的任何价格。With all that said, try this:说了这么多,试试这个:
document.querySelectorAll('.qty').forEach(el => { el.addEventListener('input', e => { const row = e.target.closest('.row'); const qty = e.target.value; const price = row.querySelector('.price').textContent; row.querySelector('.total').value = parseFloat(price * qty).toFixed(2); }); });
.order-form { margin: 16px; width: 100%; }.row { width: 100%; }.prod { margin-top: 16px; }.price { width: 10%; display: inline-block; }.price:before { content: "Price: £"; }.input-style { width: 70%; display: inline-block; } label { padding: 0 16px; }
<div class="order-form"> <div class="prod">Subscription Receipt Book</div> <div class="row"> <div class="price">4.50</div> <div class="input-style"> <label> Qty: <input class="qty" type="text" name="qty" value="0" /> </label> <label> Total: £ <input class="total" type="text" name="total_amt" value="0.00" readonly /> </label> </div> </div> <div class="row"> <div class="prod">General Receipt Book</div> <div class="price">4.00</div> <div class="input-style"> <label> Qty: <input class="qty" type="text" name="qty" value="0" /> </label> <label> Total: £ <input class="total" type="text" name="total_amt" value="0.00" readonly /> </label> </div> </div> <div class="row"> <div class="prod">Minutes book</div> <div class="price">5.50</div> <div class="input-style"> <label> Qty: <input class="qty" type="text" name="qty" value="0" /> </label> <label> Total: £ <input class="total" type="text" name="total_amt" value="0.00" readonly /> </label> </div> </div> </div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.