2014-10-30 52 views
1

我有用于将库存提交到数据库的库存表单。我在更新单位成本和动态生成行的总成本时遇到了一个问题。正如你可以在下面的快照中看到的那样。产品的名称通过自动完成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 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'); 

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

+0

在页面中不能有重复的ID。这是无效的HTML和jQuery只会看到第一场比赛。改为使用添加元素上的类并匹配那些元素。 – 2014-10-30 10:37:12

+0

为什么你在'if'内部增加输入,但是在'if'完成后再添加它们?如果他们都是'NaN',你为什么要乘以数字? – Barmar 2014-10-30 10:50:01

回答

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_idquantitycosttotal)。你的代码已经使用了这些类,所以只需移动/删除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>'); 

您正在使用一个处理程序,而不是其他人的委托事件。您还需要添加他们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(); 
    }); 

另一个问题是自动完成(我不能没有一个真正的数据饲料测试):

基本上得到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); 
    } 
+0

更好的代码还有一件事:$('#p_scents')。on('click','.remScnt',function(){'会稍微好一点(在性能上) – Regent 2014-10-30 10:43:13

+0

@Regent:授予并更新。对于任何鼠标事件,性能差异可以忽略不计,但这是一个很好的做法。 – 2014-10-30 10:47:06

+0

@ Regent:这个问题实际上存在大约6个不同的问题。现在感到无聊:) – 2014-10-30 10:52:39

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

}; 
+0

与您的解决方案添加项目和autocompete不起作用。你能否用完整的代码更新你的答案? – 2014-10-30 11:06:18