javascript - 使用动态生成的行更新字段时出错

标签 javascript jquery autocomplete

我有库存表可以将库存提交到数据库。我在更新动态生成的行的单位成本和总成本方面遇到了问题。正如您在下面的快照中看到的那样。产品名称通过自动完成 jQuery 获取。

enter image description here

HTML代码

<table class="table table-bordered table-hover">
    <thead>
        <tr>
            <th>#</th>
            <th>Product Name/Code</th>
            <th>Quantity</th>
            <th>Unit Cost</th>
            <th>Total Cost</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody id="p_scents">
        <tr>
            <td>1</td>
            <td><input id="product_id" type="text" name="product_id[]" hidden><input id="product_code" type="text" name="product_code[]" hidden><input class="product_name form-control" id="product_name" type="text" placeholder="Type product name/code here" name="products[]" required></td>
            <td><input class="quantity form-control" id="quantity" type="text" placeholder="Quantity to Buy" name="quantity[]" required /></td>
            <td><div class="input-group"><span class="input-group-addon">$</span><input class="cost form-control" id="cost" placeholder="Unit Cost" type="text" readonly /></div></td>
            <td><div class="input-group"><span class="input-group-addon">$</span><input class="total form-control" id="total" placeholder="Total" type="text" readonly /></div></td>
            <td><button class="btn btn-default" type="button" id="addScnt"><i class="fa fa-plus "></i> Item</button></td>
        </tr>
    </tbody>
</table>

jQuery 代码

<script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type='text/javascript'>

jQuery(document).ready(function(){
    var scntDiv = $('#p_scents');
    var i = $('#p_scents tr').size() + 1;

    $('#addScnt').click(function() {
        scntDiv.append('<tr>'+
        '<td>'+i+'</td>'+
        '<td><input id="product_id" type="text" name="product_id[]" hidden><input id="product_code" type="text" name="product_code[]" hidden><input class="product_name form-control" id="product_name" type="text" placeholder="Type product name/code here" name="products[]" required></td>'+
        '<td><input class="quantity form-control" id="quantity" type="text" placeholder="Quantity to Buy" name="quantity[]" required /></td>'+
        '<td><div class="input-group"><span class="input-group-addon">$</span><input class="cost form-control" id="cost" placeholder="Unit Cost" type="text" readonly /></div></td>'+
        '<td><div class="input-group"><span class="input-group-addon">$</span><input class="total form-control" id="total" placeholder="Total" type="text" readonly /></div></td>'+
        '<td><a id="remScnt" class="btn btn-danger btn-xs"><span title="Delete" class="glyphicon glyphicon-remove"></span></a></td>'+
        '</tr>');
        i++;
        //return false;
        $('.product_name').autocomplete({
            source:'http://localhost/Multi-Channel_Shipping/inc/auto_product.php',
            minLength:2,
            select:function(evt, ui)
            {
                // when a product is selected, populate related fields in this form
                this.form.cost.value = ui.item.cost;
                this.form.product_id.value = ui.item.product_id;
                this.form.product_code.value = ui.item.product_code;
            }
        });

        $('.quantity').keyup(function() {  
            updateTotal();
        });
        $('.cost').keyup(function() {  
            updateTotal();
        });

        var updateTotal = function () {
          var input1 = parseFloat($('.quantity').val());
          var input2 = parseFloat($('.cost').val());
          if (isNaN(input1) || isNaN(input2)) {
              if(!input2){
                    $('.total').val($('.quantity').val());
              }

              if(!input1){
                    $('.total').val($('.cost').val());
              }

          } else {          
                $('.total').val(input1 * input2);
          }
        };

        var output_total = $('.total');
        var total = input1 + input2;
        output_total.val(total);

    });

    //Remove button
    $(document).on('click', '#remScnt', function() {
        if (i > 2) {
            $(this).closest('tr').remove();
            i--;
        }
        return false;
    });

    $('.product_name').autocomplete({
        source:'http://localhost/Multi-Channel_Shipping/inc/auto_product.php',
        minLength:2,
        select:function(evt, ui)
        {
            // when a zipcode is selected, populate related fields in this form
            this.form.cost.value = ui.item.cost;
            this.form.product_id.value = ui.item.product_id;
            this.form.product_code.value = ui.item.product_code;
        }
    });


    $('.quantity').keyup(function() {  
        updateTotal();
    });
    $('.cost').keyup(function() {  
        updateTotal();
    });

    var updateTotal = function () {
      var input1 = parseFloat($('.quantity').val());
      var input2 = parseFloat($('.cost').val());
      if (isNaN(input1) || isNaN(input2)) {
          if(!input2){
                $('.total').val($('.quantity').val());
          }

          if(!input1){
                $('.total').val($('.cost').val());
          }

      } else {          
            $('.total').val(input1 * input2);
      }
    };

    var output_total = $('.total');
    var total = input1 + input2;
    output_total.val(total);

});
</script>

AUTO_PRODUCT.PHP 代码

<?php

class DB
{
    const DATABASE = 'multi-channel_shipping';
    const HOST = 'localhost';
    const USERNAME = 'root';
    const PASSWORD = '';

    static private $pdo;

    static public function singleton()
    {
        if (!is_object(self::$pdo))
        {
            self::$pdo = new PDO('mysql:dbname=' . self::DATABASE . ';host=' . self::HOST, 
                                    self::USERNAME, 
                                    self::PASSWORD);
        }
        return self::$pdo;
    }

    private function __construct()
    {

    }

    public function __clone()
    {
        throw new Exception('You may not clone the DB instance');
    }
}

if (!isset($_REQUEST['term']))
{
    die('([])');
}

$st = DB::singleton()
        ->prepare(
            'SELECT * ' .
            'FROM products ' .
            'WHERE (name LIKE :name) OR (code LIKE :name) ' .
            'ORDER BY name ASC ' .
            'LIMIT 0,10');

$searchProduct = '%'.$_REQUEST['term'].'%';
$st->bindParam(':name', $searchProduct, PDO::PARAM_STR);

$data = array();
if ($st->execute())
{
    while ($row = $st->fetch(PDO::FETCH_OBJ))
    {
        $data[] = array(
            'value' => $row->code." - ".$row->name,
            'cost' => $row->cost,
            'product_id' => $row->id,
            'product_code' => $row->code
        );
    }
}
echo json_encode($data);
flush(); 
?>

MySQL数据

--
-- Table structure for table `products`
--

CREATE TABLE IF NOT EXISTS `products` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `code` varchar(100) NOT NULL,
  `name` varchar(255) NOT NULL,
  `unit` varchar(50) DEFAULT NULL,
  `cost` decimal(25,2) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `code` (`code`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=3 ;

--
-- Dumping data for table `products`
--

INSERT INTO `products` (`id`, `code`, `name`, `unit`, `cost`) VALUES
(1, '4815162342', 'BAZIC 12 Dil Dil Pak', 'Packet', '0.10'),
(2, '23', 'Razer', 'Piece', '0.03');

我还需要在表格底部放置运费输入字段并显示发票总计。

最佳答案

页面和代码存在多个问题,所以我会尽我所能。 @Barmar 还发现了其他问题,因此将尝试涵盖所有内容并提出一些改进建议。

JSFiddle: http://jsfiddle.net/TrueBlueAussie/vx15mr4n/29/

模板化:

与其在代码中使用文本字符串,不如将 HTML 维护为 HTML。我提供的示例使用了一个虚拟脚本 block (type="text/template",所有浏览器都会忽略它)但是您可以使用 $('#template').html() 访问 HTML 内容

重复 ID 无效

页面中不能有重复的 ID。那是无效的 HTML,jQuery 只会看到第一个匹配项。而是在添加的元素上使用类并匹配这些元素。

所以使用:

<a class="remScnt" 

$(document).on('click', '.remScnt', function() 

注意:您还需要整理任何其他重复的 ID(例如 product_idquantitycost总计)。您的代码已经为这些使用了类,因此只需移动/删除 id 属性即可。

例如对一切都使用类:

    scntDiv.append('<tr>'+
    '<td>'+i+'</td>'+
    '<td><input class="product_id" type="text" name="product_id[]" hidden><input id="product_code" type="text" name="product_code[]" hidden><input class="product_name form-control" type="text" placeholder="Type product name/code here" name="products[]" required></td>'+
    '<td><input class="quantity form-control" type="text" placeholder="Quantity to Buy" name="quantity[]" required /></td>'+
    '<td><div class="input-group"><span class="input-group-addon">$</span><input class="cost form-control" placeholder="Unit Cost" type="text" readonly /></div></td>'+
    '<td><div class="input-group"><span class="input-group-addon">$</span><input class="total form-control" placeholder="Total" type="text" readonly /></div></td>'+
    '<td><a class="remScnt btn btn-danger btn-xs"><span title="Delete" class="glyphicon glyphicon-remove"></span></a></td>'+
    '</tr>');

您正在为一个处理程序而不是其他处理程序使用委托(delegate)事件。您还需要为 keyup 添加它们(可以合并,因为代码相同):

$('#p_scents').on('keyup', '.quantity .cost', function() {  
    updateTotal();
});

重要提示:此处的代码与特定行不匹配。还可以像这样使用 @Barmar 的 修复来传递当前行:

$('#p_scents').on('keyup', '.quantity .cost', function() {  
    updateTotal($(this).closest('tr'));
});

更新:正如下面Regent 提到的,您不应使用document,而应使用#p_scents 作为您的委托(delegate)事件处理程序:

$('#p_scents').on('click', '.remScnt', function() 

委托(delegate)事件应附加到最近的不变祖先(如果方便/可用)。这将带来非常小的速度提升,因为它在 DOM 中的位置较低。

我还清理了事件处理程序,它现在使用临时变量对与行相关的元素进行计算,看起来像:

// Update the row total of a specific row
var updateTotal = function ($row) {
    // Get the specific inputs
    var $quantity = $('.quantity', $row);
    var $cost = $('.cost', $row);
    var $total = $('.total', $row);
    var input1 = parseFloat($quantity.val());
    var input2 = parseFloat($cost.val());
    if (isNaN(input1) || isNaN(input2)) {
        if (!input2) {
            $total.val($quantity.val());
        }

        if (!input1) {
            $total.val($cost.val());
        }

    } else {
        $total.val(input1 * input2);
    }
    var total = input1 * input2;
    $total.val(total);
};

注意:没有缺失的数据,我无法轻松测试代码,但您应该明白了。

总计

要更新总计,您需要迭代所有 .total 字段并将它们添加到运费中:

   var updateGrandTotal = function()
   {
       // Now update the grand total
       var grandTotal = 0;
       $('.total').each(function () {
           grandTotal += parseFloat($(this).val());
       });
       var shipping = parseFloat($('.shippingcost').val());
       $('.grandtotal').val(grandTotal + shipping);
   }

由于运费发生变化时您会想要更新总计,因此我将其重构,以便也可以从运费的 keyup 中调用它:

   $('.shippingcost').keyup(function(){
       updateGrandTotal();
   });

另一个问题是自动完成(如果没有真实的数据馈送,我无法测试):

基本上获取选择事件以引用当前字段的行并找到要更新的适当字段:

JSFiddle: http://jsfiddle.net/TrueBlueAussie/vx15mr4n/23/

   select: function (evt, ui) {
       // when a product is selected, populate related fields in this form
       var $tr = $(this).closest("tr");
       $(".cost",$tr).val(ui.item.cost);
       $(".product_id", $tr).val(ui.item.product_id);
       $(".product_code", $tr).val(ui.item.product_code);
   }

关于javascript - 使用动态生成的行更新字段时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26650724/

相关文章:

javascript - 生成的 JavaScript 函数中的变量未按预期运行

javascript - 标记文本中的几个单词

javascript - "onkeypress"属性的html多个函数

javascript - 使用jquery在android中捕获 "back button"按键

jquery - 如何在不同页面访问phonegap数据库?

javascript - 第一个插件,我怎样才能让它为动态生成的内容而活

c# - 如何动态更改 C# 组合框或文本框中的自动完成条目?

xcode - Xcode中的自动完成功能无法按预期运行(通过使用其他IDE)

autocomplete - IDE 从哪里获得完成候选者?

javascript - Redux Dev Tools Chrome 扩展 Immutable.js 导致错误