MVC Navigation Design - c#

What is the best method to render some navigation hyperlinks depending on which page the user is on (I am using C# MVC 4).
I have a _layout.cshtml which looks like the following (shortened down for display purpose).
<body>
#{Html.RenderAction("MainNav", "Navigation");}
<div id="container">
#RenderBody();
</div>
</body>
If a user navigates to /Home/Index then I would want the MainNav to render hyperlinks of Home | Management
Then if a user clicks Management that will change to Home | Company | Teams | Roles and will change again if they click one of these links.

Using Html.RenderAction() or Html.Action() would involve passing a parameter identifying your current view and using multiple if/else blocks to define what the partial should render. Instead you can use Razor sections to act as placeholders for specific content that can be placed anywhere in the layout.
In the layout, add #RenderSection(), in this case named "menu" to act as a placeholder for your menu links
<div id="sidebar">
#RenderSection("menu", required: false)
</div>
<div id="container">
#RenderBody();
</div>
Then in each view, add #section menu { ... } containing the links to display
Index.cshtml
// content to be displayed
#section menu {
#Html.ActionLink("Home", .....)
#Html.ActionLink("Management", .....)
}
Management.cshtml
// content to be displayed
#section menu {
#Html.ActionLink("Home", .....)
#Html.ActionLink("Company", .....)
#Html.ActionLink("Teams", .....)
#Html.ActionLink("Roles", .....)
}

The more you think about it, the more complex the problem you're describing becomes. So I tend to use a library. Even though it might seem overkill at this point, but in my experience it pays off later:
<body>
#Html.MvcSiteMap().Menu()
<div id="container">
#RenderBody();
</div>
</body>
This is all you need to do when using https://github.com/maartenba/MvcSiteMapProvider
Install-Package MvcSiteMapProvider
Just annotate your actions like this:
[MvcSiteMapNode(Title = "Menu Title")]

Related

Linking 2 pages with Razor (WinFormApp)

I'm working on a WinFormApp that is using a WebView as my UI (the razor part). I have 2 files that exist in the same directory (Index.razor and Test.razor).
Using HTML, I have setup so list items (Index and Test) that should open the appropriate page when I click on the appropriate item. However, I cannot seem to get this to work. I have tried basic with no success. I have added the #page tags but this doesn't help. I have also tried using but this only seems to remove my clickable link.
I feel like I'm missing something obvious, and I'm not sure what. Any guidance would be greatly appreciated.
Here is my Home code(Index.razor). Right now Test.razor just contains a header to show it switched pages:
<div class="header">
<h1>Index Page</h1>
</div>
<div class="main">
<div class="ui-options">
<ul>
<li>Index</li>
<li>Test</li>
</ul>
</div>
</div>
#code {
}

Razor Pages: How to include pagesection in a partial page?

I have a Razor Pages layout page that includes a nav bar as a partial page
<html>
...
<body>
...
<partial name="_Nav" />
Inside my _Nav.cshtml
<div class="links">
link 1
link 2
<!-- custom links that are set by each page go here-->
</div>
This layout is used by every page in the website. I would like to be able include "extra" links that pertain to each page in the website.
I've tried doing it was #RenderSection, but it seems that sections are only allowed in the Layout page. Does this mean I need to do away with my _Nav partial and and lump all the code into one file? Or is there a way to keep an organized code structure and still pass some code around? With jinja2 code blocks this is no problem, so I'm hoping there is a nice way in Razor Pages as well!
Also, I really don't want to pass full html strings from the c# class out to the html, I'm already passing out any variables I need in the links.
Thanks for your help!
You don't have to store html in your ViewDataDictionary.
On every view that has extra links to add, store a List<string>, strings being urls, something like this:
View:
#{
ViewData["Links"] = new List<string>(){ "https://www.google.com", "https://www.facebook.com" };
}
Then in your Layout view:
<partial name="_Nav" view-data="#ViewData" />
Now in your partial view:
//Default Links
#if (ViewData["Links"] != null)
{
//We have extra links
List<string> links = (List<string>)ViewData["Links"];
foreach (string link in links)
{
link1
}
}
RenderSection can only be called from a layout page.
There is no such plugin to add the dynamic link to the partial view.
As a workaround,you could put a div outside the _Nav.cshtml like below and use RenderSection to dynamic add link to the div:
....
<div class="links">
<partial name="_Nav" />
#RenderSection("Html", required: false)
</div>
....
_Nav.cshtml:
link 1
link 2
Test View:
#page
#model IndexModel
//do your stuff...
#section Html
{
<a href='#link3'>link3</a>
}

Having separate Controller/Views for each Tab?

I'm creating an application in Asp.NET MVC. The main page will consist of a couple of tabs, for example, Students & Courses.
There will be a Student model and Course model. I'd like to have a Controller for each that would contain New, Edit, Delete Actions. The front end will look similar to this..
I'd like to use partial views within the body of each tab. Taking the first tab as an example, when the page loads it will display a list of Students in the tab body as a partial view. On clicking 'Add Student' within this partial view it will call an Action in the Student Controller and then return and display a partial view in the tab body with a form to create a new Student. On posting this form it will then again show the Student list partial view in the tab body.
Could anyone point me in the right direction or suggest a clean approach to achieve this?
A thought I had would be to have a partial view for each Action, for example:
<div class="tab-content" style="margin-top:20px;margin-left:10px;">
<div class="tab-pane fade active in" id="page-config-tab">
#Html.Partial("~/Views/Student/_List.cshtml")
#Html.Partial("~/Views/Student/_Add.cshtml")
#Html.Partial("~/Views/Student/_Edit.cshtml")
</div>
<div class="tab-pane fade" id="candidates-tab">
#Html.Partial("~/Views/Course/_List.cshtml")
#Html.Partial("~/Views/Course/_Add.cshtml")
#Html.Partial("~/Views/Course/_Edit.cshtml")
</div>
</div>
And when a button is clicked, I will use Jquery to Hide/Show the relevant partial view in a div before calling the Action in the Controller?
Thanks
You can use AJAX to call the necessary action which returns the correct partial view. Rendering them all on page load is wasteful since only 1 partial view will be displayed at a time.
Your initial HTML should looks like the following, only rendering the view you need:
<div class="tab-content" style="margin-top:20px;margin-left:10px;">
<div class="tab-pane fade active in" id="page-config-tab">
#Html.Partial("~/Views/Student/_List.cshtml")
</div>
<div class="tab-pane fade" id="candidates-tab"></div>
Then, add a script block:
<script>
$(function() {
$('#addStudentBtn').click(function() {
$.ajax({
method: 'GET',
url: '#Url.Action("Add", "Student")',
success: function(data) {
$('#page-config-tab').html(data); // 'data' will be your partial view
}
});
});
});
</script>
I've shown you a bare-minimum example for adding a student, you can use this general approach for each action.
P.S. looks like you're using bootstrap - they have event handlers you can use when changing tabs: https://getbootstrap.com/docs/3.3/javascript/#tabs-events

New to MVC can't get layout to work as desired

I am trying to implement what I think is a pretty standard "dashboard" layout. The trick is I know ASP.NET but not so familiar with MVC so this is a learning project.
I have read many an article and they have helped me progress right to the point where I am very stuck and confused.
Part of my confusion comes from an existing advanced MVC project that I am familiar with from a user perspective. This helps in that I am able to pick through the source code and match up what I am learning to what I have seen from the user perspective.
This is not the problem just an example...
For example I read here what I believe is a very good introduction to the concepts. (http://www.codeproject.com/Articles/383145/RenderBody-RenderPage-and-RenderSection-methods-in)
In the MVC project I get to pick through however I see in the _Layout
#if (IsSectionDefined("statusbar"))
{
#RenderSection("statusbar")
}
however #section statusbar is not defined in the _Layout. If I do a global search for #section I find this:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
#section header
{
}
#section headermenu
{
}
#section statusbar
{
}
#RenderBody()
So am I correct in guessing that statusbar is defined but it is an empty shell?
If it is an empty shell how does it get populated...cause when the project is running the statusbar does indeed have information???
So again this isn't my problem it is just an example of how the information at hand is confusing me.
This IS the problem:I'm not sure when to use PartialView, RenderSection...etc
My layout renders goofy. What is goofy? The only thing I can think of is to show you a screenshot of what happens.
What I want...
Here is the code used to generate these pages. The tags etc. for bootstrap etc. are omitted for brevity.
_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<title>#PageTitle</title>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
Header Stuff
</div>
</div>
<div class="row">
<div class="col-md-4">
#RenderBody()
</div>
<div class="col-md-8">
Main Content
</div>
</div>
<div class="row">
<div class="col-md-12">
Footer Stuff
</div>
</div>
</div>
</body>
</html>
Index.cshtml
#model DashboardModel
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="col-md-1">
<nav id="Navbar" class="navbar navbar-left" role="navigation">
<div id="organizer">
#(Html.Kendo().PanelBar()....etc....)
</div>
</nav>
</div>
<div class="col-md-3">
This is a place holder for my subnav...????
</div>
Stuff1Link cshtml
#model StuffModel
<div style="height:400px; border:dashed; border-width:thick;">
#{ Html.Kendo().MobileLayout().Name("mlay_PropStatus"); }
#(Html.Kendo().MobileView().....
</div>
Seems like layout is not put in Stuff1Link.cshtml
Can you put it like,
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
1.If your view just has some Html code just use "PartialView" :
#Html.Partial("_theLastPost")
2.If your view has controller for passing data it's better use "RenderAction":
#{ Html.RenderAction("_theLastPost"); }
and its controller
public PartialViewResult _theLastPost()
{
var a = (from c in db.Posts
orderby c.ID_Post descending
select c);
return PartialView(a);
}
3.I do not use render section . For more information about RenderSection go asp.net mvc layouts and sections with razor
I've got a post on my blog that discusses some of this you might want to check out.
The layout code you're referencing doesn't make much sense. The only purpose to declaring an empty section, really, is to fulfill a requirement that it exists, when you don't want to actually pass anything there. Since the layout is what defines whether it must be present or not, it makes no sense for it to exist there, empty. More than that, if you implement a section in your base layout, you'll get a runtime error because there's no place higher in the view chain where it's defined.
Long and short, to provide a place holder in your layout for a section you use:
#RenderSection("SectionName", [true|false])
The boolean param indicates whether views that utilize this layout must implement the section; false means it's optional, while true means it's required.
To implement a section in a view, you use:
#section SectionName
{
...
}
If you have a layout that inherits from another layout, that layout must implement all required sections in the layout it inherits from. If you want the the section to be available to views that utilize the sub-layout, you must redefine the section in the section implementation:
_Layout.cshtml
#RenderSection("Foo", true)
_SubLayout.cshtml
#{ Layout = "Views\Shared\_Layout.cshtml"; }
#section Foo
{
#RenderSection("Foo", true)
}
Finally, as to partial views vs. sections, it all comes down to whether you want to insert something into the layout or the view. For example, sections are most commonly used for inserting link tags to CSS files in the head or script tags before the closing body tag, where the view itself would not be able to touch directly. However, it's almost an apples and oranges comparison. Partials can be utilized in the layout, in the view, or even in a section. Whereas, sections can only be utilized in the layout.

How to remove an HTML element from the Layout for a 1 particular page?

I'm new to ASP.NET MVC and am wondering what I should be doing if I my _Layout.cshtml has an element
<div class="navbar navbar-inverse navbar-fixed-top">
...
</div>
that I don't want generated for a particular page with controller SomePageController.cs and view SomePage.cshtml. Do I just wrap that piece of HTML in an if statement like
#if(not on SomePage) {
<div class="navbar navbar-inverse navbar-fixed-top">
...
</div>
}
or is there a more proper way?
I usually use a magic string in ViewBag for this. I set it in my controller (or you can do it in the top of the view, if you wish).
ViewBag.HideNavBar = true;
in the _Layout:
#if(ViewBag.HideNavBar == null) {
<div class="navbar navbar-inverse navbar-fixed-top">
...
</div>
}
I use this strategy to pass options into the layout (such as datepicker options) all the time.
Give the single page that doesn't need that <div> a different Layout:
#model Foo
#{
Layout = "~/Views/Shared/_LayoutWithoutNavigation.cshtml";
}
<!-- rest of HTML -->
you can do it multiple way
1: Simple trick.. just use If condition and get the route name from Query string and match it with your route .
2: use two different layouts. one with that HTML part and one without HTML part.
and when creating view just specify the layout without HTML.
3: Use ViewBag / tempData
Approaches:
First:
if(Request.QueryString["routeName"] != "MyRoute" )
{
//Render HTML Part
}
second:
#{
layout = "~/shared/LayoutWithoutHTML.cshtml";
}
Third
in your Controller where you want to hide HTML
viewBag.HTMLCheck = true;
In your View
if(viewBag.HTMLCheck != true)
{
// Html Part
}
Your solution seems like an appropriate way to go about it - ideally though, if it's not going to be on every page, the pages without that section should use a different Layout.

Categories