views:

2866

answers:

4

I want to have different sorting and filtering applied on my view I figured that i'll be passing sorting and filtering params through query string

<%= Html.ActionLink("Name", "Index", new { SortBy= "Name"}) %>

this simple construction allows me to sort.

view comes back with

?SortBy=Name

in query string

now i want to add filtering and i want my query strig to end up with

?SortBy=Name&Filter=Something

how can i add another parameter to list of already existing ones in ActionLink?

example:

user requests /Index/

view has

 <%= Html.ActionLink("Name", "Index", new { SortBy= "Name"}) %>

and

 <%= Html.ActionLink("Name", "Index", new { FilterBy= "Name"}) %>

links

first one looks like /Index/?SortBy=Name second is /Index/?FilterBy=Name

i want when user pressed sorting link after he applied some filtering - filtering is not lost, so i need a way to combine my params. My guess is there should be a way to not parse query string, but get collection of parameters from some mvc object.

+3  A: 
<%= Html.ActionLink("Name", "Index", new { SortBy= "Name", Filter="Something"}) %>

To preserve the querystring you can:

<%= Html.ActionLink("Name", "Index", 
     String.IsNullOrEmpty(Request.QueryString["SortBy"]) ? 
        new { Filter = "Something" } : 
        new { SortBy=Request.QueryString["SortBy"], Filter="Something"}) %>

Or if you have more parameters, you could build the link manually by using taking Request.QueryString into account.

Mehrdad Afshari
+4  A: 

so far the best way i figured out is to create a copy of ViewContext.RouteData.Values and inject QueryString values into it. and then modify it before every ActionLink usage. still trying to figure out how to use .Union() instead of modifying a dictionary all the time.

<% RouteValueDictionary   tRVD = new RouteValueDictionary(ViewContext.RouteData.Values); %>

<% foreach (string key in Request.QueryString.Keys )
    {
      tRVD[key]=Request.QueryString[key].ToString();
    } %>

<%tRVD["SortBy"] = "Name"; %>
                <%= Html.ActionLink("Name", "Index", tRVD)%>
Alexander Taran
+1  A: 

use ActionLinkCombined instead of ActionLink

        public static string ActionLinkCombined(this HtmlHelper htmlHelper, string linkText, string actionName,
                                            object routeValues)
    {
        var dictionary = new RouteValueDictionary();
        foreach (var pair in htmlHelper.ViewContext.Controller.ValueProvider)
            dictionary[pair.Key] = pair.Value.AttemptedValue;
        if (routeValues != null)
        {
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(routeValues))
            {
                object o = descriptor.GetValue(routeValues);
                dictionary[descriptor.Name] = o;
            }
        }
        return htmlHelper.ActionLink(linkText, actionName, dictionary);
    }
+1  A: 

My solution is similar to qwerty1000's. I created an extension method, ActionQueryLink, that takes in the same basic parameters as the standard ActionLink. It loops through Request.QueryString and adds any parameters found to the RouteValues dictionary that are not already present (so we can overwrite the original query string if needed).

To preserve the existing string but not add any keys the usage would be:

<%= Html.ActionQueryLink("Click Me!","SomeAction") %>

To preserve the existing string and add new keys the user would be:

<%= Html.ActionQueryLink("Click Me!","SomeAction", new{Param1="value1", Param2="value2"} %>

The code below is for the two usages, but it should be pretty easy to add other overloads to match the other ActionLink extensions as needed.

    public static string ActionQueryLink(this HtmlHelper htmlHelper,
        string linkText, string action)
    {
        return ActionQueryLink(htmlHelper, linkText, action, null);
    }

    public static string ActionQueryLink(this HtmlHelper htmlHelper, 
        string linkText, string action, object routeValues)
    {
        var queryString =
            htmlHelper.ViewContext.HttpContext.Request.QueryString;

        var newRoute = routeValues == null 
            ? htmlHelper.ViewContext.RouteData.Values 
            : new RouteValueDictionary(routeValues);

        foreach (string key in queryString.Keys)
        {
            if (!newRoute.ContainsKey(key)) 
                newRoute.Add(key, queryString[key]);
        }
        return HtmlHelper.GenerateLink(htmlHelper.ViewContext.RequestContext,
            htmlHelper.RouteCollection, linkText, null /* routeName */, 
            action, null, newRoute, null);
    }
Brian