Как сократить URL при использовании пагинации и фильтрации с несколькими флажками - PullRequest
0 голосов
/ 31 мая 2018

Я использую PagedList для подкачки на стороне сервера, а также имею текстовое поле в представлении для фильтрации данных вместе с флажками, чтобы определить, какие поля в моей модели следует фильтровать на основе текста поиска.

Мой текущий код

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

public class SearchPagingViewModels
{
    public IPagedList<AllResolution> Resolutions { get; set; }
    public string Keyword { get; set; } // serach text
    public bool IsResYearChecked { get; set; } // used to filter the ResolutionYear field
    public bool IsResNumChecked { get; set; } // used to filter the ResolutionNumber field
    public bool IsResTextChecked { get; set; } // used to filter the ResolutionText field
}

Контроллер

public ViewResult Index(int? page string keyword, bool? isResYearChecked, bool? isResNumChecked, bool? isResTextChecked)
{
    int pageSize = 25;
    int pageNumber = (page ?? 1);
    bool searchYear = isResYearChecked.GetValueOrDefault();
    ....
    IQueryable<> resolutions = db.AllResolutions;
    if (searchKeyword != null)
    {
        if (searchYear)
        {
            resolutions = resolutions.Where(x => x.ResolutionYear.Contains(searchKeyword));
        }
        ....
    }
    resolutions = resolutions.OrderBy(c => c.ResolutionYear).ThenBy(c => c.ResolutionNumber);
    SearchPagingViewModels model = new SearchPagingViewModels
    {
        Keyword = keyword,
        IsResYearChecked = searchYear,
        ....
        Resolutions = resolutions.ToPagedList(pageNumber, pageSize)
    };
    return View(model);
}

Просмотр

@model SearchPagingViewModels
....
@using (Html.BeginForm("Index", "Resolutions", FormMethod.Get))
{
    @Html.LabelFor(m => m.Keyword)
    @Html.TextBoxFor(m => m.Keyword)

    @Html.LabelFor(m => m.IsResYearChecked)
    @Html.CheckBoxFor(m => m.IsResYearChecked)

    // .. ditto for IsResNumChecked etc

    <input type="submit" value="search" />
}

<table>
    <thead>
        ....
    </thead>
    <tbody>
        @foreach (var task in Model.Resolutions)
        {
            // .... build table rows
        }
    </tbody>
</table>

@Html.PagedListPager(Model.Resolutions, page => Url.Action("Index", new { page, Keyword = Model.Keyword, IsResYearChecked = Model.IsResYearChecked, IsResNumChecked = IsResNumChecked IsResTextChecked = Model.IsResTextChecked }))

Хотя это работает, проблема в том, чтоfor генерирует длинную и некрасивую строку запроса, например,

.../Index?Keyword=someText&IsResYearChecked=true&IsResYearChecked=false&IsResNumChecked=false&IsResTextChecked=true&IsResTextChecked=false

И теперь я хочу добавить дополнительные bool свойства для фильтрации записей, что делает его еще хуже и потенциально может превышатьограничение строки запроса.

Есть ли способ сократить URL?Будет ли это связано с маршрутизацией?Будет ли новая ViewModel для этого?

1 Ответ

0 голосов
/ 03 июня 2018

Вы можете заменить все свои свойства bool на enum, помеченный атрибутом [Flags], где каждое значение в enum представляет свойство в вашей модели для поиска.

[Flags]
public enum FilterProperties
{
    None = 0,
    ResolutionYear = 1,
    ResolutionNumber = 2,
    ResolutionText = 4,
    .... // more properties
}

и модель представления будет

public class SearchPagingViewModels
{
    public string Keyword { get; set; }
    public FilterProperties Filter { get; set; }
    public IPagedList<AllResolution> Resolutions { get; set; }
}

Метод контроллера станет

public ViewResult Index(int? page string keyword, FilterProperties filter = FilterProperties.None)
{
    IQueryable<AllResolution> resolutions = db.AllResolutions;
    if (searchKeyword != null)
    {
        if (filter.HasFlag(FilterProperties.ResolutionYear)
        {
            resolutions = resolutions.Where(x => x.ResolutionYear.Contains(feyword));
        }
        // .... more if blocks for other enum values
    }
    resolutions = resolutions.OrderBy(c => c.ResolutionYear).ThenBy(c => c.ResolutionNumber);
    SearchPagingViewModels model = new SearchPagingViewModels
    {
        Keyword = keyword,
        Filter = filter,
        Resolutions = resolutions.ToPagedList(pageNumber, pageSize)
    };
    return View(model);
}

После этого вы увидите:

@using (Html.BeginForm("Index", "Resolutions", FormMethod.Get))
{
    @Html.LabelFor(m => m.Keyword)
    @Html.TextBoxFor(m => m.Keyword)
    @Html.ValidationMessageFor(m => m.Keyword)
    @Html.HiddenFor(m => m.Filter)
    foreach (Enum item in Enum.GetValues(typeof(Tables.Controllers.FilterProperties)))
    {
        if (item.Equals(Tables.Controllers.FilterProperties.None))
        {
            continue;
        }
        <div>
            <label>
                <input type="checkbox" value="@((int)(object)item)" checked=@Model.Filter.HasFlag(item) />
                <span>@item</span>
            </label>
        </div>
    }
    <span id="filtererror" class="field-validation-error" hidden >Please select at least one property to search</span>
    <input type="submit" value="Search" />
}

<table>
    ....
</table>
@Html.PagedListPager(Model.Resolutions, page => Url.Action("Index", new { page, Keyword = Model.Keyword, Filter = (int)Model.Filter }))

И затем используйте javascript для andlesсоздает .submit() событие для обновления скрытого входного значения для Filter (заметьте, я также предположил, что вы хотите установить хотя бы один флажок, если значение Keyword не равно null)

<script>
    var checkboxes = $('input:checkbox');
    var keyword = $('#Keyword');
    $('form').submit(function () {
        var filter = 0;
        // validate at least one checkbox must be checked if Keyword has a value
        if (keyword.val() && checkboxes.filter(':checked').length == 0) {
            $('#filtererror').show();
            return false;
        }
        $.each(checkboxes, function () {
            if ($(this).is(':checked')) {
                filter += Number($(this).val());
            }
            // disable checkboxes to prevent their value being added to the query string
            $(this).prop('disabled', true);
        })
        $('#Filter').val(filter);
    })

    checkboxes.click(function () {
        if (keyword.val() && checkboxes.filter(':checked').length == 0) {
            $('#filtererror').show();
        } else {
            $('#filtererror').hide();
        }
    })
</script>

Ваш URL (на основе проверяемых ResolutionYear и ResolutionText) теперь будет

.../Index?Keyword=someText&Filter=5

вместо

.../Index?Keyword=someText&IsResYearChecked=true&IsResYearChecked=false&IsResNumChecked=false&IsResTextChecked=true&IsResTextChecked=false

...