2014-10-30 49 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