I am using Web Forms Routing in ASP.NET 4 and I am trying to route to a specific location on a page. On that page I have an element like <div id="3"> and I'd like to jump to this anchor from another page. For this purpose I have defined a Route in global.asax:
RouteTable.Routes.MapPageRoute("MyRoute", "Path/SubPath/{PageAnchor}",
"~/MyPage.aspx", true, new RouteValueDictionary { { "PageAnchor", null } });
The HyperLink to link to that page and the anchor "3" is defined this way in markup:
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="<%$ RouteUrl:RouteName=MyRoute,PageAnchor=#3 %>">
Link</asp:HyperLink>
The problem with the generated link is that the # character in the URL gets encoded by %23 this way: http://localhost:1234/Path/SubPath/%233 so that I reach the target page but not at the specified anchor.
Is there a way to avoid this unwished URL-encoding? Or any other way to route to an anchor?
Thank you in advance!
Anchors are not supported with ASP.NET's routing feature. Routing is designed to support only the part of the URL after the application's path and before the anchor.
I suggest adding an event handler (e.g. Page_Load) and in that event handler generate the URL, append the anchor, and set the value on the HyperLink control.
Of course, in most cases with Web Forms routing it's easiest to just set the URL manually to whatever you want. This is a nice option when the URL is not complex and is unlikely to change.
Does this work?
RouteTable.Routes.MapPageRoute("MyRoute", "Path/SubPath/#{PageAnchor}",
"~/MyPage.aspx", true, new RouteValueDictionary { { "PageAnchor", null } })
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="<%$ RouteUrl:RouteName=MyRoute,PageAnchor=3 %>">
Link</asp:HyperLink>
If you place the # outside of the PageAnchor placeholder, you could avoid that value being decoded, and it seems like a cleaner way to do it, besides.
How about the route goes to a controller and that reroutes to the page with the anchor parameter?
I know this is an old question, but maybe someone else could benefit from this approach.
Create a route without the anchor.
RouteTable.Routes.MapPageRoute("MyRoute", "Path/SubPath", "~/MyPage.aspx");
And then construct the url like this, appending the anchor.
Link
Related
I have a hyperlink that in certain cases I want to change to show a jquery popup, but I'm having a strange problem when doing it on a master page. The following works in a regular page:
hyp1.NavigateUrl = "#notificationPopup";
Which renders as:
<a id="ctl00_hyp1" href="#notificationPopup">Example</a>
This is exactly what I want. The problem is with the exact same code on a hyperlink on the master page it renders as:
<a id="ctl00_hyp1" href="../MasterPages/#notificationPopup">Example</a>
It looks like it might be running the navigateUrl through ResolveClientUrl() or something when I'm setting it on the master page. I've tried swapping the <asp:hyperlink for a <a href runat=server, but the same thing happens.
Any ideas?
There is a note on MSDN Control.ResolveClientUrl method description.
The URL returned by this method is
relative to the folder containing the
source file in which the control is
instantiated. Controls that inherit
this property, such as UserControl and
MasterPage, will return a fully
qualified URL relative to the control.
So the behavior of master page in your exampe is fully predictable (although this is not a very comfortable to work with). So what are the alternatives?
The best one is to set the <a> as a client control (remove runat="server"); should work like a charm even in a master page:
Example
In the case if this control should be server side only: you could just build an URL from your code behind by using UriBuilder class:
UriBuilder newPath = new UriBuilder(Request.Url);
// this will add a #notificationPopup fragment to the current URL
newPath.Fragment = "notificationPopup";
hyp1.HRef = newPath.Uri.ToString();
Create a hidden field on your form and set the value to where you want to navigate / the url of the hyperlink instead of the hyperlinks navigate url. Then call the onclick method of the hyperlink in javascript and set the hyperlink there before the browser does the actual navigation.
<html><head><title></title></head>
<script type="text/javascript">
function navHyperlink(field)
{
field.href = document.getElementById('ctl00_hdnHypNav').value;
return true;
}
</script>
<input type="hidden" id="hdnHypNav" value="test2.html" runat="server"/>
<a href="" onclick="navHyperlink(this);" >click here</a>
</html>
Code behind would be:
hdnHypNav.value = "#notificationPopup";
You could also just try setting the url after the postback with below code, i.e. replace your code behind line with this one but I am not sure if it will work...
ScriptManager.RegisterStartupScript(this,this.GetType(),"SetHyp","$('ctl00_hyp1').href = '#notificationPopup';",True)
I found another way to solve the problem.
hyp1.Attributes.Add("href", "#notificationPopup");
Seeing as the whole reason I replaced my static hyperlink with a runat="server" one was to benefit from automatic resource-based localization, none of these answers served my needs.
My fix was to enclose the hyperlink in a literal:
<asp:Literal ID="lit1" runat="server" meta:resourcekey="lit1">
Example
</asp:Literal>
The downside is if you need to programmatically manipulate the link, it's a bit more annoying:
lit1.Text = String.Format("Example", HttpUtility.HtmlAttributeEncode(url));
I'd like to be able to turn rows of an html table into links to controllers.
I figured something like
<td onclick="<%:Html.ActionLink("", "Index", new {id=item.user_id}) %>">
I'm using MVC 2
Thanks.
<td onclick="window.location='<%:Url.Action("Index", new {id=item.user_id}) %>'">
The onclick attribute accepts some javascript code to execute. If you simply give it a URL, javascript doesn't know what to do with that.
In the snippet above, you're setting the window.location property to the desired URL. This causes the browser to go there.
EDIT: I also just realized that you were using the Html.ActionLink() method which actually generates an tag in your code. You'd be better off using the Url.Action() method, which actually generates a URL.
I have my UserControls in a ~/Controls folder in my solution:
/Controls/TheControl.ascx
If specify the following:
<a id="theId" runat="server" href="./?pg=1">link text</a>
ASP.Net seems to want to rewrite the path to point to the absolute location. For example, If the control is on site.com/products/fish/cans.aspx the link href will be rewritten to read
<a id="munged_theId" href="../../Controls/?pg=1>link text</a>
Why does Asp.Net rewrite these control paths, and is there an elegant way to fix it?
I just want the anchor control to spit out exactly what I tell it to!!! Is that so hard?
EDIT:
I've basically done what Kelsey suggested. I knew I could do it this way, but I don't like adding markup in my code when I want something relatively simple. At least it solves the problem:
Aspx page:
<asp:PlaceHolder ID="ph" runat="server"></asp:PlaceHolder>
Code-behind:
var anchor = new HtmlGenericControl("a") { InnerText = "Previous" + " " + PageSize) };
anchor.Attributes["href"] = "?pg=" + (CurrentPage - 1);
anchor.Attributes["class"] = "prev button";
ph.Controls.Clear();
ph.Controls.Add(anchor);
As you can see by the amount of code needed for what is essentially supposed to be be a simple and light-weight anchor, it's not the most optimal solution. I know I could use a Literal but I figured this was cleaner as I'm adding more than one anchor.
I would be interesting in knowing WHY ASP.Net takes over and tries to fix my URL, though.
Why do you have runat="server" and no ID defined? Do you need to access it server side? If you remove the runat="server" everything will work as expected.
For more information regardinging how ASP.NET handles paths check out this MSDN article.
Edit: You can get around the problem then by using a Literal control and then outputing the raw <a href... to it.
Eg:
<asp:Literal ID="myLiteral" runat="server" />
myLiteral.Text = "link text";
Then you can set the visible property on the Literal however you want.
I know this is a bit of an old topic, but I was running into this problem as well and in the end went with a similar solution, but was able to save a few lines of code by doing this in the ascx:
<anchor id="myAnchor" runat="server" href="xxx">link text</anchor>
Then in the code behind, I referenced it using an HtmlGenericControl and can then do this:
myAnchor.TagName = "a";
// other properties set as needed
Anyway, I thought I'd post in case anyone else stumbles in here with the same issue.
Best bet is to make everything app root relative using the magic ~/ lead-in to the url. That tends to keep stuff straight.
There isn't a great answer to your question. ASP.NET is going to treat a relative path in a UserControl as relative to the path of the user control.
What you can do is in the code behind for your user control, set the HRef property of your anchor tag based on the Request.Path property. Then you can create URLs relative to the page.
Alternative is to use a literal like Kelsey was suggestion, or I would just try and map everything app relative with ~/ like Wyatt suggested.
Even a literal doesn't work using ICallBackEventHandler and RenderControl at least... I ended up hacking the tag back client-side :/ e.g in JQuery:
$('#munged_theId').attr('href', './?pg=1');
My application paths …
<a runat="server" href="~/Home">
…are resolving to “Home” (not “/Home”). After I rewrite URLs, “/Blah/Blah”, all the ”~/” links are relative to the rewrite: /Blah/Home
Is there a way to force a root to “/”?
Why don't you just write the links relative to the root ('/') instead of '~/', if you're application is not at the root of the domain, then the '~/' links will resolve to the root of the application
If you're sure that, for the links in question you'll always be at a root of "/", then the simplest thing to do is change the <a> so that the href reads "/Home" rather than "~/Home" ... That way asp.net won't parse it and change it to use the App/VDir as its starting point.
If you use standard HTML tags like a, then include the url via
...
or use asp.net hyperlinks:
<asp:Hyperlink NavigateUrl="~/Home" runat="server" ID="HomeLink" Text="..." />
That way, all links will point to the right URL, even when the web application will be installed in a subdirectory.
<% %> is inline coding for asp.net, and <%= %> outputs the content, in that case the result of ResolveUrl.
~/ gets translated in the web controls, as in not Otherwise, you need to use ResolveClientUrl to do that.
For the hyperlink control, it will automatically map correctly for you.
It seems everyone is doing this (in code posts etc.)...but I don't know how. :(
Whenever I try to manipulate an asp element using JavaScript I get an "element is null" or "document is undefined" etc. error.....
JavaScript works fine usually,...but only when I add the runat="server" attribute does the element seem invisible to my JavaScript.
Any suggestions would be appreciated.
Thanks, Andrew
What's probably happening is that your element/control is within one or more ASP.NET controls which act as naming containers (Master page, ITemplate, Wizard, etc), and that's causing its ID to change.
You can use "view source" in your browser to confirm that's what's happening in the rendered HTML.
If your JavaScript is in the ASPX page, the easiest way to temporarily work around that is to use the element's ClientID property. For example, if you had a control named TextBox1 that you wanted to reference via JS:
var textbox = document.getElementById('<%= TextBox1.ClientID %>');
Making an element runat="server" changes the client-side ID of that element based on what ASP.NET naming containers it's inside of. So if you're using document.getElementById to manipulate the element, you'll need to pass it the new ID generated by .NET. Look into the ClientId property to get that generated ID...you can use it inline in your Javascript like so:
var element = document.getElementById('<%=myControl.ClientID%>');
If you have a textbox:
<asp:TextBox id="txtText" runat="server" />
YOu can use:
var textBox=document.getElementById('<%=txtText.ClientID %>');
Any WebControl exposes the same ClientID property.
All though the question has been answered, thought I would just post some further info...
Rick Strahl provided quite an intresting work around to this problem.
http://www.west-wind.com/WebLog/posts/252178.aspx
Thankfully when ASP .NET 4.0 arrives, it will allow you to specify exacly what the client ID's will be!
http://www.codeproject.com/KB/aspnet/ASP_NET4_0ClientIDFeature.aspx