I have an ASP.NET MVC app. In my app, I have multiple layout files (~10). I have a block of HTML that is similar across the layout files. For that reason, I want to put it into a reusable control, because I anticipate some change will be needed to it.
On some of the pages that reference my layout files that use this control, I want to insert something into that a content area of the control. To demonstrate, imagine I have a layout file like this:
_Layout.cshtml
#** MY REUSED BANNER CONTROL GOES HERE **#
<div class="container">
#RenderBody()
</div>
Banner.file [not sure what to use]
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
Hello
</div>
<div class="col-lg-3">
#RenderSection("bannerContent", required: false)
</div>
<div class="col-lg-3">
Leave
</div>
</div>
</div>
MyPage.cshtml
#{
Layout = "~/Views/Shared/_Layout.cshtml"
}
<div>
Main content goes here
</div>
#section bannerContent {
<div>This goes into Banner.file</div>
}
The above code does not work. It is there to communicate the idea. From my understanding, a partial view won't work because partial's don't support sections. What are my options here?
If I could understand you need something like this.
Create _banner.cshtml in ~/Views/Shared.
<div class="container-fluid">
<div class="row">
<div class="col-lg-3">
Hello
</div>
<div class="col-lg-3" id="banner_content"> // Here your page specific content will go
</div>
<div class="col-lg-3">
Leave
</div>
</div>
_LayOut.cshtml
#Html.Partial("_banner"); // Reusable banner html
<div class="container">
#RenderBody()
</div>
MyPage.cshtml
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
Main content goes here
</div>
#section Scripts {
$(document).ready(function(){
$('#banner_conten').html('Your dynamic part.');
});
}
I am not sure whether I understood your requirement completely or not. But check if it helps you.
Related
I am in the process of converting my website from aspx to cshtml (Razor). This is going fine apart from an issue I have with my 2 or 3 column master pages and trying to convert these to a cshtml Layout Page.
In Razor I have basically created separate pages for all of my sections and am then calling these from the Layout Page using #RenderPage. Maybe this in itself is wrong? Basically what all the sections are displaying fine apart from the Main content section which is basically a wrapper for the 3 (or 2) columns that I wish to be displayed within this. I have tried various ways to do this but either just get the 1 main column displayed across the width of the page or get the column displayed above each other but the formatting of the other 2 is incorrect. I know all of the CSS etc works fine in aspx but I am obviously doing something wrong in Razor.
CSHTML New Layout Page
<body>
<div id="container">
<div id="top">
#RenderPage("~/Views/Shared/_Top.cshtml")
</div>
<div id="header">
#RenderPage("~/Views/Shared/_Header.cshtml")
</div>
<div id="nav">
#RenderPage("~/Views/Shared/_Nav.cshtml")
</div>
<div class="main">
#RenderPage("~/Views/Shared/_Main.cshtml")
<div class="columnVerySmall">
#RenderPage("~/Views/Shared/_ColumnVerySmall.cshtml", false)
</div>
<div id="columnLarge">
#RenderBody()
</div>
<div id="columnSmall">
#RenderPage("~/Views/Shared/_ColumnSmall.cshtml", false)
</div>
</div>
<div id="footer">
#RenderPage("~/Views/Shared/_Footer.cshtml")
</div>
<div id="scripts">
#RenderPage("~/Views/Shared/_Scripts.cshtml")
</div>
</div>
</body>
Old ASPX Master Page:
<div class="main">
<main role ="main" class="mainWrapper">
<div class="columnVerySmall">
<asp:ContentPlaceHolder ID="columnVerySmallContent" runat="server"></asp:ContentPlaceHolder>
</div>
<div class="columnLarge">
<asp:ContentPlaceHolder ID="columnLargeContent" runat="server"></asp:ContentPlaceHolder>
</div>
<div class="columnSmall">
<asp:ContentPlaceHolder ID="columnSmallContent" runat="server"></asp:ContentPlaceHolder>
</div>
</main>
</div>
I have managed to solve this by changing the Main section as shown in the code block below. I basically added the "Main" code to my layout and then #Render for the Columns. I don't really see how I can do this by having a separate page for "Main" and then calling it from the Layout Page using #RenderPage as I was originally trying. This is what I changed:
<div class="main">
<main role="main" class="mainWrapper">
<div class="columnVerySmall">
#RenderPage("_ColumnVerySmall.cshtml")
</div>
<div class="columnLarge">
#RenderBody()
</div>
<div class="columnSmall">
#RenderPage("_ColumnSmall.cshtml")
</div>
</main>
</div>
Im new to using partial views in mvc and for some reason could not get this working
Notes.cshtml
#model IEnumerable<SI2.Models.DashboardNote>
#foreach (var item in Model)
{
<div class="col-lg-12">
<div class="well">
<p>#Html.DisplayFor(modelItem => item.Information)</p><br />
<p>#Html.DisplayFor(modelItem => item.DateCreate)</p>
</div>
</div>
}
This is where I'm trying to call the partial view in another controllers view
Home/Index.cshtml
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fc-agenda-view"></i> Notes</div>
<div class="panel-body">
#Html.Partial("~/Views/DashboardNotes/Notes.cshtml")
</div>
</div>
</div>
</div>
Notes controller
public ActionResult Notes()
{
return View(db.DashboardNotes.ToList());
}
Every time I try calling Notes.cshtml as a partial view I receive a System.NullReferenceException with "Object reference not set to an instance of an object" but if I run the view normally it runs perfectly. There is no relation between the two models of the controllers either.
Thanks for any help:)
The code below will render your partial with no notes, hence the null reference, because you have a foreach for null notes.
#Html.Partial("~/Views/DashboardNotes/Notes.cshtml")
There is no mechanism in Html.Partial that triggers a call to the server. You would have to do some type of ajax call in your partial to get notes if you load it in the manner you are now. The easiest way to go about this is to return the Notes in your parent view or page and pass in the model to your partial, see below:
#model MainViewWithNotes
<div class="row">
<div class="col-lg-12">
<div class="panel panel-default">
<div class="panel-heading"><i class="fa fc-agenda-view"></i> Notes</div>
<div class="panel-body">
#Html.Partial("~/Views/DashboardNotes/Notes.cshtml",MainViewWithNotes.Notes)
</div>
</div>
</div>
</div>
i have created a partial view layout using bootstrap to display a single panel. whenever I call a partial view I use this layout and pass the section name on the ViewBag.
<div class="panel panel-default">
<div class="panel-heading">
#ViewBag.SectionName
</div>
<div class="panel-body">
<div class="container">
#RenderBody()
</div>
</div>
</div>
However, the issue is that inside a partial view, I may be calling another partial view using the same layout multiple times. This would result in nested panels with multiple levels.
The issue is, that I want to add a header element to the panel heading element containing the section name depending on the partial view nesting level. If we had three levels, the code would look like this:
<div class="panel panel-default main-content-panel">
<div class="panel-heading">
<h1>Section 1</h1>
</div>
<div class="panel-body">
<div class="container">
<div class="panel panel-default main-content-panel">
<div class="panel-heading">
<h2>Section 2</h2>
</div>
<div class="panel-body">
<div class="container">
<div class="panel panel-default main-content-panel">
<div class="panel-heading">
<h3>Section 3</h3>
</div>
<div class="panel-body">
<div class="container">
Some content and respective closing divs....
how could I accomplish this? An idea or solution that does not uses JS will be appreciated.
JS would certainly be the easiest way, but since you've explicitly disallowed that, the only option is to evaluate how many nesting levels there will be before they're actually rendered.
There's not a whole lot of detail here about what data structure represents these sections, but generally, you'll need to do a recursive count of the lower levels while rendering the upper level, and change the heading accordingly in the partial responsible for it. I can't give any more guidance than that without more code.
Long and short, you only get one bite at the apple when a partial is being rendered. You can't wait until the end and then modify something that happened in a previously rendered partial.
EDIT: It would seem all I needed to do was add data-position="fixed" to the header and that ensured it was encapsulated by a separate wrapper than content.
According to the panels docs, a panel must be a sibling of the header, content and footer elements within a page. So this is my basic markup (heavily stripped down):
<body>
<div data-role="panel"></div>
<div data-role="header"></div>
<div data-role="content"></div>
<div data-role="footer"></div>
</body>
However, when JQM re-renders the DOM, it creates this:
<body>
<div data-role="page">
<div data-role="panel"></div>
<div class="ui-panel-content-wrap ...">
<div data-role="header"></div>
<div data-role="content"></div>
<div data-role="footer"></div>
</div>
</div>
</body>
As you can see, it wraps the header, content and footer in the content wrap instead of just the content. How can I force it to behave correctly?
I have the following _Layout.cshtml page that has a bunch of #Html.Action() calls to several partial views.
<div class="wrapper">
<div class="header">
<a style="text-decoration:none;" href="#Url.Action("Index", "Home")"><div class="logo"><p>fisharwe</p><span class="greenText float-right">:</span></div></a>
<div class="searchBar">
#Html.Action("Search", "Item")
</div>
<div id="hearGreenBar"></div>
</div>
<div class="pageContent">
#RenderBody()
</div>
<div class="rightColumn">
<div id="help">
<div id="allHelpContent">
<span id="helpIcon"></span> <span id="helpTitle">help</span> <span id="helpArrow"></span>
</div>
</div>
<div id="userPanel">
#if(!Request.IsAuthenticated)
{
<div id="loginForm">#Html.Action("Login", "User")</div>
<div id="registerForm">#Html.Action("Register", "User")</div>
<hr class="greyLine" />
<div id="recentlyViewedItems">
<div id="recentItemsTitle">
<span class="recentItemsIcon"></span><span class="theRecentTitle">Recently Viewed</span>
</div>
</div>
}
else
{
<div id="userInfoSummary">#Html.Action("Summary", "User")</div>
}
</div>
</div>
</div>
At the top you can see the #Html.Action("Seach", "Item") call which renders a search bar and allows users to search for items/categories/sub-categories...etc. I got this working now, but it generated a new problem! When the user searches for something, and the results are rendered, the Login and Register partials in the sidebar (userPanel) are displaying validation errors such as "Email cannot be empty". I understand that the View is rendered regardless of what partial posted back but there has to be a way to prevent that from happening... Do I have to get rid of partials and render everything into the _Layout.cshtml page? But in that case I need to make this page typed which will cause yet another issue... So what can be done? I'm open to any suggestions...
Thank you.
Do you have different forms for the search and what is in the "userPanel"?. You may want to make sure your search is doing a get and not a post.
#using (Html.BeginForm("Search", "YourController", FormMethod.Get))