Including an anchor tag in an ASP.NET MVC Html.ActionLink
Asked Answered
P

7

156

In ASP.NET MVC, I'm trying to create a link that includes an anchor tag (that is, directing the user to a page, and a specific section of the page).

The URL I am trying to create should look like the following:

<a href="/category/subcategory/1#section12">Title for a section on the page</a>

My routing is set up with the standard:

routes.MapRoute("Default", "{controller}/{action}/{categoryid}"); 

The action link syntax that I am using is:

<%foreach (Category parent in ViewData.Model) { %>
<h3><%=parent.Name %></h3>
<ul>
<%foreach (Category child in parent.SubCategories) { %>
    <li><%=Html.ActionLink<CategoryController>(x => x.Subcategory(parent.ID), child.Name) %></li>
<%} %>
</ul>
<%} %>

My controller method is as follows:

public ActionResult Subcategory(int categoryID)
{
   //return itemList

   return View(itemList);
}

The above correctly returns a URL as follows:

<a href="/category/subcategory/1">Title for a section on the page</a>

I can't figure out how to add the #section12 part. The "section" word is just the convention I am using to break up the page sections, and the 12 is the ID of the subcategory, i.e., child.ID.

How can I do this?

Professional answered 8/11, 2008 at 10:10 Comment(0)
D
103

I would probably build the link manually, like this:

<a href="<%=Url.Action("Subcategory", "Category", new { categoryID = parent.ID }) %>#section12">link text</a>
Dermal answered 8/11, 2008 at 11:30 Comment(3)
Should really use the overloads for ActionLink as described by @Brad Wilson.Intentional
@Intentional sorry I disagree. KISS. Why have a member full of parameters , some of which are left as null, when you can simply state it explicitly. Anyone can see what the above means whereby Brad's response is convoluted and requires you to dig into intellisense. Too many parameters is a recognised anti pattern..c2.com/cgi/wiki?TooManyParametersModulate
I agree. Both methods work, but since the way fragments are specified in URLs isn't going to change in the near future, I think this way is actually more readable and clearer in its intent. If needed, you can still extend the Url or Html object with a custom method which includes a simple way to add a fragment string.Dermal
S
286

There are overloads of ActionLink which take a fragment parameter. Passing "section12" as your fragment will get you the behavior you're after.

For example, calling LinkExtensions.ActionLink Method (HtmlHelper, String, String, String, String, String, String, Object, Object):

<%= Html.ActionLink("Link Text", "Action", "Controller", null, null, "section12-the-anchor", new { categoryid = "blah"}, null) %>
Sixtynine answered 9/11, 2008 at 1:53 Comment(8)
Are these overloads part of an extensions library? I don't seem to get them.Including
There are two: public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, object routeValues, object htmlAttributes); public static string ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes);Sixtynine
The overloads of Html.ActionLink that allow specification of an anchor by passing the fragment, force you to pass the controller by name. I don't like that. If the controller name is incorrect, run-time exceptions will occur, rather than a compile errors.Panpipe
@BradWilson What about RedirectToAction support for anchors?Out
This doesn't work if your "Link Text" is more than just text, unfortunately.Ebert
@RobertMcKee if your link text is more than just text, then Html.ActionLink() wouldn't work in any scenario - you would need to use [email protected]() style syntax.Premedical
@R.Schreurs you can avoid this behaviour by passing null for the controller name, and it will default to the controller specified in the current route, solving that problemPremedical
@Premedical Correct, no implementation of Html.ActionLink would work, but using Url.Action like the accepted answer would, and .Net Core versions have a fragment overload too: learn.microsoft.com/en-us/dotnet/api/…Ebert
D
103

I would probably build the link manually, like this:

<a href="<%=Url.Action("Subcategory", "Category", new { categoryID = parent.ID }) %>#section12">link text</a>
Dermal answered 8/11, 2008 at 11:30 Comment(3)
Should really use the overloads for ActionLink as described by @Brad Wilson.Intentional
@Intentional sorry I disagree. KISS. Why have a member full of parameters , some of which are left as null, when you can simply state it explicitly. Anyone can see what the above means whereby Brad's response is convoluted and requires you to dig into intellisense. Too many parameters is a recognised anti pattern..c2.com/cgi/wiki?TooManyParametersModulate
I agree. Both methods work, but since the way fragments are specified in URLs isn't going to change in the near future, I think this way is actually more readable and clearer in its intent. If needed, you can still extend the Url or Html object with a custom method which includes a simple way to add a fragment string.Dermal
H
17

I don't remember in which version of ASP.NET MVC (ASP.NET MVC 3+ I believe) / Razor the parameterlabeldeclaration or whatever it's called (parameter: x) feature was introduced, but to me this is definitely the proper way to build a link with an anchor in ASP.NET MVC.

@Html.ActionLink("Some link text", "MyAction", "MyController", protocol: null, hostName: null, fragment: "MyAnchor", routeValues: null, htmlAttributes: null)

Not even Ed Blackburns antipattern argument from this answer can compete with that.

Hardback answered 28/9, 2014 at 18:52 Comment(1)
Literally this saved my life. Attributing your post as my solution here #32420528 .Backstroke
T
15

I just did it like this:

<a href="@Url.Action("Index","Home")#features">Features</a>
Towline answered 18/6, 2016 at 8:26 Comment(0)
S
1

Here is the real life example

@Html.Grid(Model).Columns(columns =>
    {
           columns.Add()
                   .Encoded(false)
                   .Sanitized(false)
                   .SetWidth(10)
                   .Titled(string.Empty)
                   .RenderValueAs(x => @Html.ActionLink("Edit", "UserDetails", "Membership", null, null, "discount", new { @id = @x.Id }, new { @target = "_blank" }));

  }).WithPaging(200).EmptyText("There Are No Items To Display")

And the target page has TABS

<ul id="myTab" class="nav nav-tabs" role="tablist">

        <li class="active"><a href="#discount" role="tab" data-toggle="tab">Discount</a></li>
    </ul>
Sternutation answered 2/12, 2014 at 12:28 Comment(0)
L
0

My solution will work if you apply the ActionFilter to the Subcategory action method, as long as you always want to redirect the user to the same bookmark:

http://spikehd.blogspot.com/2012/01/mvc3-redirect-action-to-html-bookmark.html

It modifies the HTML buffer and outputs a small piece of javascript to instruct the browser to append the bookmark.

You could modify the javascript to manually scroll, instead of using a bookmark in the URL, of course!

Hope it helps :)

Liatrice answered 19/1, 2012 at 11:2 Comment(0)
F
0

I Did that and it works for redirecting to other view I think If you add the #sectionLink after It will work

<a class="btn yellow" href="/users/Create/@Model.Id" target="_blank">
                                        Add As User
                                    </a>
Foolscap answered 12/3, 2016 at 10:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.