I have a page:
#Html.Action("Index", "Product")
#Html.Action("Index", "Vendor")
both of these contain:
#section Head {
...
}
and (of course), my layout file contains:
<head>
...
#RenderSection("Head", required:false)
</head>
the idea being that every page that has something for the head (like javascript includes, css, etc.) can do it via the section. The problem is that only one definition per page seems allowed. How is this generally handled?
I would not recommend using Section within the results of RenderAction as this is generally used for View Pages and not partials.
It would be better to have the following in your hosting layout page:
#section Head {
#Html.Action("foo")
#Html.Action("bar")
}
I couldn't find a nice way to do this, so I instead added properties to my base ViewModel that would hold the information that needed to go in the <head>, and then have a RenderPartial("Head") in my layout page. This way things are slightly more strongly-typed too, rather than just having any page put random junk in:
// Views/Shared/Head.cshtml
#model ViewModel
#foreach (var site in model.AuthorSites)
{
<link rel="me" type="text/html" href="#site" />
}
Related
I have a boilerplate that has various includes, one being:
#include('nav')
I would like to use the same boilerplate for the CMS of my site, but use a different nav.
What would be the best way of getting the boilerplate to include a different nav when the user is using the CMS:
#include('nav-cms')
This is more of an architectural question, and the answer is that you can probably do this many, many ways. However, the answers can be Laravel specific, so here goes:
One method would be to change the include statement to be:
#include($navView)
And then either in your controller, or using view composer, you should set that variable appropriately.
Alternatively, you can do it using sections:
// layout.blade.php
<html>
<head></head>
<body>
#section('nav')
#include('nav')
#show
#yield('content')
</body>
</html>
// some-frontend-view.blade.php
#extends('layout')
#section('content')
Content here
#stop
// some-cms-view.blade.php
#extends('layout')
#section('nav')
#include('nav-cms')
#overwrite
#section('content')
CMS content here
#stop
That way it assumes frontend nav, and then you override it in the CMS for the CMS nav. Alternatively, instead of defaulting to 'nav' in the layout, you could use #yield, and specify it in the some-frontend-view.blade.php file as in the some-cms-view.blade.php file.
I have a suite of several MVC3 web applications, all of which reference a common Core.dll. I have compiled common views using RazorGenerator, and the subscribing sites find the relevant views from the pre-compiled .dll without any problem.
I am trying to do the same for the layout page, as this is common across all the sites too, save for one or two divs that are specific to that particular site. This also works fine, in as much as the _layout view is served up by just doing this:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
But, to get the site specific divs in the layout populated, I want to have a partial view in the specific site and use JQuery to set the HTML of the placeholding div in the _layout. Something like:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
//Have a hidden div containing the partial view that sits in the specific site
<div id="SiteSpecificStuff" style="display:none">
#Html.Partial("_SiteSpecificStuff", model)
</div>
// Use jQuery to populate the html of the placeholding div on the _Layout
// with that of the partial view
<script type="text/javascript">
$(document).ready(function () {
$("#divPlaceHolderOnLayout")
.html($("SiteSpecificStuff").html());
});
</script>
I have tried this but the _ViewStart does not re-fire on every post. Is this possible using a different approach?
I think you're looking for this:
#RenderSection("YouSection", required: false)
Our group needs to have a standard Common Look and Feel (CLF) for all our web applications. the base line for them all is the same, and certain items like the css references can have customization.
We want to find a way to create either one full layout file or partials that can be shared by all.
I have read many postings and the layout variable on views do not have the ability to read absolute paths.
Can we get a razor method to read XML and render to our layouts, much like the renderbody() does?
EDIT:
We would like to have items like the css, standard layouts etc in one project. Then this could become a distributable package for development teams.
Example of the final output we are looking for:
_base.cshtml example.
#model CLFModel
#CLF.Header(...)
#CLF.LeftMenu(...)
#CLF.OptionalRightMenu(...)
#CLF.Body(...)
#CFL.Footer(...)
The CLF.Header would contain something like below, and would be render from either a file or a pre compiled reference.
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="#Model.dcLanguage" lang="#Model.dcLanguage">
<head>
<meta charset="utf-8" />
<title>#Model.PageTitle</title>
meta tags.....
CSS required links ....
CSS section for custom link references ...
script tags(required)
optional section for script tags
</head>
You can create as many partial view as you want and just include them into the view you are rendering using #Html.Partial("YourPartialView"). You can create a _MasteLayout, which contains various partial views and #RenderBody for maintaining a consistent feel
Just wanted to add a class="myClass" in body tag. Is there any html helper or something else can do this in MVC3 view page? Please advise, thanks.
This is very similar to Aaron's solution, but doesn't have the weight of a section (which at least in my mind, are for larger blocks of content than a single string). The simplest way is to pass a variable with the ViewBag.
In your layout, just print out the class for the body tag, plus any other page specific variables (page title, extra css/js scripts, etc...)
_Layout.cshtml:
<html>
<title>#ViewBag.Title</title>#* Can easily add in per page titles too *#
<body class="#ViewBag.BodyClass">
#RenderBody()
</body>
</html>
Then, variables set in your view get passed upwards to the layout:
Index.cshtml:
#model MyViewModel
#{
ViewBag.Title = "This page title!";
ViewBag.BodyClass = "...";
}
While you may have full control of the HTML a solution was what was needed so here is one ;-)
In the _layout.cshtml page
<body class="#RenderSection("BodyClass", false)">
This will look for a section in all the child pages but says don't worry if it can't find one
Then in your child views just do this
#section BodyClass {productList}
Keep it on one line and then the outputted HTML will look fine, also you can then build up the class names as well.
#section BodyClass {productList generic}
This idea goes perfect with DOM-Ready page specific code, why not checkout
http://paulirish.com/2009/markup-based-unobtrusive-comprehensive-dom-ready-execution/
Or my extended version here
https://github.com/AaronLayton/H5BP-Core
My way lets you do page specific code, but allows you to keep all of the Javascript in separate pages so each page becomes easily manageable. The final step would be to concatenate and minify all the JS into 1 file ;-)
I have an MVC3 site using Razor as its view engine. I want my site to be skinnable. Most of the possible skins are similar enough that they can derive from a shared master layout.
Therefore, I am considering this design:
However, I would like to be able to call RenderSection in the bottom layer, _Common.cshtml, and have it render a section that is defined in the top layer, Detail.cshtml. This doesn't work: RenderSection apparently only renders sections that are defined the next layer up.
Of course, I can define each section in each skin. For instance, if _Common needs to call RenderSection("hd") for a section defined in Detail, I just place this in each _Skin and it works:
#section hd {
#RenderSection("hd")
}
This results in some duplication of code (since each skin must now have this same section) and generally feels messy. I'm still new to Razor, and it seems like I might be missing something obvious.
When debugging, I can see the complete list of defined sections in WebViewPage.SectionWritersStack. If I could just tell RenderSection to look through the entire list before giving up, it would find the section I need. Alas, SectionWritersStack is non-public.
Alternatively, if I could access the hierarchy of layout pages and attempt execution of RenderSection in each different context, I could locate the section I need. I'm probably missing something, but I don't see any way to do this.
Is there some way to accomplish this goal, other than the method I've already outlined?
This is in fact not possible today using the public API (other than using the section redefinition approach). You might have some luck using private reflection but that of course is a fragile approach. We will look into making this scenario easier in the next version of Razor.
In the meantime, here's a couple of blog posts I've written on the subject:
http://blogs.msdn.com/b/marcinon/archive/2010/12/08/optional-razor-sections-with-default-content.aspx
http://blogs.msdn.com/b/marcinon/archive/2010/12/15/razor-nested-layouts-and-redefined-sections.aspx
#helper ForwardSection( string section )
{
if (IsSectionDefined(section))
{
DefineSection(section, () => Write(RenderSection(section)));
}
}
Would this do the job ?
I'm not sure if this is possible in MVC 3 but in MVC 5 I am able to successfully do this using the following trick:
In ~/Views/Shared/_Common.cshtml write your common HTML code like:
<!DOCTYPE html>
<html lang="fa">
<head>
<title>Skinnable - #ViewBag.Title</title>
</head>
<body>
#RenderBody()
</body>
</html>
In ~/Views/_ViewStart.cshtml:
#{
Layout = "~/Views/Shared/_Common.cshtml";
}
Now all you have to do is to use the _Common.cshtml as the Layout for all the skins. For instance, in ~/Views/Shared/Skin1.cshtml:
#{
Layout = "~/Views/Shared/_Common.cshtml";
}
<p>Something specific to Skin1</p>
#RenderBody()
Now you can set the skin as your layout in controller or view based on your criteria. For example:
public ActionResult Index()
{
//....
if (user.SelectedSkin == Skins.Skin1)
return View("ViewName", "Skin1", model);
}
If you run the code above you should get a HTML page with both the content of Skin1.cshtml and _Common.cshtml
In short, you'll set the layout for the (skin) layout page.
Not sure if this will help you, but I wrote some extension methods to help "bubble up" sections from within partials, which should work for nested layouts as well.
Injecting content into specific sections from a partial view ASP.NET MVC 3 with Razor View Engine
Declare in child layout/view/partial
#using (Html.Delayed()) {
<b>show me multiple times, #Model.Whatever</b>
}
Render in any parent
#Html.RenderDelayed();
See the answer link for more use-cases, like only rendering one delayed block even if declared in a repeating view, rendering specific delayed blocks, etc.