【问题标题】:Creating and validating a tiered pricing form创建和验证分层定价表
【发布时间】:2020-10-23 06:39:40
【问题描述】:

我正在尝试创建一个分层定价表单,使我们能够根据客户的使用量来更改价格。

我创建了一个表单,我们可以在其中添加和删除层,但我希望能够验证这一点,所以第一个选项应该始终以 0 开头,最后一层应该没有最大值,应该没有重叠,层与层之间不应有间隙。

例如: 0-5、6-10、11-15、15-20、21+

而不是: 2-5、7-11、10-12、13-19、20+

function update_max(){
  var pricing_tiers = document.getElementsByClassName("batch_pricing_tier");
  for(var i=0; i<pricing_tiers.length; i++){
    if(i!=0){
      var previous_tier = pricing_tiers.item(i-1);
      var previous_cols = previous_tier.children;
      var previous_max = parseInt(previous_cols[0].children[0].children[1].value);
    }else{
      var previous_max = -1;
    }
    var pricing_tier = pricing_tiers.item(i);
    var pricing_cols = pricing_tier.children;
    var minimum = parseInt(pricing_cols[0].children[0].children[1].value);
    var maximum = parseInt(pricing_cols[1].children[0].children[1].value);
    if(minimum <= previous_max){
      var new_min = previous_max+2;
      pricing_cols[0].children[0].children[1].value = new_min;
      minimum = new_min;
    }
    if(maximum <= minimum){
      var new_max = minimum+1;
      pricing_cols[1].children[0].children[1].value = new_max;
    }
  }
}
$(".batch_add").click(function(){
  $("#batch_form > div > div:first-child").clone(true).insertBefore("#batch_form > div > div:last-child");
  update_max();
});
$(".batch_remove").click(function(){
  $(this).parent().parent().remove();
  update_max();
});
$(".max_update").change(function(){
  update_max();
});
$("#batch_pricing_submit").click(function(){
  var pricing_array = [];
  var pricing_tiers = document.getElementsByClassName("batch_pricing_tier");
  for(var i=0; i<pricing_tiers.length; i++){
    pricing_array[i] = {};
    var pricing_tier = pricing_tiers.item(i);
    var pricing_cols = pricing_tier.children;
    var minimum = pricing_cols[0].children[0].children[1].value;
    var maximum = pricing_cols[1].children[0].children[1].value;
    var price = pricing_cols[2].children[0].children[1].value;
    pricing_array[i]['minimum'] = minimum;
    pricing_array[i]['maximum'] = maximum;
    pricing_array[i]['price'] = price;
  }
  console.log(pricing_array);
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<form class="form m-3" id="batch_form" method="POST">
  <div>
    <div class="row batch_pricing_tier">
      <div class="col">
        <div class="form-group">
          <label for="minimum">Minimum</label>
          <input class="form-control" type="text" value="0" required disabled>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label for="maximum">Maximum</label>
          <input class="form-control max_update" type="text" value="1" required>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label for="price">Price</label>
          <input class="form-control" type="text" placeholder="Price" name="price" id="price" required>
        </div>
      </div>
      <div class="col">
        <br /><span class="batch_remove float-right">Remove</span>
      </div>
    </div>
    <div class="row batch_pricing_tier">
      <div class="col">
        <div class="form-group">
          <label for="minimum">Minimum</label>
          <input class="form-control" type="text" value="2" required disabled>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label for="maximum">Maximum</label>
          <input class="form-control max_update" type="text" value="inf" required disabled>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label for="price">Price</label>
          <input class="form-control" type="text" placeholder="Price" name="price" id="price" required>
        </div>
      </div>
      <div class="col">
        <br /><span class="batch_remove float-right">Remove</span>
      </div>
    </div>
  </div>
  <span class="d-block w-100 align-center">
    <span class="batch_add float-right">Add fields</span>
    <br />
    <button class="btn btn-success" type="button" id="batch_pricing_submit" onclick="return false;">Add Batch Pricing</button>
  </span>
</form>

编辑

这是基于使用的定价模型。因此,客户使用的越多,价格应该越便宜。例如:

$10/unit for 0 to 5 units.
$9/unit for 6 to 10 units.
$8/unit for 11 to 15 units.

因此,如果用户在一个计费周期内使用 8 个单位,他们将被收取 9 x 8 个单位的费用,总计 72 美元。

每种产品都不同,因此会有不同单位数量的不同层级,因此我需要对此进行验证。 我需要第一层最低从 0 开始。 任何层的最大值应大于最小值。 下一层的最小值应该大于上一层的最大值。 层与层之间不应有间隙。 各层之间不应有重叠。

【问题讨论】:

  • 目前还不清楚你在期待什么。能详细点吗?
  • 为字段编写输入示例和预期输出,并解释我们如何使用您的表单。事实上,这很难理解。

标签: javascript html forms validation


【解决方案1】:

您可以编写 update_max 函数,以便更新字段,使其如您所愿。

function update_max() {
  let previous_max = -1;
  let previous_min = 0;

  $(".batch_pricing_tier").each(function(i, el) {
    const minimumInput = $(el).find(".min_update")[0];
    const maximumInput = $(el).find(".max_update")[0];
    let minimum = previous_max + 1;
    let maximum = Math.max(Number(maximumInput.value), minimum + 1);

    previous_min = minimumInput.value = minimum;
    if (!maximumInput.classList.contains("last_max"))
      previous_max = maximumInput.value = maximum;
  });

}

$(".batch_add").click(function() {
  $("#batch_form > div > div:first-child").clone(true).insertBefore("#batch_form > div > div:last-child");
  update_max();
});

$(".batch_remove").click(function() {
  $(this).parent().parent().remove();
  update_max();
});

$(".max_update").change(update_max);

$("#batch_pricing_submit").click(function() {
  var pricing_array = [];

  $(".batch_pricing_tier").each(function(i, el) {
    const minimumInput = $(el).find(".min_update")[0];
    const maximumInput = $(el).find(".max_update")[0];
    const priceInput = $(el).find(".price")[0];

    pricing_array.push({
      maximum: Number(minimumInput.value),
      minimum: Number(maximumInput.value),
      price: Number(priceInput.value),
    });
  });
  console.log(pricing_array);
});
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<form class="form m-3" id="batch_form" method="POST">
  <div>
    <div class="row batch_pricing_tier">
      <div class="col">
        <div class="form-group">
          <label>Minimum
                    <input class="form-control min_update" type="number" value="0" required disabled>
                </label>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label>Maximum
                    <input class="form-control max_update" type="number" value="1" required>
                </label>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label>Price
                    <input class="form-control price" type="text" placeholder="Price" name="price" id="price" required>
                </label>
        </div>
      </div>
      <div class="col">
        <br /><span class="batch_remove float-right">Remove</span>
      </div>
    </div>
    <div class="row batch_pricing_tier">
      <div class="col">
        <div class="form-group">
          <label>Minimum
                    <input class="form-control min_update" type="number" value="2" required disabled>
                </label>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label>Maximum
                    <input class="form-control max_update last_max" type="text" value="inf" required disabled>
                </label>
        </div>
      </div>
      <div class="col">
        <div class="form-group">
          <label>Price
                    <input class="form-control price" type="text" placeholder="Price" name="price" id="price" required>
                </label>
        </div>
      </div>
      <div class="col">
        <br /><span class="batch_remove float-right">Remove</span>
      </div>
    </div>
  </div>
  <span class="d-block w-100 align-center">
          <span class="batch_add float-right">Add fields</span>
  <br />
  <button class="btn btn-success" type="button" id="batch_pricing_submit" onclick="return false;">Add Batch Pricing</button>
  </span>
</form>

【讨论】:

    【解决方案2】:

    有两个验证条件(以 0 开头,以 inf 结尾)位于已知位置。所有其他(例如,没有间隙和没有重叠)都是关于将每一层与下一层进行比较。所以你遍历它们,从开始到倒数第二层,比较ith 层和i + 1th 层。这使您可以检查这些条件并准确找出不正确的地方和位置。如果没有发现问题,那么它是有效的。

    function update_max() {
      var pricing_tiers = document.getElementsByClassName("batch_pricing_tier");
      for (var i = 0; i < pricing_tiers.length; i++) {
        if (i != 0) {
          var previous_tier = pricing_tiers.item(i - 1);
          var previous_cols = previous_tier.children;
          var previous_max = parseInt(previous_cols[0].children[0].children[1].value);
        } else {
          var previous_max = -1;
        }
        var pricing_tier = pricing_tiers.item(i);
        var pricing_cols = pricing_tier.children;
        var minimum = parseInt(pricing_cols[0].children[0].children[1].value);
        var maximum = parseInt(pricing_cols[1].children[0].children[1].value);
        if (minimum <= previous_max) {
          var new_min = previous_max + 2;
          pricing_cols[0].children[0].children[1].value = new_min;
          minimum = new_min;
        }
        if (maximum <= minimum) {
          var new_max = minimum + 1;
          pricing_cols[1].children[0].children[1].value = new_max;
        }
      }
    }
    $(".batch_add").click(function() {
      $("#batch_form > div > div:first-child").clone(true).insertBefore("#batch_form > div > div:last-child");
      update_max();
    });
    $(".batch_remove").click(function() {
      $(this).parent().parent().remove();
      update_max();
    });
    $(".max_update").change(function() {
      update_max();
    });
    $("#batch_pricing_submit").click(function() {
      var pricing_array = [];
      var pricing_tiers = document.getElementsByClassName("batch_pricing_tier");
      for (var i = 0; i < pricing_tiers.length; i++) {
        pricing_array[i] = {};
        var pricing_tier = pricing_tiers.item(i);
        var pricing_cols = pricing_tier.children;
        var minimum = pricing_cols[0].children[0].children[1].value;
        var maximum = pricing_cols[1].children[0].children[1].value;
        var price = pricing_cols[2].children[0].children[1].value;
    
        pricing_array[i]['minimum'] = minimum;
        pricing_array[i]['maximum'] = maximum;
        pricing_array[i]['price'] = price;
      }
      console.log(pricing_array);
    
      console.log(validate(pricing_array));
    });
    
    function validate(pricing_array) {
      var i = 0;
      var min = null;
      var max = null;
      var price = null;
      var nextMin = null;
      var nextPrice = null;
    
      //Does the first option start with 0?
      if (parseInt(pricing_array[0].minimum) !== 0) {
        return "First option does not start with 0";
      };
    
      //No max on last tier
      if (typeof getInt(pricing_array[pricing_array.length - 1].maximum) === "number") {
        return "The last tier must not have a maximum";
      };
    
      if (0 < pricing_array.length) {
        for (i = 0; i < pricing_array.length - 1; i++) {
          //Check data types
          min = getInt(pricing_array[i].minimum);
          max = getInt(pricing_array[i].maximum);
          price = getInt(pricing_array[i].price);
          nextMin = getInt(pricing_array[i + 1].minimum);
          nextPrice = getInt(pricing_array[i + 1].price);
    
          if (typeof max !== "number") {
            return "The Maximum entered on Tier " + (i + 1) + " is not a number.";
          };
    
          if (typeof price !== "number") {
            return "The Price entered on Tier " + (i + 1) + " is not a number.";
          };
    
          if (typeof nextMin !== "number") {
            return "The Minimum entered on Tier " + (i + 2) + " is not a number.";
          };
    
          if (typeof nextPrice !== "number") {
            return "The Price entered on Tier " + (i + 2) + " is not a number.";
          };
    
          //Check max and min
          if (max < min) {
            return "The Maximum on Tier " + (i + 1) + " is less than the Minimum.";
          };
    
          //Check no overlap - must be larger
          if (nextMin <= max) {
            return "Tier " + (i + 1) + " overlaps with Tier " + (i + 2) + ".";
          };
    
          //Check no gaps
          if (1 < (nextMin - max)) {
            return "There is a gap between Tier " + (i + 1) + " and Tier " + (i + 2) + ".";
          };
    
          //Does the price get cheaper?
          if (nextPrice <= price) {
            return "The Price does not get cheaper between Tier " + (i + 1) + " and Tier " + (i + 2) + ".";
          };
        };
      };
    
      return "OK";
    };
    
    function getInt(val) {
      return parseInt(val) || val;
    };
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    
    
    <form class="form m-3" id="batch_form" method="POST">
      <div>
        <div class="row batch_pricing_tier">
          <div class="col">
            <div class="form-group">
              <label for="minimum">Minimum</label>
              <input class="form-control" type="text" value="0" required disabled>
            </div>
          </div>
          <div class="col">
            <div class="form-group">
              <label for="maximum">Maximum</label>
              <input class="form-control max_update" type="text" value="1" required>
            </div>
          </div>
          <div class="col">
            <div class="form-group">
              <label for="price">Price</label>
              <input class="form-control" type="text" placeholder="Price" name="price" id="price" required>
            </div>
          </div>
          <div class="col">
            <br /><span class="batch_remove float-right">Remove</span>
          </div>
        </div>
        <div class="row batch_pricing_tier">
          <div class="col">
            <div class="form-group">
              <label for="minimum">Minimum</label>
              <input class="form-control" type="text" value="2" required disabled>
            </div>
          </div>
          <div class="col">
            <div class="form-group">
              <label for="maximum">Maximum</label>
              <input class="form-control max_update" type="text" value="inf" required disabled>
            </div>
          </div>
          <div class="col">
            <div class="form-group">
              <label for="price">Price</label>
              <input class="form-control" type="text" placeholder="Price" name="price" id="price" required>
            </div>
          </div>
          <div class="col">
            <br /><span class="batch_remove float-right">Remove</span>
          </div>
        </div>
      </div>
      <span class="d-block w-100 align-center">
        <span class="batch_add float-right">Add fields</span>
      <br />
      <button class="btn btn-success" type="button" id="batch_pricing_submit" onclick="return false;">Add Batch Pricing</button>
      </span>
    </form>

    【讨论】:

      【解决方案3】:

      检查以下sn-p。您的原始代码有一些更改,但通常需要这样的东西。

      function update_max(index,quantity=1) {
        if (index >= 0) {
          let val = (index == 0 ? 0 : $(document).find('.row.batch_pricing_tier[data-row="' + index + '"] input.max_update').val());
          $.each($(document).find('.row.batch_pricing_tier'), (k, x) => {
            let row = parseInt($(x).attr('data-row'));
            if (row > index) {
              let items = $(x).find('input.form-control:not(.price)');
              $.each(items, (i, y) => {
                if ($(y).hasClass('max_update')) {
                  $(y).val(parseInt($(items[i - 1]).val()) + quantity);
                } else {
                  if (index == 0 && row == 1) {
                    $(y).val(index);
                  } else {
                    $(y).val(parseInt($(document).find('.row.batch_pricing_tier[data-row="' + (row - 1 < index ? index : row - 1) + '"] input.max_update').val()) + 1);
                  }
                }
              });
            }
          });
        }
      }
      $(".batch_add").click(function() {
        let clone = $("#batch_form > div > div:first-child").clone(true);
        $("#batch_form > div").append(clone);
        let tiers = $(document).find('.row.batch_pricing_tier');
        $("#batch_form > div > div:last-child").attr('data-row', tiers.length)
        //update_max(tiers.length - 1); // default quantity 1
        update_max(tiers.length - 1,4);
      });
      $(".batch_remove").click(function() {
        let tiers = $(document).find('.row.batch_pricing_tier');
      
        if (tiers.length > 1) {
          let index = $(this).parents('.row.batch_pricing_tier').attr('data-row');
          $(this).parents('.row.batch_pricing_tier').remove();
          $.each($(document).find('.row.batch_pricing_tier'), (k, x) => {
            $(x).attr('data-row', k + 1);
          });
          //update_max(index - 1); // default quantity 1
          update_max(index - 1,4);
        }
      });
      $(document).on("change", ".max_update", function() {
        let index = $(this).parents('.row.batch_pricing_tier').attr('data-row');
        //update_max(index); // default quantity 1
        update_max(index,4);
      });
      $("#batch_pricing_submit").click(function() {
        var pricing_array = [];
        var pricing_tiers = document.getElementsByClassName("batch_pricing_tier");
        for (var i = 0; i < pricing_tiers.length; i++) {
          pricing_array[i] = {};
          var pricing_tier = pricing_tiers.item(i);
          var pricing_cols = pricing_tier.children;
          var minimum = pricing_cols[0].children[0].children[1].value;
          var maximum = pricing_cols[1].children[0].children[1].value;
          var price = pricing_cols[2].children[0].children[1].value;
          pricing_array[i]['minimum'] = minimum;
          pricing_array[i]['maximum'] = maximum;
          pricing_array[i]['price'] = price;
        }
        console.log(pricing_array);
      });
      <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
      <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
      <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      
      
      <form class="form m-3" id="batch_form" method="POST">
        <div>
          <div class="row batch_pricing_tier" data-row="1">
            <div class="col">
              <div class="form-group">
                <label for="minimum">Minimum</label>
                <input class="form-control" type="text" pattern="[0-9]" value="0" required disabled>
              </div>
            </div>
            <div class="col">
              <div class="form-group">
                <label for="maximum">Maximum</label>
                <input class="form-control max_update" pattern="[0-9]" type="text" value="5" required>
              </div>
            </div>
            <div class="col">
              <div class="form-group">
                <label for="price">Price</label>
                <input class="form-control price" type="text" placeholder="Price" name="price" required>
              </div>
            </div>
            <div class="col">
              <br /><span class="batch_remove float-right">Remove</span>
            </div>
          </div>
        </div>
        <span class="d-block w-100 align-center">
          <span class="batch_add float-right">Add fields</span>
        <br />
        <button class="btn btn-success" type="button" id="batch_pricing_submit" onclick="return false;">Add Batch Pricing</button>
        </span>
      </form>

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-10-24
        • 1970-01-01
        • 2021-06-29
        • 2020-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多