No output from Html.ActionLink when trying to check Controller name - asp.net-mvc-3

This is probably a simple oversight but I'm not seeing the problem so I thought I'd ask for some quick help. I'm somewhat new to MVC also (and Razor) so that might have something to do with it also. Basically, here's what's in my Razor View that renders some list items for a navigation bar. I'm just trying to set a class of "selected" on the element if (according to the Controller name) it's the page being requested.
<li>#{ if(Html.ViewContext.RouteData.Values["controller"].ToString() == "AdminHome")
{
Html.ActionLink("Admin Home", "Index", "AdminHome", null, new { #class = "selected" });
}
else{
Html.ActionLink("Admin Home", "Index", "AdminHome");
}
}
</li>
The result I'm getting is just an empty list item element: <li></li>
Any ideas what I'm doing wrong? Is it just a syntax issue?

You need to prefix # before Html.ActionLink. Otherwise MVC treats this as a ordinary method call not a method that outputs html.
<li>
#if(Html.ViewContext.RouteData.Values["controller"].ToString() == "AdminHome"){
#Html.ActionLink("Admin Home", "Index", "AdminHome", null, new { #class = "selected" });
}
else{
#Html.ActionLink("Admin Home", "Index", "AdminHome");
}
</li>

compare the route name in case insensitve like
String.Equals(Html.ViewContext.RouteData.Values["controller"].ToString() , "AdminHome",,StringComparison.CurrentCultureIgnoreCase)
because route name can be in any case. It is what user has typed in url.
For example in url
www.yourdomain.com/AdminHome/Index (controller name is AdminHome and controller will be AdminHomeController)
but with url
www.yourdomain.com/adminhome/index (controller name is adminhome and controller will be AdminHomeController)
Hope this helps.

Related

Helpers and action links in ASP.net MVC 3

So I am having a weird issue with a helper I created:
#if (Model != null)
{
<ul>
#foreach (var item in Model)
{
<li>
#Html.ActionLink(item.name, "Map", "Home", new { id = item.id }, null)
</li>
}
</ul>
}
else
{
<p><strong>ATTN!!</strong> We could not find any locations.</p>
}
When when rendered into the view, throws the following error upon running:
CS1973: 'System.Web.Mvc.HtmlHelper' has no applicable method named 'ActionLink' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.
This happens on my action link.
I have seen other partials use action links, some with [] around the action links other with out. What am I doing wrong?
You have to cast item.name to a string, by the way if you don't use the htmlAttributes parameter, leave it instead of putting null for cleaner code

Why is my textBoxFor using my route data?

So I have these three lines:
<div style="background-color: lightgreen;">#Html.TextBoxFor(m => m.Id)</div>
<div style="background-color: green;">#Html.DisplayTextFor(m => m.Id)</div>
<div style="background-color: pink;">#Model.Id</div>
I've identified that the lightgreen value is not my Model.Id but the Id that is set by my route:
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "MyFunController", action = "Index", id = UrlParameter.Optional });
I've come accross some explanations here:
http://forums.asp.net/t/1792086.aspx/1
http://www.hanselman.com/blog/TheWeeklySourceCode38ASPNETMVCBetaObscurityModelStateIsValidIsFalseBecauseModelBinderPullsValuesFromRouteData.aspx
http://ayende.com/blog/3683/reproducing-a-bug
But they have all left me on my appetite. I'm looking for a smart way to work around this, I don't want to change my model's property names nor do I want to change the name of the route item. If I do it will represent a lot of work for me and is not ideal.
I'm sure I'm not the only one with this issue?
(This is MVC 4)
Thanks!
You could remove the problematic value from the ModelState (which is where the Html helpers are taking it from) in the controller action that is rendering the view:
public ActionResult SomeAction(int id)
{
ModelState.Remove("Id");
MyViewModel model = ...
return View(model);
}
Now it's the Id property of your view model that's gonna get used by the TextBox and not the one coming from the route.
Obviously that's only an ugly horrible workaround. The correct way is to of course properly define your view models so that you do not have such naming collisions.

Basic MVC routing query using default project template

I am in the process of learning MVC 3 using the basic project template coupled with several examples I have. Things are going well, but now I am trying to implement my controllers and I am having a couple of issues.
So far I have modified the _Layout.cshtml file to have a new link with a specified route defined:
<header>
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay">
#Html.Partial("_LogOnPartial")
</div>
<nav>
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.RouteLink("Contracts", "Contract")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
</ul>
</nav>
</header>
and my global.asax.cs file is as follows:
routes.MapRoute(
"Contract",
"Contract",
new { controller = "Contract", action = "List", id = UrlParameter.Optional }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
This works fine as in it returns the expected action view from my Contract controller.
However I would like to modify this to accept an id into the List action. I know that I need to change the List method to accept a parameter, no problem there, but the issue it with the route and how to pass this paramter into the List method from the RouteLink in the _Layout.cshtml file. I have tried a few things, but this bit is really stumping me.
I intend to pass an id from the User that I logged in as through the AccountController, however I will ask another question about that to keep this more consise.
Thank you very much.
You don't actually need your Contract route, as your Default route will work for any controller and action that corresponds to the pattern controller/action/(optional id parameter here). See the comment in the template actually says Parameter defaults. This means, if there is no Controller, Action, or id passed in, it will default to those values. That's why you can just browse to the root of the website and the Home controller's Index action is the default call.
When using routes, you need to remember that the route parameter names need to match the parameter names in your actions.. for example, your Default route currently lets you do this:
[HttpGet]
public ActionResult MyAction(int id) {
}
But, if you changed your default route to be this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{myIDParameter}", // URL with parameters
new { controller = "Home", action = "Index", myIDParameter = UrlParameter.Optional } // Parameter defaults
);
..your Index action would no longer bind the integer parameter properly.. you would have to change the action to this:
[HttpGet]
public ActionResult MyAction(int myIDParameter) {
}
In answer to your question, it might make more sense to use an ActionLink, like the other two you already have:
#Html.ActionLink("Contracts", "Contract", "ActionMethodHere", new { id = UserIdHere }, null)
That assumes though, that you remove your Contract route and just use the default route.

Html.ActionLink equivalent of a specific URL format

I want to use Html.ActionLink to return an anchor tag with href like /Product/22/Product-Name, where Product is my controller name and 22 is my id and Product-Name is my title.
In my global.asax, I have set the following route :
routes.MapRoute(
"ProductRoute", // Route name
"Product/{id}/{title}", // URL with parameters
new { controller = "Product", action = "Index", id = UrlParameter.Optional });
I tried using following code
#Html.ActionLink(model.Name, null, "Product",
new { id = model.Id, title = model.Name.Replace(" ","-") }, null)
but it yields Product/Browse/22?title=Product-Name. This code is in Browse View returned by Browse action of Catalog controller and that's why it picks up the Browse in between.
Strangely, the same code works fine in the Index View returned by Index action of the Home Controller. What's the reason for this difference? . Am I missing something or this is a bug in Asp.net MVC3.
What Should I do to achieve my stated URL format. For the meantime, I am using this code
#product.Name
make sure you have defined the custom route before the default route and try
#Html.ActionLink(model.Name,
"Index",
new {controller="Product", id = model.Id, title = model.Name.Replace(" ","-") }, null)
the first parameter is the DisplayName, second the ActionResult's name and then the RouteValues

Mvc3 implement custom action link

I have .net mvc3 web site. And i must to implement top menu. Each of the menu tags is lead to his action and display another view.This what i have now:
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("Products", "Products", "Home")</li>
<li>#Html.ActionLink("Pricing", "Pricing", "Home")</li>
<li>#Html.ActionLink("Our Team", "OurTeam", "Home")</li>
<li>#Html.ActionLink("Contact Us", "ContactUs", "Home")</li>
</ul><!-- /menu -->
This view is Html.RenderAction("Header", "Home"); in my layout(because it must to appear in all pages)
I need to implement Custom ActionLink. The anchor text must be:
<span>text</span><b>text</b>
The "text" is Home(for example of first li)
And the current ActionLink must add class :"Selected" to the anchor.
How i can do this? Help please
p.s
I can add this menu for each view in my website with "selected" class of current view, but this is not good solution.
If I understand right you want to put the "selected" class to the current displaying action.
You can do a check in the view by looking at this:
HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()
HttpContext.Current.Request.RequestContext.RouteData.Values["action"].ToString()
Then you put the "selected" class to your actionlink the way showed in the previous answer
<li>#Html.ActionLink("Home", "Index", "Home", null, new {#class = ":selected"})</li>
Personally I will create a ViewModel containing a list of "MenuAction" that expose, other than the route values, a bool property "Selected". Imo from the view will be much more cleaner the handling of the data.
You can add class with this ActionLink overload:
<li>#Html.ActionLink("Home", "Index", "Home", null, new {#class = ":selected"})</li>
The 5th parameter is HTML attributes.
MSDN ActionLink of this overload
Update:
$(function(){
var controllerName ='ViewContext.RouteData.Values["Controller"]';
$('#' +controllerName).addClass(':selected');
});

Resources