Cześć,

Działam w projekcie Razor Pages i mam pytanie.

Może najpierw co chciałbym uzyskać - chciałbym aby po kliknięciu w button o id="generate" wyrenderowała się w divie generatedList tabela z listą zakupów.

Mam to w tej chwili rozwiązane w ten sposób. Na widoku głównym użytkownik klika w przycisk i wykonuje się AJAX:

@page
@model MealApp.Pages.Diets.ShoppingListModel
@{
}
<h1>Generuj listę zakupów</h1>

<form method="post" asp-page-handler="generatepartial" class="mt-3">
    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    <div class="form-group row">
        <div class="form-group col">
            <label class="col-sm-12 col-form-label">
                Nazwa dnia
            </label>
            <div class="col-sm-12">
                <select id="daySelect" class="form-control">
                    <option id="0" value="0">-- Wybierz dzień --</option>
                    @foreach (var day in Model.DietDTO.Days)
                    {
                        <option id="@day.Id" value="@day.Id">@day.Name</option>
                    }
                </select>
            </div>
        </div>
        <div class="form-group col">
            <label class="col-sm-12 col-form-label">
                Ilość dni
            </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 do listy " id="add-row" class="btn btn-primary" />
            </div>
        </div>
    </div>
    <div id="dayTable" class="datatable" data-hover="true" data-border-color="dark ">
        <table class="table datatable-table">
            <thead class="datatable-header">
                <tr id="rowHeader">
                    <th>Dzień</th>
                    <th>Ilość</th>
                    <th></th>
                </tr>
            </thead>
            <tbody class="datatable-body">
            </tbody>
        </table>
    </div>
    <div id="generatedList"></div>
    <div class="form-group row">
        <div class="col-sm-10">

            <a href='javascript:history.go(-1)' class="btn btn-danger">Wróć do przeglądu diety</a>
        </div>
    </div>
    <button id="generate" type="submit" class="btn btn-primary">Generuj listę zakupów</button>
</form>


@section Scripts {
    <partial name="~/Pages/Shared/_ValidationScriptsPartial.cshtml" />
}
<script type="text/javascript">
    $(document).ready(function () {
        $("#add-row").click(function () {
            var tabela = $('#dayTable tr');
            var wierszy = tabela.length;
            var indeks = wierszy - 1;
            var day = $('#daySelect option:selected').text();
            var dayId = $('#daySelect option:selected').val();
            var ilosc = $('#quantity').val();
            var markup = '<tr onclick="GetIndex(this)" class="daysRows"><td><input type="hidden" class="days" id="DayId_' + indeks + '" value=' + dayId + ' name="Days[' + indeks + '].DayId"><label class="col-form-label">' + day + '</label></td><td><input class="quantity" type="hidden" value=' + ilosc + ' id="quantity' + indeks + '"__Quantity" name="Days[' + indeks + '].Quantity"><label class="col-form-label">' + ilosc + '</label></td><td><button id=' + indeks + ' type="button" class="btn btn-danger delete-row"><i class="fa fa-close"></button></td></tr>';
            $('table tbody').append(markup);
            SetNull();
            HideShowSelected(dayId, false);
        });
    });

    $(function () {
        $('#generate').on('click', function () {
            $('#generatedList').load('/Diets/ShoppingList?handler=generatepartial');
        });
    });

    $(document).on("click", ".delete-row", function (e) {
        e.preventDefault();
        var dayId = $('#DayId_' + index).attr("value");
        var parentDiv = $(this).parent().parent();
        $(parentDiv).remove();
        var rows = $(".daysRows");
        for (var tr = 0; tr < rows.length; tr++) {
            var oneRow = rows[tr];
            var newProduct = 'Days[' + tr + '].DayId';
            var newIdProduct = 'DayId_' + tr;
            $(oneRow).find('.days').attr({ "name": newProduct, "id": newIdProduct });
            var newQuantity = 'Days[' + tr + '].Quantity';
            $(oneRow).find('.quantity').attr("name", newQuantity);
        };
        HideShowSelected(dayId, true);
        return false;
    });

    function GetIndex(x) {
        index = x.rowIndex - 1;
    }

    function HideShowSelected(dayId, hideShow) {
        if (hideShow) {
            $("#daySelect").children('#' + dayId).show();
        }
        else {
            $("#daySelect").children('#' + dayId).hide();
        }
    };

    function SetNull() {
        $("#daySelect").val('0');
        document.getElementById("quantity").value = "";
    }
</script>

Akcja, która się wykonuje to OnPostGeneratePartial(), ale pierwszy mój niepokój budzi to, że zanim zostaje wywołana, wpierw wykonuje się OnGet(int dietId) gdzie dostaję pierwszy błąd na widoku, mianowicie Object reference not set to an instance of an object.. Moim zdaniem tej akcji ajax nie powinien dotykać.

  1. strona razor ShoppingListModel
public class ShoppingListModel : PageModel
    {
        private readonly IDietRepository dietRepository;
        private readonly IDayDietRepository dayDietRepository;
        private readonly IShoppingListRepository shoppingListRepository;
        private readonly IMapper mapper;

        public ShoppingListModel(
            IDietRepository dietRepository,
            IDayDietRepository dayDietRepository,
            IShoppingListRepository shoppingListRepository,
            IMapper mapper)
        {
            this.dietRepository = dietRepository;
            this.dayDietRepository = dayDietRepository;
            this.shoppingListRepository = shoppingListRepository;
            this.mapper = mapper;
        }
        public DietDTO DietDTO { get; set; }
        [BindProperty]
        public List<ShoppingDayDTO> Days { get; set; }
        [BindProperty]
        public List<ShoppingListDTO> ShoppingList { get; set; }

        public IActionResult OnGet(int dietId)
        {
            var diet = dietRepository.GetDiet(dietId);
            DietDTO = mapper.Map<DietDTO>(diet);
            return Page();
        }

        public async Task<IActionResult> OnPostGeneratePartial()
        {
            var dayIds = new List<int>();
            foreach (var day in Days)
            {
                dayIds.Add(day.DayId);
            }
            ShoppingList = shoppingListRepository.GetShoppingList(Days);
            //GenerateXLSX(shoppingList);
            return Partial("_ShoppingListTablePartial", ShoppingList);
        }
}

W końcu gdy wykonuje już się odpowiednia metoda, która zwraca Partial("_ShoppingListTablePartial") tutaj także dostaję Object reference not set to an instance of an object. mimo iż zbindowane property ma wartość (mówię tu o ShoppingList).

  1. PartialView:
@page "{handler?}"
@using MealApp.Models.Models
@model List<ShoppingListDTO>
@{

}

<div id="shoppingList" class="datatable" data-hover="true" data-border-color="dark ">
    <table class="table datatable-table">
        <thead class="datatable-header">
            <tr id="rowHeader">
                <th>Kategoria</th>
                <th>Produkt</th>
                <th>Ilość</th>
            </tr>
        </thead>
        <tbody class="datatable-body">
            @if (Model.Count > 0)
            {
                @foreach (var item in Model)
                {
                    <tr>
                        <td>@item.Category</td>
                        <td></td>
                        <td></td>
                    </tr>
                    @foreach (var product in item.Products)
                    {
                        <tr>
                            <td></td>
                            <td>@product.Product</td>
                            <td>@product.Quantity</td>
                        </tr>
                    }
                }
            }

        </tbody>
    </table>
</div>
```html