views:

93

answers:

3

Hi, I'm trying to implement a paging and sorting list in ASP.NET MVC without using MVContrib grid or javascript (needs to be seo friendly).

I have constructed my action with the following signature:

ActionResult List(int? page, string sort, string direction);

The problem I have though is getting both the paging and the sorting to work. Say for example I have the following code:

<%= Html.ActionLink("Title", "List", new { sort = "Title", direction = "ASC" }) %>

I hoped this would generate a url containing all of the existing route values (including the current page) but it doesn't. Therefore when you click on the link the page is set back to null.

I have looked at all the overloads for the ActionLink helper but nothing looks like it will help. What I effectively need to do is generate a url/link with the existing page value (or potentially any other route values) and the new sort parameters.

I'd appreciate it if someone could help. Thanks.

A: 

Hey,

You would need to write your own html helper, which is easy to do. To do that, use the following format:

public static class MyExtensions
{
   public static string MyActionLink(this HtmlHelper html, ...)
   {
      //Definition, return string
   }
}

And use this to create your own. You can access the information within the HTML helper to get information about the current request (to pull out the current route values and combine them with existing ones...

HTH.

Brian
A: 

Why can't you specify the page in your route values as follows?

<%= Html.ActionLink("Title", "List", new { page = currentPage, sort = "Title", direction = "ASC" }) %>

I will hazard a guess that the Model for ActionResult List(int? page, string sort, string direction); is your list of items currently, so you haven't got currentPage readily available. If this the case, create a view model that contains your list and the currentPage. e.g.

// View Model
public class MyViewModel
{
    public int CurrentPage { get; set; }
    public IList<SomeObject> Items { get; set; }
}

// Action Method
public ActionResult List(int? page, string sort, string direction)
{
    return View(new MyViewModel()
    {
        CurrentPage = page ?? 1,
        Items       = _myRepository.GetPagedList(page, sort, direction);
    });
}

// View
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MyProject.Controllers.MyController.MyViewModel>" %>
...

<%= Html.ActionLink("Next", "List", new { page = Model.CurrentPage + 1, sort = "Title", direction = "ASC" }) %>

<% foreach (SomeObject obj in Model.Items) { %>
    <!-- Display each item -->
<% } %>
s1mm0t
nfplee
A: 

Problem solved. I managed to come up with the following extension methods:

public static class ActionLinkExtensions
{
    public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, bool addExistingRouteValues)
    {
        return ActionLink(helper, linkText, actionName, null, null, addExistingRouteValues, null);
    }

    public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, object routeValues, bool addExistingRouteValues)
    {
        return ActionLink(helper, linkText, actionName, null, routeValues, addExistingRouteValues, null);
    }

    public static MvcHtmlString ActionLink(this HtmlHelper helper, string linkText, string actionName, string controllerName, object routeValues, bool addExistingRouteValues, object htmlAttributes)
    {
        var queryString = helper.ViewContext.HttpContext.Request.QueryString;
        var newRouteValues = routeValues == null ? helper.ViewContext.RouteData.Values : new RouteValueDictionary(routeValues);

        if (addExistingRouteValues)
        {
            foreach (string key in queryString.Keys)
            {
                if (!newRouteValues.ContainsKey(key))
                    newRouteValues.Add(key, queryString[key]);
            }
        }

        return MvcHtmlString.Create(HtmlHelper.GenerateLink(helper.ViewContext.RequestContext, helper.RouteCollection, linkText, null, actionName, controllerName, newRouteValues, new RouteValueDictionary(htmlAttributes)));
    }
}

Now all you have to do is add true at the end of your helper and the existing route values will be added. Hope this helps.

nfplee