Mam listę obiektów w moim modelu, jak mogę zrobić dla niej formularz? Chcę mieć pole wyboru i pole wprowadzania liczb, aby dodawać obiekty i móc dodawać kolejne przed wysłaniem formularza.

Gdyby to było tylko public Cargo cargo, zrobiłbym po prostu pole wyboru, aby wybrać rodzaj ładunku i pole do wprowadzenia kwoty i to wszystko. Ale to lista, więc chcę dodać tyle ładunku, ile chcę, a następnie opublikować formularz. Mam już pola do wprowadzania adresu (takie jak miasto, ulica itp.) W moim formularzu, ale utknąłem z tą listą.

Model zamówienia (model formularza):

public class Order
{
    public int Id { get; set; }
    public Address PickUpAddress { get; set; }
    public Address DropOffAddress { get; set; }
    [...]
    public List<Cargo> Cargo { get; set; }
}

Model ładunku:

public class Cargo
{
    public int Id { get; set; }
    public int Amount { get; set; }
    public CargoType CargoType { get; set; }
}
4
kkamil4sz 20 listopad 2019, 19:16
1
Tutaj uważam, że narzędzia innych firm, takie jak kendo ui, są nieocenione. Możesz tworzyć własne, korzystając z niektórych jquery, takich jak tutaj i tutaj.
 – 
Steve Greene
20 listopad 2019, 21:11

2 odpowiedzi

To rozwiąże problem, jeśli użyjesz więcej niż jednego powiązanego modelu na stronach Widok i podasz parametr listy w akcjach. Przykład; Widok;

<input type="text" name="name" id="name1" />
<input type="text" name="name" id="name2" />

Publiczny post dotyczący wyników akcji (ciąg [] nazwa)

0
azorlua 20 listopad 2019, 19:37
Ale nie wiem, ile <input/> potrzebuję, ponieważ zależy to od tego, ile użytkownik chce dodać.
 – 
kkamil4sz
20 listopad 2019, 20:00

Moje rozwiązanie

  1. Funkcję tę zaimplementowałem ręcznie bez kodu JS.
  2. Kod jest bardzo prosty. Możesz odwołać się do mojego kodu tutaj bezpośrednio.

Proces rozwiązywania

  1. Musimy wstawić tabelę zamówień, zanim będziemy mogli wstawić tabelę cargo. W przeciwnym razie nie uda nam się połączyć obu tabel.
  2. Potrzebujemy tych trzech modeli formularzy. Używamy pola cargocount, aby połączyć dwie strony zamówienia ze stroną cargo.
    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>();
    }
  1. Tworząc stronę zamówienia, musimy podać dane cargocount. Po przesłaniu strony zamówienia zapiszemy istniejące dane w tabeli zamówień, przejdziemy do strony cargo i wygenerujemy tagi wejściowe cargocount.
  2. Następnie prześlij formularz listy. Prześlij kod strony
        <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>

Kod przetwarzania danych w tle

        [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));
        }

Korzystanie z implementacji JS

  1. Potrzebujemy tych modeli formularzy.
    public class OrderAndCargoViewModel
    {
        public int OrderId { get; set; }
        public string PickUpAddress { get; set; }
        public string DropOffAddress { get; set; }
        public List<CargoViewModel> Cargos { get; set; }
    }
  1. Następnie prześlij formularz tabeli. Prześlij kod strony.
        <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()">

Kodu JS.

@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>
}

Kod kontrolera.

        [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));
        }
  1. Kliknij tutaj, aby wyświetlić kody źródłowe.

Strona odniesienia

  1. Informacje o '@'.
  2. Operacja JS.
1
ChaosFish 23 listopad 2019, 18:30
Cóż, wpadłem na pomysł, aby użytkownik określił wcześniej, ile ładunku ma zamiar dodać, ale myślę, że to trochę surowe. Chciałbym mieć pola wejściowe tylko dla jednego elementu na raz, a następnie pokazać inne pole, jeśli użytkownik naciśnie "dodaj kolejny" lub coś w tym stylu.
 – 
kkamil4sz
23 listopad 2019, 03:04
To musi być zaimplementowane przez JS. Daj mi trochę czasu. Mogę wdrożyć tę operację.@kkamil4sz
 – 
ChaosFish
23 listopad 2019, 08:00