Search code examples
asp.net-mvcasp.net-mvc-3html-selectpagedlist

Set ASP MVC3 dropdown list item from controller when using PagedList


I have a page that uses PagedList but also contains a drop down list used for sorting. Problem is, whenever someone uses the drop down list items for sorting, whenever they hit "next" or "back", the drop down list items are restored to their default, the program runs through the controller with the default (basically blank) sort criteria, and you loose the sorted items when you navigate to page two or beyond (and back).

Here is the controller used for this page:

    public ActionResult Index(FormCollection dropDownSelection, string currentFilter, int? page)
    {
        //security
        if (!Security.IsViewer(User)) return RedirectToAction("Message", "Home", new { id = 2 });

        if (ViewBag.Level == 0) return RedirectToAction("Message", "Home", new { id = 2 });

        if (!(Request.HttpMethod == "GET"))
        {
            page = 1;
        }


        string table = String.IsNullOrWhiteSpace(dropDownSelection["Table"]) ? "%" : dropDownSelection["Table"];
        string issue = String.IsNullOrWhiteSpace(dropDownSelection["IssueType"]) ? "%" : dropDownSelection["IssueType"];
        string status = String.IsNullOrWhiteSpace(dropDownSelection["Status"]) ? "%" : dropDownSelection["Status"];

        var followUpItem = from follow in db.FollowUpItems
                           where (follow.TableName.Equals(table) || table.Equals("%")) &&
                                 (follow.IssueType.Equals(issue) || issue.Equals("%")) &&
                                 (follow.Status.Equals(status) || status.Equals("%"))
                           orderby follow.Id
                           select follow;

        int pageNumber = (page ?? 1);
        int pageSize = 10;

        return View(followUpItem.ToPagedList(pageNumber, pageSize));
    }

Here is the drop down list from the View:

          <select name="Table" title="Table" style="font-size:8pt;">
            <option value="%">--Table Name--</option>
            <option value="AgentContEd">CE</option>
            <option value="AgentProductTraining">PT</option>
          </select>
          <select name="IssueType" style="font-size:8pt;">
            <option value="%">--Issue Type--</option>
            <option value="W">Warning</option>
            <option value="E">Error</option>
          </select>
          <select name="Status" style="font-size:8pt;">
            <option value="%">--Status Type--</option>
            <option value="O">Open</option>
            <option value="U">Under Review</option>
          </select>

And (just in case) below is the <div> that contains the PagedList navigation buttons in the View:

<div>
Page @(Model.PageCount < Model.PageNumber ? 0 : Model.PageNumber)
of @Model.PageCount

@if (Model.HasPreviousPage)
{
    @Html.ActionLink("<<", "Index", new { page = 1, sortOrder = ViewBag.CurrentSort, searchString = ViewBag.CurrentFilter, currentFilter = ViewBag.CurrentFilter })
    @Html.Raw(" ");
    @Html.ActionLink("< Prev", "Index", new { page = Model.PageNumber - 1, sortOrder = ViewBag.CurrentSort, searchString = ViewBag.CurrentFilter, currentFilter = ViewBag.CurrentFilter })
}
else
{
    @:<<
    @Html.Raw(" ");
    @:< Prev
}

@if (Model.HasNextPage)
{
    @Html.ActionLink("Next >", "Index", new { page = Model.PageNumber + 1, sortOrder = ViewBag.CurrentSort, searchString = ViewBag.CurrentFilter, currentFilter = ViewBag.CurrentFilter })
    @Html.Raw(" ");
    @Html.ActionLink(">>", "Index", new { page = Model.PageCount, sortOrder = ViewBag.CurrentSort, searchString = ViewBag.CurrentFilter, currentFilter = ViewBag.CurrentFilter })
}
else
{
    @:Next >
    @Html.Raw(" ")
    @:>>
}
</div>

Solution

  • What if you were to pass your followUpItem through a ViewModel first and then actually passing the selected value from the dropdownlist aswell? Maybe something close to this.

    public ActionResult Index(FormCollection dropDownSelection, string currentFilter, int? page)
    {
        //Stuff abbreviated 
    
        return View(new StuffViewModel(followUpItem.ToPagedList(pageNumber, pageSize)), "SelectedDropDownItem");
    }
    

    And then you can deal with it within the ViewModel, for instance creating your own DropDownlist in memory. Something like this.

    public class StuffViewModel
    {
        public List<FollowUpItem> FollowUpItems {get; private set;}
        public List<SelectListItem> DropDownList {get; private set}
    
        public StuffViewModel(List<FollowUpItem> followUpItems, string selectedDropDownValue)
        {
            FollowUpItems = followUpItems;
    
            List<SelectListItem> selectList = new List<SelectListItem>();
            //TODO: here you would decide which is selected from the selectedDropDownValue parameter
            selectList.Add(new SelectListItem{ Selected = true, Text = "Text", Value = "Value" });
            selectList.Add(new SelectListItem{ Selected = false, Text = "Text2", Value = "Value2" });
            //...and more values as you need them
    
            DropDownList = selectList
        }
    }
    

    By doing this with a ViewModel you would always preserve the selected value from your dropdown from each click no matter where in the pagedList you are.

    Just remember that your View would now contain a Model that includes a StuffViewModel instead of containing only PagedList. Now you call your elements within the view like this:

    @model StuffViewModel
    
    //TODO: access dropdownlist
    @Html.DropDownList("name", Model.DropDownList)
    
    //TODO: access PagedList for instenace like this:
    if(Model.FollowUpItems.HasPreviousPage)
    {
        //do stuff
    }
    

    I hope I´m making any sense :)