Dynamiczne generowanie kolejnych rekordów tablicy

0

Cześć,

Korzystam z Razor Pages w swoim projekcie oraz z helperów do tworzenia dropdowna. Koncepcja jest taka: użytkownik ma widoczny rekord tabeli z pierwszą kolumną z uzupełnioną listą rozwijaną (dane pobrane z bazy danych) i drugą kolumną z inputem, do tego ma przycisk "Dodaj kolejny rekord", który ma mu dodawać następne rekordy do tablicy. Do tego momentu wszystko udało mi się osiągnąć, ale z nie do końca takim skutkiem jakiego oczekiwałem.

Chciałbym aby skrypt jQuery generował kolejny rekord wraz z odpowiednim "id" czy po prostu indeksem tablicy tak aby przy przekazaniu modelu do kontrolera nie pojawiło się kilka wartości o tym samym indeksie (a co za tym idzie - nadpisywałyby się) lub żeby wartości były gubione po drodze.

Problem leży w tym, że nie wiem** jak zdefiniować w skrypcie jQuery zmienną "markup"** tak aby dynamicznie ustawiała indeks na długość tablicy. W tej chwili mam do niej przypisanego helper z kodem html.

Kod HTML:

@page
@model MealApp.Pages.Meals.AddModel
@{
    <h1>Dodaj posiłek</h1>

    <form method="post" class="mt-3">
        <div class="form-group row">
            <label asp-for="Meal.MealName" class="col-sm-2 col-form-label">
            </label>
            <div class="col-sm-10">
                <input asp-for="Meal.MealName" class="form-control" placeholder="Nazwa posiłku">
            </div>
        </div>
        <div class="form-group row">
            <label asp-for="Meal.TypeOfMeal" class="col-sm-2 col-form-label">
            </label>
            <div class="col-sm-10">
                @Html.DropDownListFor(p => p.Meal.TypeOfMealId, new SelectList(Model.TypeOfMeals, "Id", "TypeName"), "--Wybierz typ posiłku--", new { @class = "form-control" })
            </div>
        </div>
        <div class="form-group row">
            <label asp-for="Meal.Description" class="col-sm-2 col-form-label">
            </label>
            <div class="col-sm-10">
                <input asp-for="Meal.Description" class="form-control" placeholder="Opis">
            </div>
        </div>
        <div id="myTable" class="datatable" data-hover="true" data-border-color="dark ">
            <table class="table datatable-table">
                <thead class="datatable-header">
                    <tr>
                        <th>Produkt</th>
                        <th>Ilość</th>
                    </tr>
                </thead>
                <tbody class="datatable-body">
                    @for (int i = 0; i < 10; i++)
                    {
                        <tr>
                            <td>
                                @Html.DropDownListFor(p => p.Meal.MealProducts[i].ProductId, new SelectList(Model.Products, "Id", "ProductName"), "--Wybierz produkt--", new { @class = "form-control" })
                            </td>
                            <td>
                                <input asp-for="Meal.MealProducts[i].Quantity" class="form-control" placeholder="Ilość" />
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        </div>
        @*<button type="button" id="add-row" class="btn btn-primary">Dodaj produkt</button>*@
        <div class="form-group row">
            <div class="col-sm-10">
                <button type="submit" class="btn btn-primary">Dodaj</button>
                <a asp-page="/Products/Index" class="btn btn-danger">Cancel</a>
            </div>
        </div>
    </form>
}

Skrypt jQuery:

<script type="text/javascript">
                $(document).ready(function () {
                    $("#add-row").click(function () {
                        markup = `<tr><td>@(@Html.DropDownListFor(p => p.Meal.MealProducts[1].ProductId, new SelectList(Model.Products, "Id", "ProductName"), "--Wybierz produkt--", new { @class = "form-control" }))</td><td><input asp-for="Meal.MealProducts[1].Quantity" class="form-control" placeholder="Ilość" /></td></tr>`
                        tableBody = $("table tbody");
                        tableBody.append(markup);
                        i++;
                    });
                });
</script>

Wyrenderowany row tablicy HTML:

<tbody class="datatable-body">
                        <tr>
                            <td>
                                <select class="form-control" id="Meal_MealProducts_0__ProductId" name="Meal.MealProducts[0].ProductId"><option value="">--Wybierz produkt--</option>
<option value="4">Mleko 1,5%</option>
<option value="5">Płatki owsiane</option>
<option value="6">Płatki kukurydziane</option>
<option value="7">Truskawki</option>
<option value="8">Ser chudy</option>
</select>
                            </td>
                            <td>
                                <input class="form-control" placeholder="Ilość" type="number" id="Meal_MealProducts_0__Quantity" name="Meal.MealProducts[0].Quantity" value="">
                            </td>
                        </tr>
0

Problem leży w tym, że nie wiem jak zdefiniować w skrypcie jQuery zmienną "markup"

Myślę, że problem jest o wiele głębszy ...

Jesteś pewien, że Twój framework obsługuje składnię mechanizmu renderowania widoku nawet jeśli ta użyta jest jako wartość zmiennej?

markup = `<tr><td>@(@Html.DropDownListFor(p => p.Meal.MealProducts[1].ProductId, new SelectList(Model.Products, "Id", "ProductName"), "--Wybierz produkt--", new { @class = "form-control" }))</td><td><input asp-for="Meal.MealProducts[1].Quantity" class="form-control" placeholder="Ilość" /></td></tr>

Osobiście wątpię. Raczej musisz wyrenderować widok za pomocą odpowiedniej funkcji "render" i dopiero dokleić go do tabeli.
Zobacz co masz faktycznie doklejone do tej tabeli po wykonaniu tej funkcji. Według mnie będzie po prostu doklejony string ze zmiennej markup tak jak leci.

0

@katakrowa:
Zaskoczę Cię może. Renderuje się poprawnie, ale dlatego że mam zahardkodowane "MealProducts[1]", więc drugi wiersz doda się bez problemu. Zresztą, kolejne także. Z tym, że z tym samym indeksem. Ja natomiast chcę to moje "[1]" mieć "dynamiczne" np. na podstawie długości tabeli, tak aby do modelu trafiała lista elementów. I o tyle o ile dla tej części, która jes stringiem (Quantity) mogę zrobić sobie zmienną i później się do niej odwołać, o tyle do kodu, który jest pomiędzy @() nie mogę.

Poniżej to co wyrenderowała mi funkcja:

<tr><td><select class="form-control" id="Meal_MealProducts_1__ProductId" name="Meal.MealProducts[1].ProductId"><option value="">--Wybierz produkt--</option>
<option value="4">Mleko 1,5%</option>
<option value="5">Płatki owsiane</option>
<option value="6">Płatki kukurydziane</option>
<option value="7">Truskawki</option>
<option value="8">Ser chudy</option>
</select></td><td><input asp-for="Meal.MealProducts[1].Quantity" class="form-control" placeholder="Ilość"></td></tr>
0

Jest ktoś w stanie mi pomóc? Potrzebuję po prostu w jquery dodać odpowiednią zmianną w miejsce indeksu [1], tylko nie wiem jak to wykonać. Wziąłem sobie długość tablicy:

var tableLength = $("#productsTable tr").length;

ale używając tagów helpera w jquery nie mogę go przerwać, tzn wpisać zmiennej z jquery w środku tego tagu...

`<tr><td>@(@Html.DropDownListFor(p => p.Meal.MealProducts[1].ProductId, new SelectList(Model.Products, "Id", "ProductName"), "--Wybierz produkt--", new { @class = "form-control" }))</td><td><input asp-for="Meal.MealProducts[1].Quantity" class="form-control" placeholder="Ilość" /></td></tr>
1

w 2021 korzystasz z jquery?

0

Bym to zrobiła tak:

var tabela = document.querySelector(".datatable-table");
var wierszy = tabela.rows.length;
var indeks = wierszy - 1;
var tr = tabela.insertRow(wierszy); /* dodaj: tr */
var td, input;

  td = tr.insertCell(0); /* dodaj: td */
    td.textContent = '@(@Html.DropDownListFor(p => p.Meal.MealProducts['+indeks+'].ProductId, new SelectList(Model.Products, "Id", "ProductName"), "--Wybierz produkt--", new { @class = "form-control" }))';

  td = tr.insertCell(1); /* dodaj: td */
    input = document.createElement("INPUT");
    input.setAttribute("asp-for", "Meal.MealProducts["+indeks+"].Quantity");
    input.setAttribute("class", "form-control");
    input.setAttribute("placeholder", "Ilość");
  td.appendChild(input);

A później potrzebujesz jeszcze odpalić parser Razor Pages, który zamieni ci to wyrażenie "@(@Ht..." na faktycznego selekta.

0

EDIT:
Poradziłem sobie, zapomniałem o inputach :)))

Ogólnie to zmieniłem trochę koncepcję, bo wydaje mi się że poprzednia była nieco przekombinowana. Teraz po stronie użytkownika będzie wyglądać to tak, że tabela będzie pusta, a tuż nad nią będzie miał dwa inputy do uzupełnienia (produkt oraz ilość). Następnie po kliknięciu przycisku "Dodaj produkt" dane wpadają do tabeli jako kolejny row. Zbudowałem markup, gdzie name="Meal.MealProducts[' + indeks + '].ProductId", ale nie wiem dlaczego nie jest on wysyłany do controllera. Pozostałe właściwości są przekazywane, ale używam dla nich helpera asp-for. Takiego helpera nie mogę niestety użyć w skrypcie jquery.

Poniżej cały skrypt:

<script type="text/javascript">
    $(document).ready(function () {
        $("#add-row").click(function () {
            var tabela = $('#productsTable tr');
            var wierszy = tabela.length;
            var indeks = wierszy - 1;
            var produkt = $('#product option:selected').text();
            var produktId = $('#product option:selected').val();
            var ilosc = $('#quantity').val();
            var markup = '<tr><td><label value='+produktId+' name="Meal.MealProducts[' + indeks + '].ProductId" class="col-form-label">'+produkt+'</td><td><label id="Meal_MealProducts_' + indeks + '__Quantity" name="Meal.MealProducts[' + indeks + '].Quantity">'+ilosc+'</td></tr>';
            $('table tbody').append(markup);
        });
    });
</script>

Tutaj html:

<h1>Dodaj posiłek</h1>

<form method="post" class="mt-3">
    <div class="form-group row">
        <label asp-for="Meal.MealName" class="col-sm-2 col-form-label">
            Nazwa
        </label>
        <div class="col-sm-4">
            <input asp-for="Meal.MealName" class="form-control" placeholder="Wprowadź nazwę">
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Meal.TypeOfMeal" class="col-sm-2 col-form-label">
            Typ
        </label>
        <div class="col-sm-4">
            @Html.DropDownListFor(p => p.Meal.TypeOfMealId, new SelectList(Model.TypeOfMeals, "Id", "TypeName"), "--Wybierz typ posiłku--", new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group row">
        <label asp-for="Meal.Description" class="col-sm-2 col-form-label">
            Opis
        </label>
        <div class="col-sm-6">
            <textarea rows="5" asp-for="Meal.Description" class="form-control" placeholder="Podaj przepis na posiłek"></textarea>
        </div>
    </div>
    <hr class="dashed">
    <div class="form-group row">
        <div class="form-group col">
            <label class="col-sm-12 col-form-label">
                Nazwa produktu
            </label>
            <div class="col-sm-12">
                <select id="product" class="form-control">
                    <option value="0">-- Wybierz produkt --</option>
                    @foreach (var product in Model.Products)
                    {
                        <option value="@product.Id">@product.ProductName</option>
                    }
                </select>
            </div>
        </div>
        <div class="form-group col">
            <label class="col-sm-12 col-form-label">
                Ilość (w gramach)
            </label>
            <div class="col-sm-12">
                <input id="quantity" class="form-control" placeholder="Ilość" />
            </div>
        </div>
        <div class="form-group col">
            <label class="col-sm-12 col-form-label">
            </label>
            <div class="col-sm-12">
                <input type="button" value="Dodaj produkt " id="add-row" class="btn btn-primary" />
            </div>
        </div>
    </div>
    <div id="productsTable" class="datatable" data-hover="true" data-border-color="dark ">
        <table class="table datatable-table">
            <thead class="datatable-header">
                <tr>
                    <th>Produkt</th>
                    <th>Ilość</th>
                </tr>
            </thead>
            <tbody class="datatable-body">
            </tbody>
        </table>
    </div>

    <div class="form-group row">
        <div class="col-sm-10">
            <button type="submit" class="btn btn-primary">Dodaj</button>
            <a asp-page="/Products/Index" class="btn btn-danger">Wróć</a>
        </div>
    </div>
</form>

1 użytkowników online, w tym zalogowanych: 0, gości: 1