I have a form rendered via Html.BeginForm(), it exists as a component in the Master page so that it appears on every page in the application. I have done this using Html.RenderAction() from Mvc Futures assembly. It's a simple search form that updates some items in the same component underneigh the search form itself, and performs a GET so that the search term appears in the querystring.
<div class="sideBarContent">
<h2>Search Products</h2>
<% using (Html.BeginForm(ViewContext.RouteData.Values["action"].ToString(),
ViewContext.RouteData.Values["controller"].ToString(), FormMethod.Get)) { %>
<fieldset>
<legend>Search Products</legend>
<div class="formRow">
<label for="ProductsSearch">Search</label>
<%= Html.TextBox("ProductsSearch") %>
</div>
<input type="submit" value="Search" class="button" />
</fieldset>
<% } %>
<ul>
// Products will eventually be listed here
</ul>
</div>
I need this form to do the following:
1) It should perform a GET to whatever current page it is on appending 'ProductsSearch' as a querystring parameter (eg. example.com/?ProductsSearch=test or example.com/books/fiction?ProductsSearch=test)
2) It should remember any exising querystring parameters that are already in the querystring, maintaining them after you click Search button eg. example.com/myOrders?page=2 after Search click it should go to example.com/myOrders?page=2&ProductsSearch=test)
I can get it to do 1) but can't work out 2).
I relise that normally for a from to GET and appending querystring params it needs to have hidden form fields, so I could write a utility function that automatically adds a bunch of hidden form fields for any querystring values, but I wanted to check that there's wasn't an easier approach, or maybe I'm going about it the wrong way.
Cheers!
You'll need to do the hidden form field method.
Even if you could attach the entire querystring to the end of the URL in the action attribute of the <form> tag, browsers don't pay attention to this when doing GET form submissions.
Your method isn't too difficult; you'd want to do something like this:
public static string QueryStringAsHidden(this HtmlHelper helper)
{
var sb = new StringBuilder();
foreach (var key in HttpContext.Current.Request.QueryString.AllKeys)
{
if (! key.StartsWith("ProductSearch"))
sb.Append(helper.Hidden(key, HttpContext.Current.Request.QueryString[key]));
}
return sb.ToString();
}
I put the .StartsWith() in there because you don't want to be on a search page and submit the search string twice (and now you can prepend paging and other search-specific variables with ProductSearch.
Edit: PS: To get the form to post to the current page, you don't have to explicitly provide action and controller -- you can also send nulls.
Edit2: Why even bother with a helper method? :)
<% HttpContext.Current.Request.QueryString.AllKeys.Where(k => !k.StartsWith("ProductSearch")).ToList().ForEach(k => Response.Write(Html.Hidden(k, HttpContext.Current.Request.QueryString[k]))); %>
James
A direct to call BeginForm() does keep your query string values. Any other overload tends to fail. I love the ease of using BeginForm() from my forms, but needed a way to class all my styled forms a certain way an not lose the query string values in the action.
Here is what I came up with:
public static MvcForm BeginNormalForm<T>(this HtmlHelper<T> htmlHelper)
{
var dictionary = new Dictionary<string, object> {{"class", "normal"}};
var rvd = new RouteValueDictionary();
if (htmlHelper.ViewContext.HttpContext != null && htmlHelper.ViewContext.HttpContext.Request != null)
{
foreach (var key in htmlHelper.ViewContext.HttpContext.Request.QueryString.AllKeys)
{
rvd[key] = htmlHelper.ViewContext.HttpContext.Request.QueryString[key];
}
}
var form = htmlHelper.BeginForm(null, null, rvd, FormMethod.Post, dictionary);
return form;
}
Seems to work well and keeps my class attribute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With