简体   繁体   中英

How should I handle filtering search results within a date range for my asp.net core mvc app?

Good afternoon, I have been reading through forums, blogs and the like all day trying to figure out a solution to my issue, but none of them quite hit the nail on the head.

My scenario: I am trying to filter search results by a date range. I would like the user to be able to search for specific records and filter that search with a date range. Alternatively, I want them to be able to view all records within a date range without providing search criteria.

ViewModel

    public class VMSpecialCollectionSearch
{
    // results of search query
    public List<ArchivesFileManagement_MVCDB.SpecialCollections> SearchResults { get; internal set; }

    public SelectList TypeOptions { get; set; }

    // Selected search options
    [Required]
    public string SearchType { get; set; }
    [Required]
    public string SearchText { get; set; }
    public string CurrentFilter { get; set; }

    public DateTime? FromDate { get; set; }
    public DateTime? ToDate { get; set; }
}

The Forms - note: the first form functions properly and returns my search results accordingly.

    <form class="form-group" onsubmit="return validateSelection()">
    <div class="card-body">
        <div class="row justify-content-center">
            <div class="col-md-auto">
                <label>Type:</label>&nbsp;
                <select id="searchTypeSelection" asp-for="SearchType" asp-items=@Model.TypeOptions required></select>
            </div>
            <div class="col-md-auto">
                <label>Description:</label>&nbsp;
                <input id="searchText" type="text" asp-for="SearchText" required />
            </div>
            <div class="col-md-auto">
                <button type="submit" class="btn btn-primary btn-sm">Search</button>
            </div>
        </div>
    </div>
</form>
<form id="dateForm" onsubmit="ApplyDateFilter(event)" class="form-group">
    <div class="row justify-content-center">
        <div class="col-md-auto">
            <label>From:</label>&nbsp;
            <input id="fromDate" type="text" asp-for="FromDate" class="datePicker" required />
        </div>
        <div class="col-md-auto">
            <label>To:</label>&nbsp;
            <input id="toDate" type="text" asp-for="ToDate" class="datePicker" required />
        </div>
        <div class="col-md-auto">
            <button class="btn btn-primary btn-sm" type="submit">Apply</button>
        </div>
    </div>
</form>

Handling the date filter submission - note: I tried setting this up as a Post method as well, but that didn't work either.

    function ApplyDateFilter(e) {
        e.preventDefault();
        //var formData = new FormData($("#dateForm").get(0));
        var from = $("#fromDate").val();
        var to = $("#toDate").val();
        var type = $("#searchTypeSelection").val();
        var text = $("#searchText").val();
        debugger;
        $.ajax({
            type: "Get",
            url: '@Url.Action("IndexFilter", "SpecialCollections")',
            data: //formData,
            {
                FromDate: from,
                ToDate: to,
                SearchType: type,
                SearchText: text
            },
            contentType: "application/json",
        });
    }

Controller

    // GET: SpecialCollections/
    public IActionResult IndexFilter(string FromDate, string ToDate, string SearchType, string SearchText)
    {    ... CREATE AN UPDATED VIEW MODEL ...

        return View(nameof(Index), vm);
    }

My issue: When the second form (for date range) is submitted I don't get back my new search query results when I return the view. It gives me the same results I had previously. Is there a better way to handle this scenario?

Here is what I have tried... I tried implementing the search results as a partial view so I could update the results without reloading the page. This failed because all of my buttons in the results table broke. (I tried using delegation to fix that to no avail). I am currently trying to handle the second form submission in a different action and then reload the same View (index) with the new View Model.

Everything seems to work except the search results are unchanged. I am not getting any errors.

My issue: When the second form (for date range) is submitted I don't get back my new search query results when I return the view. It gives me the same results I had previously. Is there a better way to handle this scenario?

Since you are using JQuery Ajax to filter the data (based on the date range), after the action executing, it will return the updated view to the Ajax success function. But from your code, you haven't updated the page content based the response in the Ajax success function, so the data not update.

I suggest you could refer the following sample code and use a Partial view to display the records.

Models:

public class VMSpecialCollectionSearch
{ // results of search query
    public List<VMArchives> SearchResults { get; internal set; }

    public SelectList TypeOptions { get; set; }

    // Selected search options
    [Required]
    public string SearchType { get; set; }
    [Required]
    public string SearchText { get; set; }
    public string CurrentFilter { get; set; }

    public DateTime? FromDate { get; set; }
    public DateTime? ToDate { get; set; }
}
 
public class VMArchives
{
    public int Id { get; set; }
    public string Titile { get; set; }

    public DateTime DateTime { get; set; }
    public string Type { get; set; }
}

Then, Create a ArchivesController controller to manager the Archives:

public class ArchivesController : Controller
{
    private readonly IRepository repo; //create a Repository and add initial data.
    public ArchivesController(IRepository repository)
    {
        repo = repository;
    }
    //Main page
    public IActionResult Index(string FromDate, string ToDate, string SearchType, string SearchText)
    { 
        var result = FilterData(FromDate, ToDate, SearchType, SearchText); 

        return View(result);
    }

    //Based on the condition to filter data
    public VMSpecialCollectionSearch FilterData (string FromDate, string ToDate, string SearchType, string SearchText)
    {
        VMSpecialCollectionSearch result = new VMSpecialCollectionSearch();
        //get All type
        result.TypeOptions = new SelectList(
            repo.GetAllVMArchives()
            .GroupBy(c => c.Type)
            .Select(c =>
                new SelectListItem()
                {
                    Value = c.Key,
                    Text = c.Key
                }).ToList(), "Value", "Text");

        var allArchives = repo.GetAllVMArchives();

        //According the SearchType to filter data
        if (!string.IsNullOrEmpty(SearchType) && SearchType != "All")
            allArchives = allArchives.Where(c => c.Type == SearchType).ToList();
        //According the SearchText to filter data
        if (!string.IsNullOrEmpty(SearchText))
            allArchives = allArchives.Where(c => c.Titile.Contains(SearchText)).ToList();
        //According the date range to filter data.
        if (!string.IsNullOrEmpty(FromDate) && !string.IsNullOrEmpty(ToDate))
        {
            DateTime from;
            DateTime to;

            if (DateTime.TryParse(FromDate, out from) && DateTime.TryParse(ToDate, out to))
            {
                allArchives = allArchives.Where(c => c.DateTime > from && c.DateTime < to).ToList();
            }
        }
        result.SearchResults = allArchives;
        return result;
    }

    // GET: SpecialCollections/
    public IActionResult IndexFilter(string FromDate, string ToDate, string SearchType, string SearchText)
    {
        var result = FilterData(FromDate, ToDate, SearchType, SearchText);
        return PartialView("_IndexFilter", result.SearchResults);
    }

Code in the Main Page (Index.cshtml):

@model MVCDemo.Models.VMSpecialCollectionSearch

@{
    ViewData["Title"] = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h1>Index</h1>

<form class="form-group">
    <div class="card-body">
        <div class="row justify-content-center">
            <div class="col-md-auto">
                <label>Type:</label>&nbsp;
                <select id="searchTypeSelection" asp-for="SearchType" asp-items=@Model.TypeOptions required>
                    <option value="All">All</option>
                </select>
            </div>
            <div class="col-md-auto">
                <label>Description:</label>&nbsp;
                <input id="searchText" type="text" asp-for="SearchText" required />
            </div>
            <div class="col-md-auto">
                <button type="submit" class="btn btn-primary btn-sm">Search</button>
            </div>
        </div>
    </div>
</form>
<form id="dateForm" onsubmit="ApplyDateFilter(event)" class="form-group">
    <div class="row justify-content-center">
        <div class="col-md-auto">
            <label>From:</label>&nbsp;
            <input id="fromDate" type="text" asp-for="FromDate" class="datePicker" required />
        </div>
        <div class="col-md-auto">
            <label>To:</label>&nbsp;
            <input id="toDate" type="text" asp-for="ToDate" class="datePicker" required />
        </div>
        <div class="col-md-auto">
            <button class="btn btn-primary btn-sm" type="submit">Apply</button>
        </div>
    </div>
</form>

<div id="content">
    <partial name="_IndexFilter.cshtml" model="Model.SearchResults" />
</div>

@section Scripts{
    <script>
        function ApplyDateFilter(e) {
            e.preventDefault(); 
            var from = $("#fromDate").val();
            var to = $("#toDate").val();
            var type = $("#searchTypeSelection").val();
            var text = $("#searchText").val();
            debugger;
            $.ajax({
                type: "Get",
                url: '@Url.Action("IndexFilter", "Archives")',
                data: //formData,
                {
                    FromDate: from,
                    ToDate: to,
                    SearchType: type,
                    SearchText: text
                },
                contentType: "application/json",
                success: function (response) {
                    $("#content").html(""); //clear the records content
                    $("#content").html(response);  //add the updated content.
                }
            });
        } 
    </script>
}

[ Comment ] In the Index.cshtml page, we are using a partial tag to display the VMArchives list. Then, in the Ajax success function, after get result from controller successfully, we will clear the records container and update the content.

Create a _IndexFilter.cshtml partial view to display the VMArchives, with the following code:

@model IEnumerable<MVCDemo.Models.VMArchives>

<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Id)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Titile)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.DateTime)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Type)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Id)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Titile)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.DateTime)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Type)
            </td>
            <td>
                @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
                @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
            </td>
        </tr>
}
    </tbody>
</table>

The result like this (If click the "Search" button, it will submit the form to the Index action, if click the "Apply" button, it will filter the data via Ajax):

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM