How can I add meta description and title to my MVC3 pages? - asp.net-mvc

Can someone tell me if there is a recommended way to add Meta information to MVC3 pages. The kind of information that I would like to add is title, description, keywords.
Thanks,
Gemma

I'd use ViewBag for the title and RenderSection for the rest of the head content. This goes in the Master Layout file (_Layout.cshtml):
<head>
<title>#ViewBag.Title</title>
#RenderSection("head", false);
</head>
In your individual views, you will add:
#{
ViewBag.Title = "My Page Title";
}
#section head {
<meta name="description" content="best site ever">
}
EDIT:
Note that the #section head {...} block is optional. You will not get a compilation error if you omit this block. On views where you want metadata you'd supply it.

I'd add it as a seperate view - that way you can call:
#{Html.RenderAction("Head", "Header");}
from within your various layouts and have the same correct header data rendered.
hth

Usually, in master page, we put a ContentPlaceHolder control, call it TitleContent like this:
<head>
<title>
<asp:ContentPlaceHolder ID="TitleContent" runat="server" />
</title>
</head>
And in children pages:
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Some Title
</asp:Content>
The same thing can be done for Meta Tags, or you could make a full ContentPlaceHolder for HeadContent and fill it with (title/meta...) in each page individually.

You have to put metatags inside the HEAD tag of HTML. For MVC application it depends there you have HEAD. It could be either page (*.cshmtl) of layout (Layout.cshtml). It is quite better to place into layout, since meta info is shared throught the rest of pages.
// *.cshtml
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<meta ... />
</html>
</head>

Related

Using other layouts inside a Grails GSP layout

I have a Grails 2.4.x app where ~80% of the pages use a simple.gsp layout, and the other pages are all stragglers that don't use any layout/templating at all. But they can't use simple.gsp because its contents don't apply to them.
I have a need to add a header nav to all of these pages (100%) and would like an elegant solution. Ideally, I could create a new layout, say, awesome-header.gsp that contains the header nav. Then:
For any pages (again, ~20%) that don't use the simple.gsp layout, I would just have them use awesome-header.gsp directly; but then...
I would just somehow reference/import/extend simple.gsp to (somehow) use awesome-header.gsp; which now allows the other ~80% pages to use the new header nav
Let's pretend that this is simple.gsp:
<!DOCTYPE html>
<html>
<head>
<title>
<g:layoutTitle default="Some App" />
</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!-- Lots of stuff -->
<g:layoutHead />
<!-- Lots of stuff -->
</head>
<body>
<!-- Lots of stuff -->
<div id="page-content">
<g:layoutBody />
</div>
<!-- Lots of stuff -->
</body>
</html>
And let's pretend that this is awesome-header.gsp:
<%# page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title></title>
</head>
<body>
<script id="awesome-header-bootstrap" src="/awesome-header/awesome-header-bootstrap-1.0.js"><script>
<g:layoutBody />
</body>
</html>
Pretty barebones. All I need this awesome-header.gsp layout to do is include a JS right at the top of the <body> element. For the purpose of this question, this JS script is "magic" and fetches the header nav magically for me.
How can reference/import/extend simple.gsp to use awesome-header.gsp?
I don't want the awesome-header.gsp to override any title or header content (either defined inside simple.gsp or in any of the straggler pages)
Any ideas how I could accomplish this setup?
If I well understand, you want a hierarchy between simple.gsp and awesome-header.gsp. So you may look at this link to help you to do that.
An other solution, maybe easier because there isn't a lot of modifications to do, is to use templates:
Put all your HTML / JS code related to your awesome-header inside a template (let say _awesome-header.gsp, the '_' is important !)
Simply put that line inside your 'simple' layout and inside all others pages which are not connected to your 'simple' layout: <g:render template='awesome-header'/>

What is the Grails GSP equivalent of ASP's ContentPlaceHolder?

I've been playing around a lot with the templating/layout concepts in Grails GSP. I've ben using layouts/content blocks for imitating ASP's master page behavior.
For example, I am using the tag <g:pageProperty /> in a template to leave a "placeholder" which can be overridden using a <content> tag:
myTemplate.gsp:
<body>
<g:pageProperty name="page.topDiv" />
</body>
myPage.gsp:
<html>
<head>
<meta name="layout" content="myTemplate"></meta>
</head>
<body>
<content tag="topDiv">
My top div
</content>
</body>
</html>
This works great for "appending" content to some spot within a template. However, I really want the behavior I can get in ASP.NET's master pages... which is to provide a "default" rendering of some content, and allow optional overriding. In an ASP.NET Master page, it would look like this:
myMaster.master:
<asp:ContentPlaceHolder id="something" runat="server">
<div>Default text/html here</div>
</asp:ContentPlaceHolder>
someOtherPage.aspx:
<asp:Content contentPlaceHolderId="something" runat="server">
Overriden content here!! I don't need to override this though :)
</asp:Content>
My Question:
Can I do this same default/overriding behavior in Grails' GSP?
There are a few different days you could accomplish this. The g:pageProperty is equivalent to the Sitemesh decorator:getProperty tag, so you can use a default attribute to indicate the default text to use. For example:
<g:pageProperty name="page.topDiv" default="Default text/html here"/>
However, I don't know of a clean way to get HTML content in there. You could use a g:if tag to test for that property and specify default behavior if it doesn't exist:
<g:if test="${pageProperty(name:'page.topDiv')}">
<g:pageProperty name="page.topDiv"/>
</g:if>
<g:else>
<div>Default text/html here</div>
</g:else>
The default content could also live in an external template gsp. The render method could then be used to display that content in the default attribute of g:pageProperty:
<g:pageProperty name="page.topDiv" default="${render(template:'topDiv')}"/>
Where in this case, the default content would be located in _topDiv.gsp.
I think you can try instead.
<g:render template=""><g:render>

ASP.NET MVC 3 RAZOR Style

how to use style block in a view ?
#<Style>
...
</Style>
You have to create a RenderSection in the head of your Layout, then add section to that content in a view. See this article: http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx
(Hopefully this will help the next Google visitor who gets this unanswered question first.)
style block only valid under <head> tag. if u use master page, just add content template in <head> tag
As the example:
<head>
<style>
...
</style>
</head>

How do I create a ContentPlaceHolder for CSS in ASP.NET MVC?

In my MasterPages, I created a content place holder to insert a CSS file right after the ContentPlaceHolder for the title and before the one for the body.
However, when I create a new View, the CSS ContentPlaceHolder shows up after the body one instead of before.
How can I fix it so the CSS content place holder shows up in the correct order as in the master pages whenever I create a new View?
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<asp:ContentPlaceHolder ID="Css" runat="server"></asp:ContentPlaceHolder>
<link rel="Stylesheet" href="../../Content/Site.css" />
<link rel="Stylesheet" href="../../Content/SiteMaster.css" />
</head>
<body>
<asp:ContentPlaceHolder id="MainContent" runat="server">
</asp:ContentPlaceHolder>
</body>
</html>
If you look at the Add View dialog box you will see, at the bottom, there is a field called ContentPlaceHolder ID. It appears whatever Content Placeholder Id is entered here will be rendered immediately after the Title content placeholder followed by all remaining placeholders so if you enter your css placeholder id in there you should get the behaviour you are expecting.
I have no idea why it works like this and would be interested to hear any suggestions.
Bizarrely if you enter TitleContent into this field then two placeholders are rendered on the view with that id!

How does Grails know to apply a "layout" to pages it renders?

I've been going through the book "The Definitive Guide to Grails" (Rocher/Brown) and in Chapter 04, this mysterious thing called a "layout" just appeared with no explanation. (And there's no "layout" in the index. As far as I know, it's never explained.)
How does the system know to "inherit" the pages from layout/main.gsp? There's nothing about "layouts" in the index, and it seems to have just appeared.
On their sample app, a simple store site, the URL mappings for the / homepage say
"/"(controller:"store")
and store controller's empty "index" closure
package com.g2one.gtunes
class StoreController {
def index = {
}
}
simply tells it to render store/index.gsp
The store/index.gsp just has a few lines of HTML; no layout gets included with any directive
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta name="layout" content="main">
<title>gTunes Store</title>
<g:javascript library="prototype"></g:javascript>
</head>
<body id="body">
<h1>Your online music store and storage service!</h1>
<p>Manage your own library, browse music and purchase new tracks as they become available</p>
</body>
</html>
When I run the sample the page shown for "/" isn't just this simple HTML, it's the contents of "layouts/main.gsp" with this information magically inserted inside it.
I don't see how the information in layout/main.gsp gets applied to the page, how the elements get mixed together. I've been following through the book page by page and this functionality just "appeared" with no explanation.
The <meta name="layout" content="main"> tag includes the layout in the gsp page.
You can view the grails-app/views/layouts/main.gsp to view and modify the layout. You can copy main.gsp to mymain.gsp, modify it, then change layout entry in the gsp page to reference mymain.gsp instead of main.gsp and experiment with customizing your layout preserving your ability to easily back out your changes.
Grails uses sitemesh under the covers (like it uses hibernate and spring) to do view layouts. There is a web-app/WEB-INF/sitemesh.xml configuration file in the project directory as well. This particular file isn't that helpful, but it references a class in the groovy project if you wanted to deeply understand how grails is using sitemesh (this probably isn't necessary).
Here's your directive:
<meta name="layout" content="main">
main.gsp contains <g:layoutHead> and <g:layoutBody>, where the <head> and <body> content of the index.gsp are folded into the layout to create the final page.
One recent trick that appears to work, if you name your layout to match your controller it appears (in Grails 2.3.4 at least) to automatically use that template.
For example, my controller:
// grails-app/controllers/myapp/HomeController.groovy
package myapp
class HomeController {
def index() {
[ myvar: "Test" ]
}
}
my layout:
// grails-app/views/layouts/home.gsp
<html>
<head></head>
<body>
<h1>Home</h1>
<g:layoutBody />
</body>
</html>
my view:
// grails-app/views/home/index.gsp
<p>${ myvar }</p>
renders using the home layout.
Also, you can specify a layout for all your actions in a controller like this:
class HomeController {
static layout = "someotherlayout"
// actions will render using grails-app/views/layouts/someotherlayout.gsp
}

Resources