Making menu item active based on url and query string - c#

I have some menu item in my application which are as below :
Statistics
Tax
Skills
Now when user click on any menu item I want to make it active like when user click on statistic I would like to make it active and this is how currently I am doing it and it is working fine.
_Layout.cshtml:
<div class="Menu #Html.IsSelected(actions: "Index", controllers: "Statistics", class: "active")" >Stats</div>
<div class="Menu #Html.IsSelected(actions: "Index", controllers: "Tax", class: "active")">Tax</div>
<div class="Menu #Html.IsSelected(actions: "Index", controllers: "Skills", class: "active")">Skills</div>
public static string IsSelected(this HtmlHelper html, string controllers = "", string actions = "", string cssClass = null)
{
ViewContext viewContext = html.ViewContext;
bool isChildAction = viewContext.Controller.ControllerContext.IsChildAction;
if (isChildAction)
viewContext = html.ViewContext.ParentActionViewContext;
RouteValueDictionary routeValues = viewContext.RouteData.Values;
string currentAction = routeValues["action"].ToString();
string currentController = routeValues["controller"].ToString();
if (String.IsNullOrEmpty(actions))
actions = currentAction;
if (String.IsNullOrEmpty(controllers))
controllers = currentController;
//for passing multiple comma seperated Action.
//For Eg:class="#Html.IsSelected(actions: "List,Detail", controllers: "Default")"
string[] acceptedActions = actions.Trim().Split(',').Distinct().Select(t=>t.ToLower().ToString()).ToArray();
string[] acceptedControllers = controllers.Trim().Split(',').Distinct().Select(t=>t.ToLower().ToString()).ToArray();
return acceptedActions.Contains(currentAction.ToLower()) && acceptedControllers.Contains(currentController.ToLower()) ?
cssClass : String.Empty;
}
But now I have 1 common page accessible from both statistics and tax page :
Rank
Url when user goes to this page from Statistics :
http://localhost:1231/Rank/Index?type=stats&Id=21
Url when user goes to this page from Statistics :
http://localhost:1231/Rank/Index?type=Tax&Id=48
So I would like to make Statistics menu active when user goes on Rank page from Statistics page and make Tax menu item active when user goes on rank page from Tax page.

You're making this way too complicated. Try this instead:
#{ string url = null; }
#{ url = Url.Action("Index", "Statistics"); }
<div class="Menu #(url == Request.Url.AbsolutePath ? "active" : null)">
Stats
</div>
#{ url = Url.Action("Index", "Tax"); }
<div class="Menu #(url == Request.Url.AbsolutePath ? "active" : null)">
Tax
</div>
#{ url = Url.Action("Index", "Skills"); }
<div class="Menu #(url == Request.Url.AbsolutePath ? "active" : null)">
Skills
</div>
In other words, all you need is a simple ternary to compare the URL of the link with the current URL. Request.Url.AbsolutePath is used so that query strings are ignored. Setting a url variable just prevents having to call Url.Action multiple times, keeping things DRY.

Its simple, just like a trick
Create a css of Active and set whatever color you want to show active.
On selection of any of them, remove class from all, get what item is clicked. add class named Active to only that element.

Related

getting anchor tag href on click from Action Method

I have a grid which includes below hyperlink row,currently for all rows we have same hyperlink and only ID is changing and it is working fine.
<a href=" + #ViewBag.Url+ ID + " target='_blank'>Test</a>
Now for every row, we have different link url which i would get from action method when I pass ID.
I want to call MVC Action Method to get hyperlink url and then open it in another tab.How can I accomplish this?
I tried this one but it is not opening hyperlink?
<div class="row">
<div class="col-md-4">
Click Here;
</div>
</div>
public string GetPDFUrl(string id)
{
return "test.com" + id;
}
There are several ways to solve your problem. one of them is using child actions.
Put your generating URL part into a partial view to put your logic in your action method. So, create a child action method that can only be called in your views.
[ChildActionOnly]
public ActionResult GenerateUrlPartial(int id)
{
var generatedUrl = "";//your url business is here
var model = new UrlInfo { Url = generatedUrl };
return PartialView(model);
}
Then, create GenerateUrlPartial.cshtml partial view :
#model UrlInfo
#{
Layout = null;
ViewBag.Title = "GenerateUrlPartial";
}
<div class="row">
<div class="col-md-4">
Click Here;
</div>
</div>
And in your loop, call the action method like this :
#for (int i = 0; i < 10; i++)
{
Html.RenderAction("GenerateUrlPartial", new { id = i });
}
Hope this helps.

Build Menu Items From Controller

I am creating HTML Menus from controller. Menus are stored in database and I make html tag as below :
foreach (UIMenuModel item in list)
{
if (item.Controller != "Home")
{
string line = string.Format(#"<li><a asp-area=""{0}"" asp-controller=""{1}"" id=""{1}""
asp-action = ""{2}"" style = ""font-size:16px;;"" > {3} </a></li>", item.Area, item.Controller, item.Action, item.LinkText);
sb.Append(line);
}
}
which gives me below HTML :
<li><a asp-area="" asp-controller="CrossApproval" id="CrossApproval" asp-action="Index" style="font-size:16px;;"> Cross Approval </a></li>
Other Menu Item, Which is written in HTML itself, gives below HTML in browser.
<li><a id="CrossRequest" style="font-size:16px" href="/CrossRequest">Cross Request</a></li>
On UI, it looks perfect. However, I am not able to click and navigate to desired controller and action methods. Can someone please help me to identify while this anchor tag is not allowing me to navigate.
Use RazorLightEngine to convert plain string as rendered Razor string:
string content = "Hello #Model.Name. Welcome to #Model.Title repository";
var model = new
{
Name = "John Doe",
Title = "RazorLight"
};
var engine = new RazorLightEngine();
string result = engine.ParseString(content, model);
And then add it any place in razor view like encoded string
<div>
#Html.Raw(result)
</div>
As posted in Question, HTML with href was working fine. So, I decided to mimic the same behaviour from the controller and changed my code as below :
string line = string.Format(#"<li><a asp-area=""{0}"" id=""{1}"" href=""/{1}/{2}""
style=""font-size:16px"">{3}</a></li>", item.Area, item.Controller, item.Action, item.LinkText);
This generated a link which I can click and navigate.

Action not being hit from another controller

I am asking a simple login page to get the user to enter a pin on a mobile responsive app its in house not online.
When the page is posted the user clicks the submit button the SaveUsers is the function that is called first this is on the Login Controller.
[HttpPost]
[ActionName("Index")]
public ActionResult SaveUsers(Users model)
{
BrianScott_SOMEntities usr = new BrianScott_SOMEntities();
var s = usr.GetUsers(model.Pin);
var item = s.FirstOrDefault();
if (item == "Success")
{
var sageDetails = usr.Users.Where(w => w.Pin ==model.Pin).FirstOrDefault();
HttpCookie cookie = new HttpCookie("BScotSalesOrderManagerLogin");
cookie.Values.Add("SageUserName", sageDetails.SageUserName.ToString());
cookie.Values.Add("SagePassword", sageDetails.SagePassWord.ToString());
cookie.Expires = DateTime.Now.AddDays(30);
Response.Cookies.Add(cookie);
return View("~/Views/Home/Index.cshtml");
}
else if (item == "User Does not Exists")
{
ViewBag.NotValidUser = item;
}
else
{
ViewBag.Failedcount = item;
}
return View("Index.cshtml");
}
The below form is the form that is represented with the above controller which prompts the user for their pin number.
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#model Web.SOM.Models.Users
#using (Html.BeginForm())
{
<div class="bs-example" style="border:2px solid gray;">
<label>#ViewBag.SageUserName</label>
<div class="form-group centerlook">
<h1> Login </h1>
</div>
<div class="form-group centerlook">
<label>Pin: </label>
#Html.EditorFor(model => model.Pin )*
#Html.ValidationMessageFor(model => model.Pin)
</div>
<div class="form-group error">
#if (#ViewBag.Failedcount != null)
{
<label> Failed Attempt count is: #ViewBag.Failedcount</label>
}
#if (#ViewBag.NotValidUser != null)
{
<label> #ViewBag.NotValidUser</label>
}
</div>
<div class="loginbtn">
<input type="submit" value="Login" class="btn btn-primary" />
</div>
</div>
}
The home controller is what the controller in the first piece of codes redirects to it is the index action to which I want to hit.
public ActionResult Index()
{
if (Request.Cookies["BScotSalesOrderManagerLogin"] != null)
{
ViewBag.SageUserName = Request.Cookies["BScotSalesOrderManagerLogin"].Values["SageUserName"];
ViewBag.SagePassword = Request.Cookies["BScotSalesOrderManagerLogin"].Values["SagePassword"];
}
return View();
}
But the method is not getting hit unless I do a hard reload is there another way of moving to the other view and making sure that the index method is being hit ?.
Because when I look at the viewbag the items are null when they should contain a username and a password of the related row when I debug on the first page the values are their but then lost on the other page.
On my page i am wanting to display the information I am just doing
<label>Sage Username : #ViewBag.SageUserName </label>
But the value is blank? I am coming from a web forms background so please excuse me better late than never jumping ship
Your sequence of events is...
User POSTs to SaveUsers on Login (aliased as the action Index)
You return a view
User POSTs from that view to Index, still on Login
When you do this:
return View("~/Views/Home/Index.cshtml");
You're essentially overriding the framework's standard behavior. You're returning a specific file to be used as the view, but not telling the framework to switch any context or change the URL in any way. So from the browser's perspective, even though you returned a view from your server-side Home folder, the page is still /Login/Index and any form actions, links, etc. will be from there.
In general you should prefer redirects to manually specifying views. So a sensible sequence of events might be:
User POSTs to SaveUsers on Login (aliased as the action Index)
Server-side code performs its logic, redirects the user to Index on Home
User GETs Index on Home
Server returns the view
User POSTs to Index on Home
So your SaveUsers action method, when successful, can do something like:
return RedirectToAction("Index", "Home");
This will then cause the user to make a GET request to Index on Home, which can just return View() and that will default to the view you're manually returning now. Now from the browser's perspective it's on /Home/Index and all form actions, links, etc. will be from that context.
Additionally, if you always want a given form, link, etc. to point to a specific controller action regardless of where it was loaded from, you can specify that. For example, when you do this:
using (Html.BeginForm())
You are telling the framework that this form will "POST to the current URL, whatever that URL is". But when you do this:
using (Html.BeginForm("Index", "Home"))
This tells the framework that the form will always post to the Index action on the Home controller, regardless of the current URL.
can you try using
#using (Html.BeginForm(yourActionName, yourControllerName))
{
}
And use RedirectToAction to return to your Home Index..

Redirect to Page but specific Tab

I have used this as an example of what I am trying to do.
I have a tabbed page.
In my Controller I want to redirect to a page but a specific tab on that page.
Now when I am on that page, and hover over the tab the link is http://localhost:xxxxx/OInfoes/Details/2#phases
So in my controller I did this to try and recreate the same link:
return new RedirectResult(Url.Action("Details", "OInfoes", new { id = phase.OID }) + "#phases");
This gives me the correct link but it doesn't put me on the correct tab.
How do I get this to work?
My HTML for the tabs is below:
<ul class="nav nav-tabs">
<li class="active">Information</li>
<li>Previous Reports</li>
<li>Previous/Current Phases</li>
</ul>
You should update your action method to take a parameter to represent the tab to be selected.
public ActionResult Details(int id,string tab="")
{
if (id != null)
ViewBag.ActiveTab = id.ToString();
// to do : Return a view
}
When you return the redirect result, send a querystring with name tab
return new RedirectResult(Url.Action("Details", "OInfoes", new { id = phase.OID ,
tab="phases"}));
Now in your document ready, use the value of ViewBag.ActiveTab value, generate the jQuery selector from that and use that to call .tab('show').
$(function () {
var selector = '#ViewBag.ActiveTab';
if(selector)
{
$("#link-tab"+selector).tab('show');
}
});
Make sure your tab's has id's matching with our above code.
<ul class="nav nav-tabs">
<li class="active">Info</li>
<li>Prev Reports</li>
<li>Prev/Cur Phases</li>
</ul>

How could i change layout page from viewpage in mvc

I am working on asp.net mvc 3 with razor. I have a layout(master) page in my project. It contains a side panel with 4 links and place for viewpage(#RenderBody). when user clicks on link1 it redirects to viewpage1 and link1 should be selected, and when he clicks link2 it redirects to viewpage2 and link2 should be selected so on. It redirecting very well to required pages but it always selects the link1 only though i clicked link2,link3,link4. How could i select the appropriate link in layout page from the individual viewpage. guide me.
By selected I guess you mean highlight using CSS, don't you? If this is the case I would propose you to write a custom HTML helper to generate those links:
public static IHtmlString MenuItem(
this HtmlHelper htmlHelper,
string text,
string action,
string controller
)
{
var li = new TagBuilder("li");
var routeData = htmlHelper.ViewContext.RouteData;
var currentAction = routeData.GetRequiredString("action");
var currentController = routeData.GetRequiredString("controller");
if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
{
li.AddCssClass("active");
}
li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
return new HtmlString(li.ToString());
}
and then inside your layout use the helper:
<ul>
#Html.MenuItem("link 1", "Action1", "Controller1")
#Html.MenuItem("link 2", "Action2", "Controller2")
...
</ul>
and now all that's left is to define the .active rule in your CSS class:
.active {
... something fancy to pop the currently selected link from the others
}

Categories

Resources