Ошибка при попытке доступа ко второй странице разбитой на страницы таблицы - PullRequest
0 голосов
/ 15 мая 2018

У меня есть разбитая на страницы таблица в приложении ASP .Net Core MVC, где первая «страница» таблицы правильно отображает количество строк таблицы, как указано.Проблема заключается в том, что при нажатии кнопки «Далее» для отправки асинхронного вызова к действию контроллера для получения следующего набора строк сервер не может найти действие контроллера.

У меня естьследовал этому руководству и, как указано, для ссылок на страницы в представлении должен использоваться следующий код (измененный для использования в этом случае):

  @{ 
        var prevDisabled = !Model.PageList.HasPreviousPage ? "disabled" : "";
        var nextDisabled = !Model.PageList.HasNextPage ? "disabled" : "";
        }

    <a asp-action="GetResultList"
       asp-route-sortOrder="@ViewData["CurrentSort"]" 
       asp-route-page="@(Model.PageList.PageIndex - 1)"
       asp-route-currentFilter="@ViewData["CurrentFilter"]"
       class="btn btn-default @prevDisabled">
        Previous
    </a>
    <a asp-action="GetResultList"
       asp-route-sortOrder="@ViewData["CurrentSort"]"
       asp-route-page="@(Model.PageList.PageIndex + 1)"
       asp-route-currentFilter="@ViewData["CurrentFilter"]"
       class="btn btn-default @nextDisabled">
        Next
    </a>

Ссылка вURL при первоначальной загрузке формы - http://localhost:62501/Home/..%2FresortDeals%2FGetResultList, но при нажатии кнопки «следующий» URL-адрес: http://localhost:62501/resortDeals/GetResultList?page=2

Это странно, поскольку действие asp для кнопки отправки формы имеетто же значение:

 <div>
            <input type="submit" value="View Results" asp-action="GetResultList" class="btn btn-sm" />
        </div>

Я предполагаю, что проблема может быть связана со значением параметра страницы, указанным в asp-route-page, но я точно не знаю, почему это может привести к тому, чтобудет использоваться совершенно другой URL, так как я все еще очень плохо знаком с тегами-помощниками. Что может быть причиной того, что кнопка «следующий» генерирует неверный URL?

Редактировать

действие контроллера:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> GetResultList(ResortDataJoinObj resDeals, int page =1)
        {
            if (ModelState.IsValid)
            {
                var resultsObj = (from rd in _db.ResortData
                                  join ra in _db.ResortAvailability on rd.RecNo equals ra.RecNoDate
                                  where ra.TotalPrice < Int32.Parse(resDeals.priceHighEnd) && ra.TotalPrice > Int32.Parse(resDeals.priceLowEnd)

                                  select new ResortDealResultsObject
                                  {
                                      Name = rd.Name,
                                      ImageUrl = rd.ImageUrl,
                                      ResortDetails = rd.ResortDetails,
                                      CheckIn = ra.CheckIn,
                                      Address = rd.Address,
                                      TotalPrice = ra.TotalPrice

                                  });
                int i = 0;
                List<ResortDealResultsObject> resultList = new List<ResortDealResultsObject>();
                foreach (var row in resultsObj)
                {
                        var tempVm = new ResortDealResultsObject
                        {
                            Name = row.Name,
                            ImageUrl = row.ImageUrl,
                            ResortDetails = row.ResortDetails,
                            CheckIn = row.CheckIn,
                            Address = row.Address,
                            TotalPrice = row.TotalPrice
                        };
                        resultList.Add(tempVm);
                }
                int pageSize = 3;    
                var model = await PaginatedList<ResortDealResultsObject>.CreateAsync(resultsObj, page, pageSize);
                ResortDataJoinObj joinObj = new ResortDataJoinObj();
                joinObj.PageList = model;
                ViewBag.rowsReturned = true;

                return View(joinObj);
            }
            return View(resDeals);
        }

HTML-форма:

<form asp-action="GetResultList" method="post">
        <div>
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <div class="row">
                    <div class="col-sm-1">
                        <label asp-for="ResData.Name"></label>
                        <input asp-for="ResData.Name" />
                        <span asp-validation-for="ResData.Name"></span>
                    </div>
                    @*<div class="col-sm-2">
                            <label asp-for="ResAvail.CheckIn"></label>
                            <input asp-for="ResAvail.CheckIn" />
                            <span asp-validation-for="ResAvail.CheckIn"></span>
                        </div>
                        <div class="col-sm-3">
                            <label asp-for="ResAvail.CheckOut"></label>
                            <input asp-for="ResAvail.CheckOut" />
                            <span asp-validation-for="ResAvail.CheckOut"></span>
                        </div>*@
                    <div class="col-sm-4">
                        <label asp-for="priceLowEnd"></label>
                        <input asp-for="priceLowEnd" />
                        <span asp-validation-for="priceLowEnd"></span>
                    </div>
                    <div class="col-sm-5">
                        <label asp-for="priceHighEnd"></label>
                        <input asp-for="priceHighEnd" />
                        <span asp-validation-for="priceHighEnd"></span>
                    </div>
                </div>
            </div>
            <span asp-validation-for="ResData.Name" class="text-danger"></span>
        </div>

        <div>
            <input type="submit" value="View Results" asp-action="GetResultList" class="btn btn-sm" />
        </div>
    </form>

Ответы [ 2 ]

0 голосов
/ 16 мая 2018

Позвольте мне перефразировать то, что я сказал в комментарии:

Обычно для нумерации страниц необходимо просто выполнить действие контроллера, чтобы иметь параметр page=1, такой же, как у вас, для указаниятекущий выбор страницы.А в ссылках на элементы нумерации страниц вы можете получить текущий URL и просто изменить параметр page на currentPage +/- 1, currentPage +/- 2 и т. Д.

Так что я сделаю нумерацию страниц следующим образом:

Создание класса Pager.cs для представления логики

using System;

namespace DL.SO.Framework.Mvc.Pagination
{
    public class Pager
    {
        // Here I hard code the page size but you can set it as one of
        // the parameters of its constructor
        private const int PAGESIZE = 12;

        public int TotalItems { get; private set; }
        public int CurrentPage { get; private set; }
        public int TotalPages { get; private set; }
        public int StartPage { get; private set; }
        public int EndPage { get; private set; }

        public int PageSize
        {
            get { return PAGESIZE; }
        }

        public int ShowingRangeFromItem
        {
            get
            {
                int fromItem = (CurrentPage - 1) * PageSize + 1;
                if (fromItem > TotalItems)
                {
                   fromItem = TotalItems;
                }

                return fromItem;
            }
        }

        public int ShowingRangeToItem
        {
            get
            {
                int toItem = CurrentPage * PageSize;
                if (toItem > TotalItems)
                {
                    toItem = TotalItems;
                }

                return toItem;
            }
        }

        // Constructor
        public Pager(int totalItems, int currentPage = 1)
        {
            // Calculate total, start and end pages
            var totalPages = (int)Math.Ceiling((decimal)totalItems / (decimal)PageSize);

            currentPage = currentPage < 1
                ? 1
                : currentPage;

            // I only want to display +/- 2 pagination links
            var startPage = currentPage - 2;
            var endPage = currentPage + 2;

            if (startPage <= 0)
            {
                endPage = endPage - startPage + 1;
                startPage = 1;
            }

            if (endPage > totalPages)
            {
                endPage = totalPages;
                if (endPage > 5)
                {
                    startPage = endPage - 4;
                }
            }

            TotalItems = totalItems;
            CurrentPage = currentPage;
            TotalPages = totalPages;
            StartPage = startPage;
            EndPage = endPage;
        }
    }
}

Создание частичного представления _PagerPartial.cshtml в общей папке для построения нумерации страниц

@model DL.SO.Framework.Mvc.Pagination.Pager

@if (Model != null && Model.TotalItems > 0)
{
   <div class="list-pager">
       <div class="list-pager-info">
           <span>
               Showing 
               <strong>@Model.ShowingRangeFromItem-@Model.ShowingRangeToItem</strong>
               of
               <strong>@Model.TotalItems</strong>
               entries
           </span>
       </div>
       <div class="list-pagination">
           <ul class="pagination">
               <li class="page-item @(Model.CurrentPage == 1? "disabled" : "")">
                   <!-- See how I change the page parameter? -->
                   <a href="@Url.Current(new { page = Model.CurrentPage - 1 })"
                       class="page-link" tabindex="-1">
                       &lt; Prev
                   </a>
               </li>

               @for (int i = Model.StartPage; i <= Model.EndPage; i++)
               {
                   <li class="page-item @(i == Model.CurrentPage? "active" : "")">
                       <!-- See how I change the page parameter? -->
                       <a href="@Url.Current(new { page = i })" class="page-link">@i</a>
                   </li>
               }

               <li class="page-item @(Model.CurrentPage >= Model.EndPage? "disabled" : "")">
                   <!-- See how I change the page parameter? -->
                   <a href="@Url.Current(new { page = Model.CurrentPage + 1 })"
                       class="page-link" tabindex="-1">
                       Next &gt;
                   </a>
               </li>
           </ul>
       </div>
   </div>
}

Метод расширения для получения текущего URL

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Routing;

namespace DL.SO.Framework.Mvc.Extensions
{
    public static class UrlHelperExtensions
    {
        public static string Current(this IUrlHelper url, object routeValues)
        {
            // Convert new route values to a dictionary
            var newRouteData = new RouteValueDictionary(routeValues);

            // Get current route data
            var currentRouteData = url.ActionContext.RouteData.Values;

            // Get current route query string and add them back to the new route
            var currentQuery = url.ActionContext.HttpContext.Request.Query;
            foreach (var param in currentQuery)
            {
                currentRouteData[param.Key] = param.Value;
            }

            // Merge new route data
            foreach (var item in newRouteData)
            {
                currentRouteData[item.Key] = item.Value;
            }

            return url.RouteUrl(currentRouteData);
        }
    }
}

Допустим, у вас есть ProductController, который отображает список продуктов.Обычно у вас есть модель представления для этой страницы, и в этой модели представления вы можете иметь список продуктов, а также класс pager для представления нумерации страниц.

Просмотр моделей

public class ProductListViewModel
{   
    public IList<ProductSummaryViewModel> Products { get; set; }
    public Pager Pager { get; set; }
}

public class ProductSummaryViewModel
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}

Контроллер

// I am just making this up. Not production ready
public class ProductController : Controller
{
    private readonly AppDbContext _dbContext;

    public ProductController(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IActionResult Index(int page = 1)
    {
        var vm = new ProductListViewModel
        {
            Products = new List<ProductSummaryViewModel>()
        };

        // Get products from database
        var products = _dbContext.Products
            .AsNoTracking();

        // Setup pagination
        vm.Pager = new Pager(products.Count(), page);

        var pagedProducts = products
            .Skip((vm.Pager.CurrentPage - 1) * vm.Pager.PageSize)
            .Take(vm.Pager.PageSize)
            .ToList();

        foreach (var product in pagedProducts)
        {
            vm.Products.Add(new ProductSummaryViewModel
            {
               ProductId = product.Id,
               Name = product.Name
            });
        }

        return View(vm);
    }
}

Представление списка продуктов - Index.cshtml

@model ProductListViewModel
@{
    ViewData["Title"] = "Products";
}

@foreach (var product in Model.Products)
{
    <!-- However you want to display your products -->
}

<!-- 
  -- This is how you generate the pagination. Just render the partial 
  -- with the pager model
  -->
@Html.Partial("_PagerPartial", Model.Pager)

Снимок экрана

No fun without a screenshot to show how it works out?

0 голосов
/ 15 мая 2018

Ваше действие не найдено на контроллере при нажатии «Далее», потому что якорь отправляет запрос get, а контроллер настроен на прием только [HttpPost] запросов.

РЕДАКТИРОВАТЬ

В основном, я бы обновил вашу форму для использования get.
1. Обновите форму для использования method="get"
2. Удалите [HttpPost]и [ValidateAntiForgeryToken] из действия контроллера
3. Обновите ссылки Next и Previous, чтобы получить текущую строку запроса с измененным номером страницы (как показано ниже)

@{
        var existing = Url.ActionContext.HttpContext.Request.Query.ToDictionary(f => f.Key, f => f.Value.ToString());
        existing["sortOrder"] = ViewData["CurrentSort"]?.ToString();
        existing["currentFilter"] = ViewData["CurrentFilter"]?.ToString();

        var previousData = new Dictionary<string, string>(existing);
        previousData["page"] = $"{Model.Results.PageIndex - 1}";

        var nextData = new Dictionary<string, string>(existing);
        nextData["page"] = $"{Model.Results.PageIndex + 1}";
    }

    <a asp-all-route-data="previousData" asp-action="GetResultList">Previous</a>
    <a asp-all-route-data="nextData" asp-action="GetResultList">Next</a>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...