Convert HREF to RouteLink - asp.net-mvc

It seems to be simple, but I can't get anything to work. This code was generated by my template generator and needs to be changed.
<li><a href="../Home/Contact" class="active"><span class="l"></span><span class="r">
</span><span class="t">Nous contacter</span></a> </li>
My best bet up to now is:
<li><span class="l"></span><span class="r"></span>
#Html.RouteLink("Contact", new { Controller = "Home", Action = "Contact" }, new { #class = "t" })</li>
But it doesn't do anything.
Just to make sur that my question is clear: The link works in both cases, that's fine. The formating doesn't work. That's my issue here.

The second will generate:
<li>
<span class="l"></span>
<span class="r"></span>
<a class="t" href="/Home/Contact">Contact</a>
</li>
which is different than what you had in the first place which might explain the formatting problems:
<li>
<a href="../Home/Contact" class="active">
<span class="l"></span>
<span class="r"></span>
<span class="t">Nous contacter</span>
</a>
</li>
The problem with Html helpers such as Html.ActionLink and RouteLink is that they by always Html encode the text, so you cannot use HTML as text. So one possibility is the following:
<li>
<a href="#Url.RouteUrl("Contact", new { controller = "home", action = "contact" })" class="active">
<span class="l"></span>
<span class="r"></span>
<span class="t">Nous contacter</span>
</a>
</li>
Another possibility if you have lots of those to generate is to write a custom Html helper that will do the job for you:
public static class HtmlExtensions
{
public static IHtmlString MyLink(
this HtmlHelper htmlHelper,
string linkText,
string routeName,
object routeValues
)
{
var spans = string.Format(
"<span class=\"l\"></span><span class=\"r\"></span><span class=\"t\">{0}</span>",
htmlHelper.Encode(linkText)
);
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var url = urlHelper.RouteUrl(routeName, routeValues);
var anchor = new TagBuilder("a");
var rvd = new RouteValueDictionary(routeValues);
var rd = htmlHelper.ViewContext.RouteData;
var currentAction = rd.GetRequiredString("action");
var currentController = rd.GetRequiredString("controller");
var controller = rvd["controller"] as string;
var action = rvd["action"] as string;
if (string.Equals(controller, currentController, StringComparison.OrdinalIgnoreCase) &&
string.Equals(action, currentAction, StringComparison.OrdinalIgnoreCase))
{
anchor.AddCssClass("active");
}
anchor.Attributes["href"] = url;
anchor.InnerHtml = spans;
return new HtmlString(anchor.ToString());
}
}
and then:
<li>
#Html.MyLink("Nous contacter", "Contact", new { controller = "home", action = "contact" })
</li>

Just use something like this:
#Url.Action("Index", "Home")

Related

ASP.NET Actionlink with glyphicon and text with different font

I want to present a button with #Html.ActionLink but i need to have my application font in the text.
With this code:
<span>
#Html.ActionLink(" Create New", "Create", null, new { #class = "btn btn-warning glyphicon glyphicon-plus-sign" })
</span>
I get my button but the Create New text appears with the glyphicon font-family.
Putting the glyphicon classes in the span doesn't change anything
You should not add the glyphicon class to the a-tag.
From the Bootstrap website:
Don't mix with other components
Icon classes cannot be directly combined with other components. They should not be used along with other classes on the same element. Instead, add a nested <span> and apply the icon classes to the <span>.
Only for use on empty elements
Icon classes should only be used on elements that contain no text content and have no child elements.
In other words the correct HTML for this to work the way you want would be: test <span class="glyphicon glyphicon-plus-sign"></span>
This makes the Html.ActionLink helper unsuitable. Instead you could use something like:
<a href="#Url.Action("Action", "Controller")" class="btn btn-warning">
link text
<span class="glyphicon glyphicon-plus-sign" aria-hidden="true"></span>
</a>
This works for me in MVC 5:
#Html.ActionLink(" ", "EditResources", "NicheSites", new { ViewBag.dbc, item.locale, ViewBag.domainId, domainName = ViewBag.domaiName }, new {#class= "glyphicon glyphicon-edit" })
The first parameter cannot be empty or null or it will blow.
It might be better to just write out the HTML rather than try to make it work with HtmlHelper.ActionLink...
<span>
<a href="#Url.Action("Create")" class="btn btn-warning">
<span class="glyphicon glyphicon-plus-sign"></span>
Create New
</a>
</span>
Here's mine. Inspired by Andrey Burykin
public static class BensHtmlHelpers
{
public static MvcHtmlString IconLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, String iconName, object htmlAttributes = null)
{
var linkMarkup = htmlHelper.ActionLink(linkText, actionName, routeValues, htmlAttributes).ToHtmlString();
var iconMarkup = String.Format("<span class=\"{0}\" aria-hidden=\"true\"></span>", iconName);
return new MvcHtmlString(linkMarkup.Insert(linkMarkup.IndexOf(#"</a>"), iconMarkup));
}
}
I should go with the approach of #Url.Action instead of #Html.ActionLink, se example code below:
<span>
<span class="glyphicon glyphicon-plus-sign"></span> Create New
</span>
You can use simple extension:
private static readonly String SPAN_FORMAT = "<span class=\"{0}\" aria-hidden=\"true\"></span>";
private static readonly String A_END = "</a>";
public static MvcHtmlString ActionLink(this HtmlHelper htmlHelper, string linkText, string actionName, object routeValues, String iconName, object htmlAttributes = null)
{
var linkMarkup = htmlHelper.ActionLink(linkText, actionName, routeValues, htmlAttributes).ToHtmlString();
if (!linkMarkup.EndsWith(A_END))
throw new ArgumentException();
var iconMarkup = String.Format(SPAN_FORMAT, iconName);
return new MvcHtmlString(linkMarkup.Insert(linkMarkup.Length - A_END.Length, iconMarkup));
}
Usage:
Html.ActionLink(" ", "DeleteChart", new { Id = _.Id }, "glyphicon glyphicon-trash")
Try it!
#Html.ActionLink(" Cerrar sesiĆ³n", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" , #class = "glyphicon glyphicon-log-in" })
Let's have a try on this. Let me know if it is working .Thanks
<style>
span.super a
{
font: (your application font) !important;
}
</style>
<span class="super">
#Html.ActionLink(" Create New", "Create", null, new { #class = "btn btn-warning glyphicon glyphicon-plus-sign" })
</span>
How about using Html.BeginForm with a FormMethod.Get / FormMethod.Post
#using (Html.BeginForm("Action", "Controller", new { Area = "" },
FormMethod.Get, htmlAttributes: new { title = "SomeTitle" }))
{
<button type="submit" class="btn-link" role="menuitem">
<i class="glyphicon glyphicon-plus-sign"></i>Create New</button>
}
Try this. Worked for me.
<button class="btn btn-primary"><i class ="fa fa-plus">#Html.ActionLink(" ", "Create", "Home")</i></button>

Image button in ActionLink MVC

How to put image instead text in ActionLink button:
#Html.ActionLink("Edit-link", "Edit", new { id=use.userID })
So how to change text "Edit-link" to image?
Thanks for any idea.
do like this:
<a href="#Url.Action("Edit")" id="#use.userID">
<img src="#Url.Content("~/images/someimage.png")" />
</a>
or pass both action and controller name by using other override:
<a href="#Url.Action("Edit","Controller")" id="#use.userID">
<img src="#Url.Content("~/images/someimage.png")" />
</a>
UPDATE:
You can also create a custom Html Helper, and can reuse it in any View in application:
namespace MyApplication.Helpers
{
public static class CustomHtmlHelepers
{
public static IHtmlString ImageActionLink(this HtmlHelper htmlHelper, string linkText, string action, string controller, object routeValues, object htmlAttributes,string imageSrc)
{
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var img = new TagBuilder("img");
img.Attributes.Add("src", VirtualPathUtility.ToAbsolute(imageSrc));
var anchor = new TagBuilder("a") { InnerHtml = img.ToString(TagRenderMode.SelfClosing) };
anchor.Attributes["href"] = urlHelper.Action(action, controller, routeValues);
anchor.MergeAttributes(new RouteValueDictionary(htmlAttributes));
return MvcHtmlString.Create(anchor.ToString());
}
}
}
and use it in View:
#using MyApplication.Helpers;
#Html.ImageActionLink("LinkText","ActionName","ControllerName",null,null,"~/images/untitled.png")
Output HTML:
<a href="/ControllerName/ActionName">
<img src="/images/untitled.png">
</a>
Try this code :
#Html.Raw(#Html.ActionLink("Edit-link","Edit", new { id=use.userID }).ToHtmlString().Replace("Edit-link", "<img src=\"/Contents/img/logo.png\" ... />"))
or
<a href="#Url.Action("Edit Link","Edit",new {id = item.EId })">
<img src="#Url.Content("~/img/iconfinder_new-24_103173.png")" style="height:20px;width:20px;color:blue" title="Edit" />
</a>
Try this code. It will add an image linked to the Edit() action with the id set.

MVC with Bootstrap Navbar - Set Selected Item to Active

I'm learning Bootstrap and can't get the selected item into an "active" state. The active state remains on the default item. The newly selected/clicked item changes to active briefly, but reverts back. I've read all the posts and still can't get this code to work. I'm using MVC5 and JQuery 2.1.
EDIT:
If I change the li's hrefs to href="#", then the active class gets applied properly. What's happening when a new view gets loaded? I think Sebastian's response is close, but gets messy with Areas.
Markup
<div class="navbar-wrapper">
<div class="container">
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-header">
<a class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="navbar-brand" href="#">Test</a>
</div>
<div class="btn-group pull-right">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
<i class="icon-user"></i>Login
<span class="caret"></span>
</a>
<ul class="dropdown-menu">
<li>Profile</li>
<li class="divider"></li>
<li>Sign Out</li>
</ul>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active">Home</li>
<li>About</li>
<li>Students Sample</li>
<li class="dropdown">
Dropdown <b class="caret"></b>
<ul class="dropdown-menu">
<li>Admin</li>
<li>Another action</li>
<li>Something else here</li>
<li class="divider"></li>
<li>Separated link</li>
<li>One more separated link</li>
</ul>
</li>
</ul>
</div>
</div>
</div>
<!-- /container -->
</div>
<!-- /navbar wrapper -->
Script
<script type="text/javascript">
$(function () {
$('.navbar-nav li').click(function () {
$(this).addClass('active').siblings().removeClass('active');
});
});
</script>
EDIT: Here's what I ended up doing with the help of the posted answers and some research.
public static string MakeActive(this UrlHelper urlHelper,string action, string controller, string area = "")
{
string result = "active";
string requestContextRoute;
string passedInRoute;
// Get the route values from the request
var sb = new StringBuilder().Append(urlHelper.RequestContext.RouteData.DataTokens["area"]);
sb.Append("/");
sb.Append(urlHelper.RequestContext.RouteData.Values["controller"].ToString());
sb.Append("/");
sb.Append(urlHelper.RequestContext.RouteData.Values["action"].ToString());
requestContextRoute = sb.ToString();
if (string.IsNullOrWhiteSpace(area))
{
passedInRoute = "/" + controller + "/" + action;
}
else
{
passedInRoute = area + "/" + controller + "/" + action;
}
// Are the 2 routes the same?
if (!requestContextRoute.Equals(passedInRoute, StringComparison.OrdinalIgnoreCase))
{
result = null;
}
return result;
}
You have to check in your controller or view which menu item is active based on the current url:
I have an extension method similar to this:
public static string MakeActiveClass(this UrlHelper urlHelper, string controller)
{
string result = "active";
string controllerName = urlHelper.RequestContext.RouteData.Values["controller"].ToString();
if (!controllerName.Equals(controller, StringComparison.OrdinalIgnoreCase))
{
result = null;
}
return result;
}
You can use it in your view like this:
<!-- Make the list item active when the current controller is equal to "blog" -->
<li class="#Url.MakeActive("blog")">
....
</li>
The JavaScript isn't working because the page is getting reloaded after it runs. So it correctly sets the active item and then the page loads because the browser is following the link. Personally, I would remove the JavaScript you have because it serves no purpose. To do this client side (instead of the server side code you have), you need JavaScript to set the active item when the new page loads. Something like:
$(document).ready(function() {
$('ul.nav.navbar-nav').find('a[href="' + location.pathname + '"]')
.closest('li').addClass('active');
});
I recommend adding an id or other class to your navbar so you can be sure you have selected the correct one.
Simplest thing to do is send a ViewBag parameter from your controllers like following;
public ActionResult About()
{
ViewBag.Current = "About";
return View();
}
public ActionResult Contact()
{
ViewBag.Current = "Contact";
return View();
}
In the cshtml page do the following;
<ul class="nav navbar-nav">
<li class="#(ViewBag.Current == "About" ? "active" : "")">#Html.ActionLink("About", "About", "Home")</li>
<li class="#(ViewBag.Current == "Contact" ? "active" : "")">#Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
Courtesy to #Damith in here
Simply you can do this in any view
<ul class="nav navbar-nav">
#Html.NavigationLink("Link1", "Index", "Home")
#Html.NavigationLink("Link2", "Index", "Home")
#Html.NavigationLink("Link3", "Index", "Home")
#Html.NavigationLink("Links with Parameter", "myAction", "MyController", new{ id=999}, new { #class= " icon-next" })
</ul>
After you add this method to a new class or existing HtmlExtensions class
public static class HtmlExtensions
{
public static MvcHtmlString NavigationLink(this HtmlHelper html, string linkText, string action, string controller, object routeValues=null, object css=null)
{
TagBuilder aTag = new TagBuilder("a");
TagBuilder liTag = new TagBuilder("li");
var htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(css);
string url = (routeValues == null)?
(new UrlHelper(html.ViewContext.RequestContext)).Action(action, controller)
:(new UrlHelper(html.ViewContext.RequestContext)).Action(action, controller, routeValues);
aTag.MergeAttribute("href", url);
aTag.InnerHtml = linkText;
aTag.MergeAttributes(htmlAttributes);
if (action.ToLower() == html.ViewContext.RouteData.Values["action"].ToString().ToLower() && controller.ToLower() == html.ViewContext.RouteData.Values["controller"].ToString().ToLower())
liTag.MergeAttribute("class","active");
liTag.InnerHtml = aTag.ToString(TagRenderMode.Normal);
return new MvcHtmlString(liTag.ToString(TagRenderMode.Normal));
}
}
I believe you have the selection backward. You're adding the class, then removing it from the siblings, and I think doing the remove second is causing the issue. Can you try reversing this to be:
<script type="text/javascript">
$(function () {
$('.navbar-nav li').click(function () {
$(this).siblings().removeClass('active');
$(this).addClass('active');
});
});
</script>
Your javascript function should work fine... The issue is that your links route to a controller and reload the entire page. In order to avoid this behavior you could render your body content as a partial view, that way the navbar elements do not reload. You shouldn't have to write a function to handle dom events - that is what javascript is for.
To see what I mean, change your code:
<li>About</li>
<li>Students Sample</li>
to:
<li>About</li>
<li>Students Sample</li>
Just add this JQuery coded :
<script>
$(document).ready(function () {
$('body').find('a[href="' + location.pathname + '"]')
.addClass('active');
});
</script>
With this simplified version of the code from here, you can use a tag helper to mark the anchor 'active' if the controller & action match (or just the controller if no action is supplied).
The nav:
<li class="nav-item px-2">
<a class="nav-link" asp-active-route asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item px-2">
<a class="nav-link" asp-active-route asp-controller="Car" asp-action="Add">Add Car</a>
</li>
The tag helper class
[HtmlTargetElement(Attributes = "asp-active-route")]
public class ActiveRouteTagHelper : TagHelper
{
[HtmlAttributeName("asp-controller")] public string Controller { get; set; }
[HtmlAttributeName("asp-action")] public string Action { get; set; }
[HtmlAttributeNotBound] [ViewContext] public ViewContext ViewContext { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
if (IsActive())
{
output.AddClass("active", HtmlEncoder.Default);
}
output.Attributes.RemoveAll("asp-active-route");
base.Process(context, output);
}
private bool IsActive()
{
var currentController = ViewContext.RouteData.Values["Controller"].ToString();
var currentAction = ViewContext.RouteData.Values["Action"].ToString();
var active = false;
if (!string.IsNullOrWhiteSpace(Controller) && !string.IsNullOrWhiteSpace(currentController))
{
active = Controller.Equals(currentController, StringComparison.CurrentCultureIgnoreCase);
if (active && !string.IsNullOrWhiteSpace(Action) && !string.IsNullOrWhiteSpace(currentAction))
{
active = Action.Equals(currentAction, StringComparison.CurrentCultureIgnoreCase);
}
}
return active;
}
}
Don't forget to add the tag helper to your _ViewImports.cshtml
#addTagHelper *, My.Awesome.Web
Future improvement would be to also check areas and possibly wrap the entire nav in a control/helper so you only have to compare the routes once and flag the item
You can use Bootstrap's nav-pills to change the color of active menu item.
Bootstrap's nav-pills to change the color of active menu item
Here is a simple solution that works - store class name in TempData:
In each action of the controller add one line:
// add "active" class to nav-item TempData["Home"] = "active";
In Layout view nav item:
<a class="nav-link #TempData["Home"]">Home</a>
Thus only one nav-item will get class "active"

asp.net mvc set parent element class from ActionLink helper

I have the following menu:
<ul class="nav nav-tabs nav-stacked">
<li class="nav-header">Navigation Menu</li>
<li>#Html.MenuLink("Test Link", "Index", "Home", "active",true)</li>
MenuLink is a helper that sets a class to the ActionLink (href) element:
public static HtmlString MenuLink(this HtmlHelper htmlHelper, string linkText, string actionName, string controllerName, string activeClass, bool checkAction)
{
string currentAction = htmlHelper.ViewContext.RouteData.GetRequiredString("action");
string currentController = htmlHelper.ViewContext.RouteData.GetRequiredString("controller");
if (string.Compare(controllerName, currentController, StringComparison.OrdinalIgnoreCase) == 0 && ((!checkAction) || string.Compare(actionName, currentAction, StringComparison.OrdinalIgnoreCase) == 0))
{
return htmlHelper.ActionLink(linkText, actionName, controllerName, null, new { #class = activeClass });
}
return htmlHelper.ActionLink(linkText, actionName, controllerName);
}
What I need is to set the class attribute to the parent HTML element, in this case the <li> element, so the final result would be:
<ul class="nav nav-tabs nav-stacked">
<li class="nav-header">Navigation Menu</li>
<li class="active"><href="....."></li>
instead of the actual result:
<ul class="nav nav-tabs nav-stacked">
<li class="nav-header">Navigation Menu</li>
<li><href="....." class="active"></li>
Any clue, any advise is appreciated.
Thanks.
Instead of the MenuLink helper you can simply use the #Url helper like this:
<li class="active">
<href="#Url.Action("Index", "Home")">
</li>
and write your custom Helper only to generate the result for class name (e.g. active )
so the final code would look something like this:
<li class="#Html.YourCustomHelperForActiveTab("Index","Home")" >
<href="#Url.Action("Index", "Home")">
</li>
UPDATE: it might also be helpful to some people to mention that an example helper for getting the class for each tab could be like this: (Source)
public static string ActiveTab(this HtmlHelper helper, string activeController, string[] activeActions, string cssClass)
{
string currentAction = helper.ViewContext.Controller.
ValueProvider.GetValue("action").RawValue.ToString();
string currentController = helper.ViewContext.Controller.
ValueProvider.GetValue("controller").RawValue.ToString();
string cssClassToUse = currentController == activeController
&& activeActions.Contains(currentAction)
? cssClass
: string.Empty;
return cssClassToUse;
}

How to work with Action Link when using CSS

<li class="rtsLI" id="Summary"><span class="rtsTxt">Test</span></li>
Above I am replacing with following actionlink:
<li class="rtsLI" >#Html.ActionLink("test1", "Index", new { Area = "Area1", Controller = "controller1" }, new { #class = "rtsLink rtsTxt"})</li> "
At first css is working fine. But when using Actionlink, css not working. Thanks
The standard ActionLink helper always HTML encodes the link text. This means that you cannot use it if you want to render HTML inside. You have 3 possibilities:
Modify your CSS so that you don't need a span inside the link and so that the rtsTxt class could directly be applied to the link
Write a custom ActionLink helper that doesn't HTML encode the text and which would allow you to generate the same markup:
public static class ActionLinkExtensions
{
public static IHtmlString ActionLinkUnencoded(
this HtmlHelper htmlHelper,
string linkText,
string actionName,
object routeValues,
object htmlAttributes
)
{
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
var link = new TagBuilder("a");
link.MergeAttributes(new RouteValueDictionary(htmlAttributes));
link.Attributes["href"] = urlHelper.Action(actionName, routeValues);
link.InnerHtml = linkText;
return new HtmlString(link.ToString());
}
}
and then:
<li>
#Html.ActionLinkUnencoded(
"<span class=\"rtsTxt\">User Security</span>",
"index",
new { area = "Tools", controller = "UserSecurity" },
new { #class = "rtsLink" }
)
</li>
Use the Url.Action helper:
<li class="rtsLI">
<a href="#Url.Action("index", new { area = "Tools", controller = "UserSecurity" })" class="rtsLink">
<span class="rtsTxt">User Security</span>
</a>
</li>
Best option will be to use #Url.Action extension method
<li class="rtsLI" id="Summary"><span class="rtsTxt">User Security</span></li>
Write code this way:
<li class="rtsLI" >#Html.ActionLink("<span class='rtsTxt'>User Security</span>", "Index", new { Area = "Tools", Controller = "UserSecurity" }, new { #class = "rtsLink"})</li>`

Resources