Reputation: 531
I have a List of objects in my Model, how can I make a form for it? I want to have select box and number input box to add objects and be able to keep adding more before posting form.
If it was just public Cargo cargo
I would just make a select box to choose cargo type and input box for amount and that's it. But it's a list so I want to add as much cargo as I want and then post a form. I already have input fields for address (like city, street etc.) in my form but I'm stuck with this list.
Order model (Form model):
public class Order
{
public int Id { get; set; }
public Address PickUpAddress { get; set; }
public Address DropOffAddress { get; set; }
[...]
public List<Cargo> Cargo { get; set; }
}
Cargo model:
public class Cargo
{
public int Id { get; set; }
public int Amount { get; set; }
public CargoType CargoType { get; set; }
}
Upvotes: 5
Views: 6979
Reputation: 72
public class CargoViewModel
{
public int OrderId { get; set; }
public int Amount { get; set; }
public string CargoType { get; set; }
//Other use
public int CargoCount { get; set; }
public List<CargoViewModel> Cargos { get; set; }
}
public class OrderViewModel
{
public int OrderId { get; set; }
public string PickUpAddress { get; set; }
public string DropOffAddress { get; set; }
public int CargoCount { get; set; }
public List<CargoViewModel> Cargos { get; set; }
}
public class OrdersViewModel
{
public List<OrderViewModel> Orders { get; set; } = new List<OrderViewModel>();
}
<form asp-controller="Order" asp-action="CreateCargo" method="post">
@if (Model.CargoCount != 0)
{
for (int itemCount = 0; itemCount < Model.CargoCount; itemCount++)
{
<div class="row">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<div class="form-group" style="width:300px; height:auto; float:left; display:inline">
<label asp-for="@Model.Cargos[itemCount].Amount" class="control-label"></label>
<input asp-for="@Model.Cargos[itemCount].Amount" class="form-control" />
<span asp-validation-for="@Model.Cargos[itemCount].Amount" class="text-danger"></span>
</div>
<div class="form-group" style="width:300px; height:auto; float:left; display:inline">
<label asp-for="@Model.Cargos[itemCount].CargoType" class="control-label"></label>
<input asp-for="@Model.Cargos[itemCount].CargoType" class="form-control" />
<span asp-validation-for="@Model.Cargos[itemCount].CargoType" class="text-danger"></span>
</div>
</div>
</div>
}
}
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
Background data processing code
[HttpPost]
public async Task<IActionResult> CreateCargo(CargoViewModel model)
{
var orderId = await _context.Order.Select(o => o.OrderId).MaxAsync();
var cargos = model.Cargos;
foreach (var item in cargos)
{
var cargo = new Cargo
{
OrderId = orderId,
Amount = item.Amount,
CargoType = item.CargoType
};
await _context.AddAsync(cargo);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
public class OrderAndCargoViewModel
{
public int OrderId { get; set; }
public string PickUpAddress { get; set; }
public string DropOffAddress { get; set; }
public List<CargoViewModel> Cargos { get; set; }
}
<div style="float:right;">
<table id="tb">
<tr>
<th> <label class="control-label">ID</label></th>
<th> <label asp-for="@Model.Cargos.FirstOrDefault().Amount" class="control-label"></label> </th>
<th><label asp-for="@Model.Cargos.FirstOrDefault().CargoType" class="control-label"></label></th>
</tr>
@{
var countId = 0;
for (var itemCount = 0; itemCount < 3; itemCount++)
{
<tr id="trs">
<td>@(++countId)</td>
<td><input asp-for='@Model.Cargos[itemCount].Amount' class= 'form-control' /></td>
<td><input asp-for='@Model.Cargos[itemCount].CargoType' class='form-control' /></td>
</tr>
}
}
</table>
</div>
<input id="btnAdd" value="Add" type="button" class="btn btn-primary" onclick="btnAddClick()">
JS Code.
@section scripts{
<script src="~/js/jquery-3.4.1/jquery-3.4.1.js" type="text/javascript"></script>
<script src="~/js/jquery-3.4.1/jquery-ui-1.12.1.js" type="text/javascript"></script>
<script src="~/js/jquery-3.4.1/jquery.unobtrusive-ajax.js" type="text/javascript"></script>
<script>
var btnAddClick = function () {
var trLen = $("#tb tr[id='trs']").length;
var $lastTr = $("#tb tr[id='trs']").last();
var tr = "<tr id='trs'>";
tr += "<td>" + (trLen + 1) + "</td>";
tr += "<td><input class='form-control' type='number' data-val='true' data-val-required='The Amount field is required.' id='Cargos_"+trLen+"__Amount' name='Cargos["+trLen+"].Amount' value=''></td>";
tr += "<td><input class='form-control' type='text' id='Cargos_"+trLen+"__CargoType' name='Cargos["+trLen+"].CargoType' value=''>";
tr += "</tr>";
$(tr).insertAfter($lastTr);
}
</script>
}
Controller Code.
[HttpPost]
public async Task<IActionResult> CreateOrderAndCargo(OrderAndCargoViewModel model)
{
var order = new Order()
{
PickUpAddress = model.PickUpAddress,
DropOffAddress = model.DropOffAddress
};
await _context.AddAsync(order);
await _context.SaveChangesAsync();
var orderId = await _context.Order.Select(o => o.OrderId).MaxAsync();
var cargos = model.Cargos;
foreach (var item in cargos)
{
var cargo = new Cargo
{
OrderId = orderId,
Amount = item.Amount,
CargoType = item.CargoType
};
await _context.AddAsync(cargo);
await _context.SaveChangesAsync();
}
return RedirectToAction(nameof(Index));
}
Upvotes: 1
Reputation: 1
It will solve the problem if you use more than one related model in View pages and give a list parameter in actions.. An example; View;
<input type="text" name="name" id="name1" />
<input type="text" name="name" id="name2" />
Action public actionresult post(string [] name)
Upvotes: 0