Jquery script delete all items in form’s collection

I have a table:

<% using(Html.BeginForm("View2","Order"))
{  %>  
<table id="Products" class="Products">
    <tr>
        <th>ProductId</th>
        <th>Productname</th>
        <th>Quantity</th>
        <th>UnitPrice</th>
    </tr>
    <% for(int i=0; i < Model.NorthOrderDetails.Count; i++)
       {                            %>
              <tr>
        <td><%: Html.Label(Model.NorthOrderDetails[i].ProductID.ToString()) %></td>
        <td><%: Html.Label(Model.NorthOrderDetails[i].ProductName) %> </td>
        <td><%: Html.TextBoxFor(m => m.NorthOrderDetails[i].Quantity) %></td>
        <td><%: Html.TextBoxFor(m => m.NorthOrderDetails[i].UnitPrice) %></td>
          <td><button type="button" class="delete" data-id="<%:Model.NorthOrderDetails[i].ProductID %>">Delete</button><td> 
    <td><input type="hidden" name="<%:Model.NorthOrderDetails[i].ProductName %>" value="<%:i %>" /><td>
 <tr>
    <% } %>

</table>
<input type="submit" name="button" value="Add" /> 
<input type="submit" name="button" value="Save" /> 
<% } %>

When I click the delete button I’m calling this script:

<script type="text/javascript">
          var url = '<%:Url.Action("Delete", "Order")%>';
          $('.delete').click(function () {
              var id = $(this).data('id'); // Get the product ID
              var row = $(this).closest('tr');// Get the table row
              $.post(url, { ID: id }, function () {
                  row.remove(); // remove the row from the table
                                });
          });

            </script>

And the script call this method in the Controller

[HttpPost]
public JsonResult Delete(int ID)
{
    NorthOrder forOrderDetail = (NorthOrder)Session["Order"];
    forOrderDetail.NorthOrderDetails.RemoveAll(z => z.ProductID == ID);
    Session["Order"] = forOrderDetail;

    return Json(null);
}

In the UI the row deletes correctly when I click on the submit button. But In the controller method the count of the collection equal null when I delete the first row, and it’s equals to 1 when I delete the last row
For example, table contains two rows when page loaded

public ActionResult View2(NorthOrder q,  string button)
{
}

Why?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

Because you are deleting some rows, but posting back the whole collection in the Save submit action, your indexers are either not starting a zero, or are non consecutive. In the case of deleting the 1st row, the posted values are

NorthOrderDetails[1].Quantity=SomeValue&NorthOrderDetails[1].UnitPrice=SomeOtherValue

There are no values with NorthOrderDetails[0]... so binding fails and the collection is empty.

By default, the DefaultModelBinder require collection indexers to start at zero and be non-consecutive. When you delete an item and remove its controls from the DOM, the collection cannot be bound correctly. To make this work you need to add an extra hidden input which the DefaultModelBinder uses to match up collection properties. Change the view code to

% for(int i=0; i < Model.NorthOrderDetails.Count; i++)
{%>
  <tr>
    <td><%: Html.DisplayFor(m => m.NorthOrderDetails[i].ProductID) %></td> // Remove the .ToString()
    <td><%: Html.DisplayFor(m => m.NorthOrderDetails[i].ProductName) %></td>
    <td>
      <input type="hidden" name="NorthOrderDetails.Index" value="<%: i %>" /> // add this 
      <%: Html.TextBoxFor(m => m.NorthOrderDetails[i].Quantity) %>
    </td>
    <td><%: Html.TextBoxFor(m => m.NorthOrderDetails[i].UnitPrice) %></td>
    <td><button type="button" class="delete" data-id="<%:Model.NorthOrderDetails[i].ProductID %>">Delete</button><td> 
    <td><input type="hidden" name="<%:Model.NorthOrderDetails[i].ProductName %>" value="<%:i %>" /><td>
  <tr>
<% } %>

Note: I have long forgotten aspx, but the razor code for the hidden input is <input type="hidden" name="NorthOrderDetails.Index" value="@i" /> so you may want to check my syntax.

Side notes:

  1. Your use of session seems inappropriate here. In the Delete
    method, you are removing the item. When your finally save the
    collection, you would need to get the original collection from the
    database and compare them to determine which items to delete in the
    database. Instead, you Delete() method should be calling the
    database to delete the item (refer my answer to your previous
    question
    )
  2. Your Add button should not be, a submit and posting to the
    View2() method.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x