动态插入新行后增加和更新总数的值

问题描述

编辑:我已经用答案更新了代码

我有一个运行良好的增量功能。但是:

1。我想根据跨度之一中可用的总数设置一些限制。例如10。因此增量不能超过10。#DONE

  1. 一个问题是,我计划有多行,在保存之前,我想确保如果我们计算每行中的增量,它也不应超过10。如果它动态减少总数(跨度)会很好。

我使用ADD按钮动态添加行,如何添加实际上可与当前功能一起使用的新闻行?我的行只是克隆第一个,而增量功能已禁用。

document.addEventListener('DOMContentLoaded',async function() {
  document.querySelector('#addlocationdest').addEventListener('click',add);
});
function add() {
    var x = 1;
    var container = document.getElementById('destination');
    var detail = document.getElementById('row');
    var clone = detail.cloneNode(true);
    clone.id = "destination" + x;
    x++;
    container.appendChild(clone);

}

window.addEventListener("load",() => {
  let elTotalQuantity = document.querySelector("#totalqty");
  let totalQuantity = parseInt(elTotalQuantity.innerHTML);
  
  function getSumOfRows() {
    let sum = 0;
    for (let input of document.querySelectorAll("form .row > input.quantity"))
      sum += parseInt(input.value);
    return sum;
  }
  
  for (let row of document.querySelectorAll("form .row")) {
    let input = row.querySelector("input");
    row.querySelector(".increment").addEventListener("click",() => {
      if (getSumOfRows() >= totalQuantity) return;
      input.value++;
      elTotalQuantity.innerHTML = totalQuantity - getSumOfRows();
    });
    row.querySelector(".decrement").addEventListener("click",() => {
      if (input.value <= 0) return;
      input.value--;
      elTotalQuantity.innerHTML = totalQuantity - getSumOfRows();
    });
  }
});
<div id="location" class="hide">
                    <div class="title">Transfer details</div><br>
                    <div class="line padded-s">Total Quantity: <span>10</span></div>
                    <br>
                        <form>
                            <label>New Total Quantity at this location: <span id="totalqty">10</span></label>
                            <br>
                            <div id="destination">
                                <div id="row" class="row">
                                    <button type="button" class="decrement">-</button>
                                    <input type="text" class="quantity" value="0" readonly/>
                                    <button type="button" class="increment">+</button>
                                    <a>Location: </a>
                                    <input type="text" class="location" value="0" readonly/>
                                </div>
                            </div>
                        </form>

                        <label>Total being transfer: <p id="total-sum"></p></label>
                        <br>
                        <button type="button" id="addlocationdest">ADD</button>
            <button type="button" id="removelocationdest">REMOVE</button>
                </div>

解决方法

QuerySelector仅选择第一个出现的行,因此您并未真正向第二个“行”添加侦听器。您应该使用querySelectorAll,但要使用类来代替唯一的ID。

<input class="increment" type="button" value="+" />
  1. 现在您可以使用document.querySelectorAll(".increment")来获取数组中的所有元素。

  2. 您可以使用parentElement在DOM中遍历。通过知道单击了哪个按钮,可以遍历到表单元素,然后选择第一个子项-这是输入项。一种更动态的方法是使用querySelector选择输入,以防将来HTML发生更改。无论如何,您可以根据按钮在DOM中的位置来知道要操纵哪个输入。

  3. 我添加了两个全局变量totalSummaxSum。从您的span元素(我为其分配了唯一的ID)中获取了 maxSum totalSum 确保所有输入的总和不超过 maxSum

  4. 您有一些重复的代码,因此我将其重构为一个新方法:changeValue

总的来说,我认为代码可以说明一切。

哦,这段代码没有考虑到用户可以更改输入中的值。我将留给您在每个文本输入上使用“ oninput”侦听器来解决。

var totalSum = 0;  // 3
var maxSum = 0
var totalSumElement = null;

document.addEventListener('DOMContentLoaded',async function() {
  totalSumElement = document.getElementById('total-sum');
  maxSum = document.getElementById('max-sum').innerText;

  var incrementElements = document.querySelectorAll('.increment');  // 1
  var decrementElements = document.querySelectorAll('.decrement');

  addListener('click',incrementElements,incrementValue);
  addListener('click',decrementElements,decrementValue);
});


function addListener(type,elementArr,func) {
  for (element of elementArr) {
    element.addEventListener(type,func);
  }
}

function withinRange(newValue) {
  var maxReached  = newValue > maxSum;  // 3
  var zeroReached = newValue < 0;

  return !maxReached && !zeroReached;
}

function changeValue(event,change) {  // 4
  if (withinRange(totalSum + change)) {
    let parent = event.currentTarget.parentElement;  // 2
    let input  = parent.children[0];
    let value  = parseInt(input.value) || 0;
    
    if (withinRange(value + change)) {
      input.value = value + change;
      totalSum = totalSum + change;
    }
  }

  totalSumElement.textContent = `Total: ${totalSum}`;
}

function incrementValue(event) {
  changeValue(event,1);
}

function decrementValue(event) {
  changeValue(event,-1);
}
#totalqty {
  padding-bottom: 1rem;
}
<div id="totalqty" class="line padded-s">Total Quantity: <span id="max-sum">10</span></div>

<form>
  <input type="text" value="0" />
  <input class="increment" type="button" value="+" />
  <input class="decrement" type="button" value="-" />
</form>
<form>
  <input type="text" value="0" />
  <input class="increment" type="button" value="+" />
  <input class="decrement" type="button" value="-" />
</form>

<p id="total-sum"></p>

,

序言
只要脚本执行开始时固定总数量,就可以使用。否则,最好将实际允许的总量保存为属性,并使用MutationObserver进行观察。这样您就可以更新最高总数量属性更改时,代码中的值动态变化。您可以通过将custom attributes命名为“ data- *”来定义,其中“ *”是自定义名称。

解决问题的方法
您正在多个元素上使用相同的ID。您的意思是类,因此将id="increment"更改为class="increment",将decrement更改为相同内容。

由于我们不想在按钮上输入任何内容,而是在按钮上添加侦听器,所以我说最好使用<button>。在表单中,按钮充当type="submit",这是我们不想要的,因此我们需要将其更改为type="button"

由于行和总数实际上属于同一行,因此将它们放到一个 <form>元素中是比较明智​​的。但是,您仍然可以使用<div>将按钮和输入分组为一行。

现在有关行值的增/减和总数:

  1. 将允许的总量保存在变量中
  2. 将事件监听器添加到相应的按钮
  3. 如果操作有效,请更改行的值
  4. 将总数更新为totalQuantity - getSumOfRows()

要动态添加新行,我们创建并设置了这样的元素,并将其附加到表单中。请参阅下面的appendNewRow()函数。

边注
我已将readonly属性添加到输入字段,以便您无法通过键盘输入数字。

window.addEventListener("load",() => {
  let elTotalQuantity = document.querySelector("#totalqty");
  let totalQuantity = parseInt(elTotalQuantity.innerHTML);
  
  function getSumOfRows() {
    let sum = 0;
    for (let input of document.querySelectorAll("form .row > input.quantity"))
      sum += parseInt(input.value);
    return sum;
  }
  function updateTotalQuantity() {
      elTotalQuantity.innerHTML = totalQuantity - getSumOfRows();
  }
  
  function appendNewRow() {
    let row = document.createElement("div");
    row.classList.add("row");
    let child;
    
    // input.quantity
    let input = document.createElement("input");
    input.classList.add("quantity");
    input.value = "0";
    input.setAttribute("readonly","");
    input.setAttribute("type","text");
    row.append(input);
    
    // button.increment
    child = document.createElement("button");
    child.classList.add("increment");
    child.innerHTML = "+";
    child.setAttribute("type","button");
    child.addEventListener("click",() => {
      if (getSumOfRows() >= totalQuantity) return;
      input.value++;
      updateTotalQuantity();
    });
    row.append(child);
    
    // button.increment
    child = document.createElement("button");
    child.classList.add("decrement");
    child.innerHTML = "-";
    child.setAttribute("type",() => {
      if (input.value <= 0) return;
      input.value--;
      updateTotalQuantity();
    });
    row.append(child);
    
    // button.remove-row
    child = document.createElement("button");
    child.classList.add("remove-row");
    child.innerHTML = "Remove";
    child.setAttribute("type",() => {
      row.remove();
      updateTotalQuantity();
    });
    row.append(child);
    
    document.querySelector("form .rows").append(row);
  }
  
  document.querySelector("form .add-row").addEventListener("click",() => appendNewRow());
  
  appendNewRow();
});
<form>
  <label>Total Quantity: <span id="totalqty">10</span></label>
  <br>
  <div class="rows">
  </div>
  <button type="button" class="add-row">Add new row</button>
</form>