2012-10-29 138 views
3

我們有使用Razor和Knockout.js顯示錶單的視圖。部分表單要求用戶輸入值列表,我們使用ko.observablearray來跟蹤它們。這個列表被表示爲一堆文本框,每個值一個,每個框旁邊都有一個「刪除」按鈕,在它們下面有一個「添加」按鈕。它的工作原理與http://learn.knockoutjs.com/#/?tutorial=collections的演示項目類似。敲除綁定無法按預期操作可觀察陣列

我們的形式有兩種方式意外作用:

  1. 當點擊刪除按鈕,它會從ko.observablearray所有值,而不是僅僅對應於被點擊一下之一。
  2. 當點擊整個表單的「提交」按鈕時,它會向ko.observablearray添加一個新元素,而不是將表單提交給我們的服務器。

爲什麼我們會看到這種行爲? (我知道這些是兩個不同的問題,但我不確定它們是否是由相同的潛在問題引起的,這就是爲什麼我在一個問題中發佈它們。)

這是我們的剃刀視圖:

@model OurProject.Models.Input.InputModel 
@{ 
    ViewBag.Title = "Input"; 
} 

<h2>Inputs</h2> 

<div id="inputForm"> 
    <!-- snip - lots of input elements to fill in that are bound to KO --> 

    <div> 
     @Html.LabelFor(model => model.POSTransactionCodes) 
    </div> 
    <div> 
     <span class="help-block">Separate values by commas.</span> 
    </div> 
    <div> 
     <ul data-bind="foreach: POSTransactionCodes"> 
      <li><input data-bind="value: $data" /> <a href="#" data-bind="click: $root.removePOSTransactionCode">Delete</a></li> 
     </ul> 
     <button data-bind="click: addPOSTransactionCode">Add another POS Transaction Code</button> 

     @Html.ValidationMessageFor(model => model.POSTransactionCodes, null, new { @class = "help-inline" }) 
    </div> 
    <!-- snip - more input elements --> 

    <button data-bind="click: save">Submit</button> 
</div> 

<script type="text/javascript" src='~/Scripts/jquery-1.8.2.min.js'></script> 
<script type="text/javascript" src='~/Scripts/knockout-2.1.0.js'></script> 
<script type="text/javascript" src='~/Scripts/OP/OP.js'></script> 
<script type="text/javascript" src='~/Scripts/OP/Input/OP.Input.Input.Form.js'></script> 
<script type="text/javascript" src='~/Scripts/OP/Input/OP.Input.Input.Data.js'></script> 
<script type="text/javascript"> 
    var elementToBindTo = $("#inputForm")[0]; 
    OP.Input.Input.Form.init(elementToBindTo); 
</script> 

這裏是我們的主片的敲除代碼,OP.Input.Input.Form.js:

extend(OP, 'OP.Input.Input.Form'); 
OP.Input.Input.Form = function (jQuery) { 
    //The ViewModel for the page 
    var ViewModel = function() { 
     var self = this; 

     //Fields 
     /* snip - lots of ko.observables() */ 
     self.POSTransactionCodes = ko.observableArray([]); //is a list of transaction codes 
     /* snip - lots of ko.observables() */ 

     //Set up with initial data 
     self.initialize = function() { 
      var c = function (data, status, response) { 
       if (status === "success") { 
        /* snip - lots of ko.observables() */ 
        ko.utils.arrayPushAll(self.POSTransactionCodes, data.POSTransactionCodes); 
        self.POSTransactionCodes.valueHasMutated(); 
        /* snip - lots of ko.observables() */ 
       } else { 

       } 
      }; 
      OP.Input.Input.Data.GetInput(c); 
     } 

     //When saving, submit data to server 
     self.save = function (model) { 
      var c = function (data, status, response) { 
       if (status === "success") { 
        //After succesfully submitting input data, go to /Input/Submitted 
        //in order to let MVC determine where to send the user next 
        window.location.href = "~/Input/Submitted"; 
       } else { 
       } 
      }; 
      OP.Input.Input.Data.SaveInput(model, c); 
     } 

     //Modifying POSTransactionCodes array 
     self.removePOSTransactionCode = function (POScode) { 
      self.POSTransactionCodes.remove(POScode) 
     } 

     self.addPOSTransactionCode = function() { 
      self.POSTransactionCodes.push(""); 
     } 
    }; 

    //Connect KO form to HTML 
    return { 
     init: function (elToBind) { 
      var model = new ViewModel(); 
      ko.applyBindings(model, elToBind); 
      model.initialize(); 
     } 
    }; 
} ($); 

這裏是OP.Input.Input.Data.js:

extend(OP, 'OP.Input.Input.Data'); 
OP.Input.Input.Data = { 
    GetInput: function (callback) { 
     $.get("/API/Input/InputAPI/GetInputModel", callback); 
    }, 
    SaveInput: function (input, callback) { 
     $.ajax({ 
      url: "/API/Input/InputAPI/SaveInput", 
      type: "post", 
      data: input, 
      complete: callback 
     }); 
    } 
}; 

回答

2

您需要將新的ViewModel推入您的可觀察數組中。其中將包含可觀察的屬性。

因此,要做到這一點,我創建了一個名爲TransactionCodeView

var TransactionCodeView = function() { 
    var self = this; 
    self.code = ko.observable("");  
}; 

然後,當用戶點擊「添加其他POS交易代碼」的新視圖模型:

self.addPOSTransactionCode = function() { 
    self.POSTransactionCodes.push(new TransactionCodeView()); 
} 

唯一的其他東西改變是在HTML綁定:

<li><input data-bind="value: code" /> <a href="#" data-bind="click: $root.removePOSTransactionCode">Delete</a></li> 

因爲code是OBSERV在新的視圖模型中,我們將input值綁定到該屬性。請看jsfiddle。我沒有測試的原因很明顯;-)

0

這就是爲什麼提交功能不工作我的形式提交功能:

在視圖中,我有這個剃鬚刀:

<div> 
    <ul data-bind="foreach: POSTransactionCodes"> 
     <li><input data-bind="value: $data" /> <a href="#" data-bind="click: $root.removePOSTransactionCode">Delete</a></li> 
    </ul> 
    <button data-bind="click: addPOSTransactionCode">Add another POS Transaction Code</button> 

    @Html.ValidationMessageFor(model => model.POSTransactionCodes, null, new { @class = "help-inline" }) 
</div> 

對我的「添加」按鈕使用button元素會導致它響應用戶按Enter鍵而不是表單末尾的提交按鈕。當我將按鈕改爲input元素時,它開始按預期工作。

<input type="button" value="Add another POS Transaction Code" 
    data-bind="click: addPOSTransactionCode" />