Reputation: 741
I'm working on converting several paper forms into digital format and have been working on a scratch app to demonstrate some of the functionality I want to have in these. Right now I'm working on a form that will require several tables that all function the same.
Essentially the user can enter n
numbers of locations, users, etc. to their appropriate tables on the page. Here's what I've got so far.
Model classes
public class TableDemo
{
public List<Location> Locations { get; set; }
public List<User> Users { get; set; }
public TableDemo()
{
Locations = new List<Location>();
Locations.Add(new Location());
Users = new List<User>();
Users.Add(new User());
}
}
public class Location
{
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
}
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
}
Controller
public IActionResult Index()
{
TableDemo model = new TableDemo();
return View(model);
}
View:
@model TableDemo
@{
ViewData["Title"] = "Table Test";
}
@section Scripts{
<script type="text/javascript">
function addLocation() {
var locTab = $('#locationsTable');
var html = "<tr>"+
"<td><input type='text'/></td>"+
"<td><input type='text'/></td>"+
"<td><input type='text'/></td>"+
"<td><input type='text'/></td>"+
"</tr>"
locTab.append(html);
};
</script>
}
<h2>Table Example</h2>
<form>
<div class="form-group">
<div class="form-row">
<table id="locationsTable" class="table table-bordered">
<thead>
<tr>
<th>Street</th>
<th>City</th>
<th>State</th>
<th>Zip</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Locations.Count(); i++)
{
<tr>
<td><input type="text" asp-for="@Model.Locations[i].Street" /></td>
<td><input type="text" asp-for="@Model.Locations[i].City" /></td>
<td><input type="text" asp-for="@Model.Locations[i].State" /></td>
<td><input type="text" asp-for="@Model.Locations[i].Zip" /></td>
</tr>
}
</tbody>
</table>
</div>
<button type="button" onclick="addLocation()">Add</button>
<button type="button" onclick="removeLocation()">Remove</button>
</div>
</form>
From here I need to be able to click add as many times as I want and have a row added to the table that'll be bound to the next item in the list. There will be other fields and tables on the page and the entire form will be checked for validation errors and submitted once all fields are filled out - including several tables like the one above each bound to a different list of items per table. Once all the rows are added and values entered, once the entire form is submitted the List of (in this case) Locations will have as many items as the user entered.
I've tried the following:
Adding a method to the TableDemo
class that creates a StringBuilder with the rows including the tag helper for the Model.Locations[i].Property
and inside the script I had var html = @Model.AddLocation();
but the HTML generated from this was gibberish and produced errors.
I also tried adding a local counter to the script like so
<script type="text/javascript">
@{
var counter = 1;
}
function addLocation() {
var locTab = $('#locationsTable');
var html = "<tr><td><input type='text' asp-for='@Model.Locations[counter].Street' /></td>"+
"<td><input type='text' asp-for='@Model.Locations[counter].City' /></td>"+
"<td><input type='text' asp-for='@Model.Locations[counter].State' /></td>"+
"<td><input type='text' asp-for='@Model.Locations[counter].Zip' /></td>"+
"</tr>"
locTab.append(html);
@counter++;
};
</script>
But this introduced a new problem in that the list in the model didn't currently have an item with the index of 1.
How can I achieve the desired result with .NET Core MVC?
Upvotes: 0
Views: 93
Reputation: 18169
Taghelper(asp-for) cannot be distinguished in jquery.If you want to bind the new data,you can add name liking name=Locations[" + counter + "].street
This is my view:
<div>
<form method="post">
<div class="form-group">
<div class="form-row">
<table id="locationsTable" class="table table-bordered">
<thead>
<tr>
<th>Street</th>
<th>City</th>
<th>State</th>
<th>Zip</th>
</tr>
</thead>
<tbody>
@for (int i = 0; i < Model.Locations.Count(); i++)
{
<tr>
<td><input type="text" asp-for="@Model.Locations[i].Street" /></td>
<td><input type="text" asp-for="@Model.Locations[i].City" /></td>
<td><input type="text" asp-for="@Model.Locations[i].State" /></td>
<td><input type="text" asp-for="@Model.Locations[i].Zip" /></td>
</tr>
}
</tbody>
</table>
</div>
<button type="button" onclick="addLocation()">Add</button>
<button type="button" onclick="removeLocation()">Remove</button>
<button >submit</button>
</div>
</form>
</div>
@section Scripts{
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script type="text/javascript">
var counter = @Model.Locations.Count;
function addLocation() {
var locTab = $('#locationsTable');
var html = "<tr><td><input type='text' name=Locations[" + counter + "].street id=Locations_" + counter + "__street /></td>" +
"<td><input type='text' name=Locations[" + counter + "].city id=Locations_" + counter + "__city /></td>" +
"<td><input type='text' name=Locations[" + counter + "].state id=Locations_" + counter + "__state /></td>" +
"<td><input type='text' name=Locations[" + counter + "].zip id=Locations_" + counter + "__zip /></td>" +
"</tr>";
locTab.append(html);
counter++;
};
</script>
}
This is my controller:
[HttpPost]
public IActionResult Index(TableDemo tableDemo)
{
TableDemo model = tableDemo;
return View(model);
}
This is the result:
Upvotes: 1