EDIT:
I've a table with which I dynamically add / remove rows in a table using jQuery in MVC4. When I do POST the rows are not stored completely,
Example: I add 10 rows to the table and delete the 7th, theoretically there are only 9 rows left. The problem I have is that regardless of the row that I delete, only the rows before that (1 to 6) are saved and it is supposed to save all the rows that are in the table (1 to 9).
I was looking for debbug and noticed that the Input ID is not updated, I got the following results.
<input name="[0].HW_SQ">
<input name="[1].HW_SQ">
<input name="[2].HW_SQ">
<input name="[3].HW_SQ">
<input name="[4].HW_SQ">
<input name="[5].HW_SQ">
<input name="[7].HW_SQ">
<input name="[8].HW_SQ">
<input name="[9].HW_SQ">
As you can see, the position I selected was eliminated but the input ID was not updated, so I need it to be as follows.
<input name="[0].HW_SQ">
<input name="[1].HW_SQ">
<input name="[2].HW_SQ">
<input name="[3].HW_SQ">
<input name="[4].HW_SQ">
<input name="[5].HW_SQ">
<input name="[6].HW_SQ">
<input name="[7].HW_SQ">
<input name="[8].HW_SQ">
Is there any way to update the id values correctly?
Here's my code:
<div><a href="#" id="addNew"><input type="button" value="Add"/></a></div>
<table id="dataTable">
<thead>
<tr>
<th>#</th>
<th>SEQ</th>
<th>Brand</th>
<th>Serial</th>
<th>Model</th>
<th>Year Model</th>
<th>Status</th>
<th>Place</th>
<th>Location</th>
<th>FA Tag</th>
<th>Security Tag</th>
<th>Date Acquisition</th>
<th>Price</th>
<th>Description</th>
</tr>
</thead>
<tbody id="mytbody">
@if (Model != null && Model.Count > 0)
{
int j = 0;
int index = 1;
foreach (var p in Model)
{
<tr>
<td style="text-align:center;">@index</td>
<td>@Html.TextBoxFor(a => a[j].HW_SQ)</td>
<td>@Html.TextBoxFor(a => a[j].HW_BRAND)</td>
<td>@Html.TextBoxFor(a => a[j].HW_SERIAL)</td>
<td>@Html.TextBoxFor(a => a[j].HW_MODEL)</td>
<td>@Html.TextBoxFor(a => a[j].HW_YEAR)</td>
<td>@Html.TextBoxFor(a => a[j].HW_STATUS)</td>
<td>@Html.TextBoxFor(a => a[j].HW_PLACE)</td>
<td>@Html.TextBoxFor(a => a[j].HW_LOCATION)</td>
<td>@Html.TextBoxFor(a => a[j].HW_FA_TAG)</td>
<td>@Html.TextBoxFor(a => a[j].HW_SECURITY_TAG)</td>
<td>@Html.TextBoxFor(a => a[j].HW_DATE_ITEM_ADQUISITION)</td>
<td>@Html.TextBoxFor(a => a[j].HW_PRICE)</td>
<td>@Html.TextBoxFor(a => a[j].HW_DESCRIPTION)</td>
<td>
<a href="#" id="remove" class="remove">Remove</a>
</td>
</tr>
index = 1;
}
}
</tbody>
</table>
<center><input type="submit" value="Save" id="sendinv"/></center>
jQuery Code:
$(document).ready(function () {
function numberRows($t) {
$t.find("tr").each(function (i, el) {
$(el).find("td").eq(0).html((i 1));
});
}
//- Start Table Add, delete buttons -
$("#addNew").click(function (e) {
e.preventDefault();
var last = $('#dataTable>tbody>tr:last');
if (last.length > 0) {
var name = last.children().find('input,select')[0].name;
var index = Number(name.replace(/[^0-9]/gi, '')) 1;
var tr = ('<tr>' last.html().replace(/[0-9] __/gi, index '__') '</tr>').replace(/\[[0-9] \] [.]/gi, '[' index '].');
numberRows($('#dataTable tbody').append(tr));
}
});
$(document).on('click', '#remove', function (e) {
e.preventDefault();
if ($('#dataTable>tbody>tr').length > 1) {
//$(this).parent().parent().remove();
$(this).closest('tr').remove();
numberRows($('#dataTable tbody'));
return false;
}
else {
//$(this).parent().parent().show();
alert('Form must have at least one row')
numberRows($('#dataTable tbody'));
}
});
//- End Table Add, delete buttons -
});
CodePudding user response:
The core of the issue here is that ASP.NET MVC's model binding stops building a collection when it finds a gap in the numbering. So the client is successfully POSTing the values to the server, but the server-side framework is ignoring them so they're lost before they reach the controller action method.
A solution is going to depend on what your server-side code is expecting and how it uses the data. Whether that code knows how to identify and handle the missing records and how you're updating the backing data. But currently that's not in the scope of the question and what you're specifically asking is how to re-number the values client-side, so let's focus on that.
You already have and call a function to "re-number rows" after deleting an entry:
function numberRows($t) {
$t.find("tr").each(function (i, el) {
$(el).find("td").eq(0).html((i 1));
});
}
It just doesn't re-number anything significant. All it's doing is showing a number to the user, not re-numbering any indexes sent to the server. But you can use the same function to do exactly that. Perhaps something like this:
function numberRows($t) {
$t.find("tr").each(function (i, el) {
$(el).find("td").eq(0).html((i 1));
$(el).find("td").eq(1).find("input").prop("name", "[" i "].HW_SQ");
});
}
The new line of code is similar to the previous one in that it starts at the "current row", finds a <td>
cell (this time the second cell, not the first one), and modifies something in that cell. This time it finds an <input>
in the cell and sets its name
attribute to a value based on the i
index. So the resulting values should be "[0].HW_SQ", "[1].HW_SQ", "[2].HW_SQ", etc.
You can add more lines to that function using this same approach to re-number the rest of the inputs. At that point it should then be up to your server-side code to know how to interpret the newly-numbered records and sync back to the data as needed.
As an aside, your HTML markup is currently invalid which could lead to more bugs in the future. Specifically, this element has an id
that gets repeated multiple times:
<a href="#" id="remove" class="remove">Remove</a>
Fortunately the element already has a class
attribute that you can use. So remove the id
attribute entirely and use the class
to select the element in your JavaScript:
$(document).on('click', '.remove', function (e) {
//...
});