Eternal Learner
Eternal Learner

Reputation: 121

MVC Back Button Having Problems

I want to have a "Back" button that returns a user back to a page with a grid/table on it, but I'm having some trouble. The point of the back button is to allow my user's grid settings to be persisted between viewing records. The link that the Back button points to depends on what URL the user comes from. The url is set in the controller method. When the Url looks like the following...

http://localhost:49933/OpenOrder

... there is very little problem getting the back button to work. However, when the URL looks like this...

http://localhost:49933/OpenOrder?grid-sort=&grid-page=1&grid-pageSize=1000&grid-group=&grid-filter=CustomerName~contains~'TEST'

... sometimes the "Back" button won't work at all. I'm using a Telerik Kendo MVC grid, and this is what happens to the URL when a user filters the page.

I have noticed that the following code in the view works consistently on all links when there is no form tag (e.g. @Html.BeginForm())...

View

<a href='@Url.Content(@ViewBag.PreviousReferrer)' style="display:none;">
    <input type="button" value="Back" />
</a>

But this doesn't work well with Views that do have the form tag. All I get is a Back button that I can click, but does absolutely nothing. It doesn't even show up in Fiddler.

Other things that I've tried include...

<input type="button" value="Back" onclick="@("window.location.href='" + @Url.Content(ViewBag.PreviousReferrer) + "'");" />
<input type="button" value="Back2" onclick="window.location.href = '@Url.Content(@ViewBag.PreviousReferrer)'" />
<input type="button" value="Back3" onclick="javascript:window.location=('@Url.Content(@ViewBag.PreviousReferrer)')" />

As stated previously, the ViewBag.PreviousReferrer property is set in the controller. Depending on whether a user is getting or posting, it will use either the Request.PreviousReferrer, or a session variable that I set. I won't include all my controller code since the rest of the pages work fine, but here's what it looks like when I set the ViewBag.PreviousReferrer in the gets and posts. At least one GET will come before any posts, so the session variable will always be set to something.

Controller

GET
string urlReferrer = Request.UrlReferrer == null ? string.Empty : Request.UrlReferrer.AbsoluteUri.ToUpper();
if (!string.IsNullOrEmpty(urlReferrer) && urlReferrer.Contains("OPENORDER"))
{
    ViewBag.PreviousReferrer = Request.UrlReferrer.AbsoluteUri;
    Session["OpenOrderPreviousReferrer"] = Request.UrlReferrer.AbsoluteUri;
}
else
{
    ViewBag.PreviousReferrer = "~/OpenOrder";
}


POST
ViewBag.PreviousReferrer = Session["OpenOrderPreviousReferrer"] ?? "~/OpenOrder";

Ideally, this is what I want: One style of markup to go to the link in the PreviousReferrer REGARDLESS of whether or not the button is inside or outside of a form tag.

I think the problem might have something to do with HTML escape sequences, but I don't know if that's the technical term for it.

Upvotes: 0

Views: 1860

Answers (1)

iCollect.it Ltd
iCollect.it Ltd

Reputation: 93611

I had to create button links, that did a browser back "a lot" in one project, so created this HtmlHelper extension:

public static class ActionLinkButtonHelper
{
    /// <summary>
    /// Add a back button that generates a Javascript browser-back 
    /// </summary>
    /// <param name="htmlHelper">HtmlHelper we are extending</param>
    /// <param name="buttonText">Text to display on back button - defaults to "Back"</param>
    /// <param name="actionName">Name of action to execute on click</param>
    /// <param name="controller">Name of optional controller to send action to</param>
    /// <returns></returns>
    public static MvcHtmlString BackButton(this HtmlHelper htmlHelper, string buttonText="Back", string actionName="index", string controller=null, object routeValuesObject = null)
    {
        // Note: "Index is provided as a default
        return ActionLinkButton(htmlHelper, buttonText, actionName, controller, routeValuesObject, new { onclick = "history.go(-1);return false;" });
    }
}

and use it in the page like this:

@Html.BackButton()

or this:

@Html.BackButton("Button text", "action", "controller", new {id=routevalues})

It generates a button with a small snippet of JS that causes the browser to go back, so an actual link is not required unless JavaScript is disabled.

Supporting method (ActionLink as a button):

public static MvcHtmlString ActionLinkButton(this HtmlHelper htmlHelper, string buttonText, string actionName, string controllerName, object routeValuesObject = null, object htmlAttributes = null)
{
    // For testing - create links instead of buttons
    //return System.Web.Mvc.Html.LinkExtensions.ActionLink(htmlHelper, buttonText, actionName, controllerName, routeValues, htmlAttributes);

    if (string.IsNullOrEmpty(controllerName))
    {
        controllerName = HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString();
    }
    RouteValueDictionary routeValuesDictionary = new RouteValueDictionary(routeValuesObject);
    RouteValueDictionary htmlAttr = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
    TagBuilder tb = new TagBuilder("input");
    tb.MergeAttributes(htmlAttr, false);
    string href = UrlHelper.GenerateUrl("default", actionName, controllerName, routeValuesDictionary, RouteTable.Routes, htmlHelper.ViewContext.RequestContext, false);

    tb.MergeAttribute("type", "button");
    tb.MergeAttribute("value", buttonText);
    if (!tb.Attributes.ContainsKey("onclick"))
    {
        tb.MergeAttribute("onclick", "location.href=\'" + href + "\';return false;");
    }
    return new MvcHtmlString(tb.ToString(TagRenderMode.Normal).Replace("&#39;", "\'").Replace("&#32;"," "));
}

Views/Web.config change:

To make the above available to Intellisense/auto-complete in Views you need to add a new entry in the Views/web.config file <namespaces> like this:

  <namespaces>
    ... [SNIP]  ...
    <add namespace="My.Lib.Name" />
  </namespaces>

Where My.Lib.Name is the namespace where you have placed the ActionLinkButtonHelper shown above.

Upvotes: 1

Related Questions