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

时间:2014-10-30 10:35:43

标签: javascript jquery autocomplete

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

enter image description here

HTML CODE

<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 CODE

<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 CODE

<?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');

我还需要输入运费成本输入字段并在表格底部显示发票总额。

2 个答案:

答案 0 :(得分:3)

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

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

<强>模板:

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

重复ID无效

您不能在页面中包含重复的ID。这是无效的HTML和jQuery只会看到第一场比赛。改为使用添加元素上的类并匹配它们。

所以使用:

<a class="remScnt" 

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

注意:您还需要排除任何其他重复的ID(例如product_idquantity以及costtotal)。您的代码已经使用了类,因此只需移动/删除id属性。

e.g。使用所有类的类:

    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>');

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

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

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

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

更新:如下所示Regent,您不应使用document,而是使用#p_scents作为委派事件处理程序:

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

委托事件应附加到最近的不变的祖先(如果方便/可用)。这将使得速度非常小,因为它在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);
   }

由于您希望在发货更改时更新总计,我会对其进行重构,以便也可以从运输中的密钥调用:

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

另一个问题是自动填充功能(如果没有真正的数据Feed,我就无法测试):

基本上让select事件引用当前字段的行并找到要更新的相应字段:

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);
   }

答案 1 :(得分:0)

updateTotal()使用$('.quantity').val()时,它会获取该类的第一个字段的值,而不是用户输入的行中的值。您需要将该行传递给该函数。此外,由于元素是动态添加的,因此您需要使用委托来进行事件绑定。

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

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

        if(!input1){
            $('.total', row).val($(input2);
                                }

        } else {          
            $('.total', row).val(input1 * input2);
        }
    }
    var output_total = $('.total', row);
    var total = input1 + input2;
    output_total.val(total);

};