title: Knockout with MVC3: Knockout Model won't post collection data?
body: <p><strong>ANSWER:</strong>
  Replacing this line:</p>
  
  <pre><code>self.identifiers.push(new Identifier(self.identifierToAdd(), self.selectedIdentifierTypeValue()));
  </code></pre>
  
  <p>With this line:</p>
  
  <pre><code>self.identifiers.push({ Key: self.identifierToAdd(), Value: self.selectedIdentifierTypeValue()});
  </code></pre>
  
  <p>The post requests is now sending the collection data correctly. However that doesn't solve the fact that the MVC action is not receiving it but this question is big enough already.</p>
  
  <hr>
  
  <p>I can't seem to get the data from collection property of my model in knockout into my MVC model when posting to an action. If I alert <code>ko.toJSON</code> my <code>identifiers()</code> property from below it properly shows all the data, but when I try and submit that data via a normal postback (the action just takes the EquipmentCreateModel below), it looks like this:</p>
  
  <p><img src="https://i.stack.imgur.com/YWQMe.png" alt="state of model upon submit"></p>
  
  <p>Identifiers is empty and when I look at the ModelState error for Identifiers, it says that it <code>cannot convert String to Dictionary&lt;Guid, string&gt;</code>. What am I doing wrong? I thought MVC3 automatically converts JSON into objects if it can, as it did with the <code>BuildingCode</code> and <code>Room</code> properties?</p>
  
  <p>Also why does my string data in the above picture have escaped quotes?</p>
  
  <hr>
  
  <p><strong>EDITS:</strong> 
  If I look at the post data, identifiers is shown as an empty array (<code>identifiers: [{}]</code>). I tried jsoning identifiers in the save method like so:</p>
  
  <pre><code>self.identifiers = ko.toJSON(self.identifiers());
  </code></pre>
  
  <p>This causes the request data to not be empty and look like this:</p>
  
  <pre><code>identifiers:"[{\"Value\":\"sdfsd\",\"Key\":\"4554f477-5a58-4e81-a6b9-7fc24d081def\"}]"
  </code></pre>
  
  <p>However, the same problem occurs when I debug the action. I also tried jsoning the entire model (as outlined in <a href="https://stackoverflow.com/questions/8091103/knockoutjs-submit-with-ko-utils-postjson-issue">knockoutjs submit with ko.utils.postJson issue</a>):</p>
  
  <pre><code>ko.utils.postJson($("form")[0], ko.toJSON(self));
  </code></pre>
  
  <p>But this gives a .NET error that says <code>Operation is not valid due to the current state of the object.</code> Which from looking at the request data it looks like it's being JSON-ified twice because each letter or character is it's own value in the HttpCollection and this is because .NET only allows 1000 max by default (<a href="https://stackoverflow.com/questions/8832470/operation-is-not-valid-due-to-the-current-state-of-the-object-error-during-pos">&#39;Operation is not valid due to the current state of the object&#39; error during postback</a>).</p>
  
  <p>Using the $.ajax method to submit the data, everything works fine:</p>
  
  <pre><code> $.ajax({
              url: location.href, 
              type: "POST",
              data: ko.toJSON(viewModel),
              datatype: "json",
              contentType: "application/json charset=utf-8",
              success: function (data) { alert("success"); }, 
              error: function (data) { alert("error"); }
          });
  </code></pre>
  
  <p>But due to other reasons I cannot use the $.ajax method for this, so I need it working in the normal post. Why can I <code>toJSON</code> the entire viewModel in the ajax request and it works, but in the normal postback it splits it up, and when I don't, all quotes are escaped in the sent JSON.</p>
  
  <hr>
  
  <p>Here is my ViewModel:</p>
  
  <pre><code>public class EquipmentCreateModel
  {
  //used to populate form drop downs
  public ICollection&lt;Building&gt; Buildings { get; set; }
  public ICollection&lt;IdentifierType&gt; IdentifierTypes { get; set; }
  
  [Required]
  [Display(Name = "Building")]
  public string BuildingCode { get; set; }
  
  [Required]
  public string Room { get; set; }
  
  [Required]
  [Range(1, 100, ErrorMessage = "You must add at least one identifier.")]
  public int IdentifiersCount { get; set; } //used as a hidden field to validate the list
  public string IdentifierValue { get; set; } //used only for knockout viewmodel binding
  
  public IDictionary&lt;Guid, string&gt; Identifiers { get; set; }
  }
  </code></pre>
  
  <p>Then my knock-out script/ViewModel:</p>
  
  <pre><code>&lt;script type="text/javascript"&gt;
  // Class to represent an identifier
  function Identifier(value, identifierType) {
      var self = this;
      self.Value = ko.observable(value);
      self.Key = ko.observable(identifierType);
  }
  
  // Overall viewmodel for this screen, along with initial state
  function AutoclaveCreateViewModel() {
      var self = this;
  
      //MVC properties
      self.BuildingCode = ko.observable();
      self.room = ko.observable("55");
      self.identifiers = ko.observableArray();
      self.identiferTypes = @Html.Raw(Json.Encode(Model.IdentifierTypes));
      self.identifiersCount = ko.observable();
  
  
      //ko-only properties
      self.selectedIdentifierTypeValue = ko.observable();
      self.identifierToAdd = ko.observable("");
  
      //functionality
      self.addIdentifier = function() {
          if ((self.identifierToAdd() != "") &amp;&amp; (self.identifiers.indexOf(self.identifierToAdd()) &lt; 0)) // Prevent blanks and duplicates
          {
              self.identifiers.push(new Identifier(self.identifierToAdd(), self.selectedIdentifierTypeValue()));
              alert(ko.toJSON(self.identifiers()));
          }
          self.identifierToAdd(""); // Clear the text box
      };
  
      self.removeIdentifier = function (identifier) {
          self.identifiers.remove(identifier);
          alert(JSON.stringify(self.identifiers()));
      };
  
      self.save = function(form) {
          self.identifiersCount = self.identifiers().length;
          ko.utils.postJson($("form")[0], self);
      };
  }
      var viewModel = new EquipmentCreateViewModel();
      ko.applyBindings(viewModel);
      $.validator.unobtrusive.parse("#equipmentCreation");      
      $("#equipmentCreation").data("validator").settings.submitHandler = viewModel.save;
  </code></pre>
  
  <p> </p>
  
  <p>View:</p>
  
  <pre><code>@using (Html.BeginForm("Create", "Equipment", FormMethod.Post, new { id="equipmentCreation"}))
  {
  @Html.ValidationSummary(true)
  &lt;fieldset&gt;
      &lt;legend&gt;Location&lt;/legend&gt;
      &lt;div class="editor-label"&gt;
          @Html.LabelFor(model =&gt; model.BuildingCode)
      &lt;/div&gt;
      &lt;div class="editor-field"&gt;
          @Html.DropDownListFor(model =&gt; model.BuildingCode, new SelectList(Model.Buildings, "BuildingCode", "BuildingName", "1091"), "-- Select a Building --", new { data_bind = "value:BuildingCode"})
          @Html.ValidationMessageFor(model =&gt; model.BuildingCode)
      &lt;/div&gt;
      &lt;div class="editor-label"&gt;
          @Html.LabelFor(model =&gt; model.Room)
      &lt;/div&gt;
      &lt;div class="editor-field"&gt;
          @Html.TextBoxFor(model =&gt; model.Room, new { @class = "inline width-7", data_bind="value:room"})
          @Html.ValidationMessageFor(model =&gt; model.Room)
      &lt;/div&gt;
  &lt;/fieldset&gt;
  &lt;fieldset&gt;
      &lt;legend&gt;Identifiers&lt;/legend&gt;
      &lt;p&gt;Designate any unique properties for identifying this autoclave.&lt;/p&gt;
      &lt;div class="editor-field"&gt;
          Add Identifier
          @Html.DropDownList("identifiers-drop-down", new SelectList(Model.IdentifierTypes, "Id", "Name"), new { data_bind = "value:selectedIdentifierTypeValue"})
          @Html.TextBox("identifier-value", null, new { @class = "inline width-15", data_bind = "value:identifierToAdd, valueUpdate: 'afterkeydown'" })
          &lt;button type="submit" class="add-button" data-bind="enable: identifierToAdd().length &gt; 0, click: addIdentifier"&gt;Add&lt;/button&gt;
      &lt;/div&gt;
  
      &lt;div class="editor-field"&gt;
          &lt;table&gt;
              &lt;thead&gt;
                  &lt;tr&gt;
                      &lt;th&gt;Identifier Type&lt;/th&gt;
                      &lt;th&gt;Value&lt;/th&gt;
                      &lt;th&gt;&lt;/th&gt;
                  &lt;/tr&gt;
              &lt;/thead&gt;
              &lt;!-- ko if: identifiers().length &gt; 0 --&gt;
              &lt;tbody data-bind="foreach: identifiers"&gt;
  
                  &lt;tr&gt;
                      &lt;td&gt;
                          &lt;select data-bind="options: $root.identiferTypes, 
                          optionsText: 'Name', optionsValue: 'Id', value: Key"&gt;
                          &lt;/select&gt;
                      &lt;/td&gt;
                      &lt;td&gt;&lt;input type="text" data-bind="value: Value"/&gt;&lt;/td&gt;
                      &lt;td&gt;&lt;a href="#" class="ui-icon ui-icon-closethick" data-bind="click: $root.removeIdentifier"&gt;Remove&lt;/a&gt;&lt;/td&gt;
                  &lt;/tr&gt;
  
  
              &lt;/tbody&gt;
              &lt;!-- /ko --&gt;
              &lt;!-- ko if: identifiers().length &lt; 1 --&gt;
              &lt;tbody&gt;
                  &lt;tr&gt;    
                      &lt;td colspan="3"&gt; No identifiers added.&lt;/td&gt;
                  &lt;/tr&gt;
              &lt;/tbody&gt;
              &lt;!-- /ko --&gt;
          &lt;/table&gt;
          @Html.HiddenFor(x =&gt; x.IdentifiersCount, new { data_bind = "value:identifiers().length" })&lt;span data-bind="text:identifiers"&gt;&lt;/span&gt;
          @Html.ValidationMessageFor(x =&gt; x.IdentifiersCount)
      &lt;/div&gt;    
  &lt;/fieldset&gt;
  &lt;p&gt;
      &lt;input type="submit" value="Create" /&gt;
  &lt;/p&gt;
  }
  </code></pre>