What's the difference between #Html.Partial, #Html.Section and #section ? When should I use each of them?
#Html.Partial is to split the page into parts. The page will be incomplete without filling in the part.
#Html.Section is an (often optional) portion, usually defined in layouts, that inheritors can add content into. For example, if they want to add extra scripts to the page, there's a "scripts" section at the end of the default layout that allows pages to inject it at the end of the content.
#section is just defining the content for an #Html.Section in the child page.
For example:
<!-- layout page. -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
</head>
<body>
<div class="container body-content">
Layout content.<br/>
#RenderBody()
</div>
#RenderSection("scripts", required: false)
</body>
</html>
...
<!-- child page -->
#section scripts{
<script src="/Scripts/jquery.signalR-2.2.1.min.js"></script>
}
<div>Child content.</div>
<div>Partial content here: #Html.Partial("~/Views/PartialContent.cshtml")</div>
...
<!-- partial content in PartialContent.cshtml -->
Hello!
The result would be something like:
Layout content.
Child content.
Partial content here: Hello!
Related
I'm very confused by how the application.html.erb file and the view files combine. I have in my application.html.erb file the following (minimized the content for brevity):
<!DOCTYPE html>
<html>
<head>
<!-- Bootstrap Css -->
<link href="/bootstrap-assets/css/bootstrap.css" rel="stylesheet">
<%= yield :head %>
</head>
<body>
<nav>
<!--Long navbar section -->
</nav>
<%= yield %>
</body>
</html>
In my view file:
<html>
<head>
<!-- View Specific Stylesheet -->
<link href="/css/ViewSpecific.css" rel="stylesheet" />
</head>
<body>
<!-- View Specific Body -->
</body>
What I would expect is that when these 2 files combine, the View specific stylesheet load in the <head> section, and the View Specific Body load in the <body> section. The final result actually sends the view specific stylesheet to the <body> section, after the navbar from application.html.erb is already loaded. This obviously produces the unwanted result that part of my body is loading before the stylsheet is loaded, and the first second the user views the page everything looks terrible.
You should make use of content_for if you want to render the view-specific head into the head section of application.html.erb. Use
<% content_for :head do %>
<!-- View specific head section -->
<link href="/css/ViewSpecific.css" rel="stylesheet" />
<% end %>
Since you yield :head in the application.html.erb, thats all to be done. And you don't need html tags in the views.
For more, see http://apidock.com/rails/v4.2.1/ActionView/Helpers/CaptureHelper/content_for
I use partial views to render the content of the pages.
Normally, I use sections to render specific Scripts and CSS for the content by using #section
My basic url is {Controller}/{Action}/{Id}
For urls like {Controller}/{Action} ie. Product/Create, the sections and the pages render ok.
But when my url is {Controller}/{Action}/{Id} ie. Product/Edit/2, the CSS and Scripts are absent and I only get a plain HTML page.
My Layout:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<!-- CSS FILES -->
<link href="../assets/global/plugins/bootstrap-switch/css/bootstrap-switch.min.css" rel="stylesheet" type="text/css" />
<!-- BEGIN RENDER CSS SECTION EXISTING IN PARTIAL -->
#RenderSection("Style", required: false)
<!-- END RENDER CSS SECTION EXISTING IN PARTIAL -->
<link href="../assets/global/css/components.min.css" rel="stylesheet" id="style_components" type="text/css" />
<link rel="shortcut icon" href="favicon.ico" />
</head>
<body>
<div class="header">
#Html.Partial("_Header")
</div>
<div class="container">
<div class="sidebar">
#Html.Partial("_Sidebar")
</div>
<div class="content">
#RenderBody()
</div>
</div>
<!-- JAVASCRIPT FILES -->
<script src="../assets/global/plugins/bootstrap-switch/js/bootstrap-switch.min.js" type="text/javascript"></script>
<!-- RENDER JAVASCRIPT SECTION EXISTING IN PARTIAL -->
#RenderSection("Scripts", required: false)
<!-- RENDER JAVASCRIPT SECTION EXISTING IN PARTIAL -->
<script src="../assets/layouts/layout/scripts/layout.min.js" type="text/javascript"></script>
</body>
</html>
My Partial Views Structure:
#model IEnumerable<Backend.Models.Product>
#{
ViewBag.Title = "Product";
}
#section Style {
SPECIFIC CSS URLS TO THE VIEW
}
HTML CODE
#section Scripts{
SPECIFIC JAVASCRIPT URLS TO THE VIEW
}
I'm doubting the additional {Id} in the URL is what messes the code because the following:
with {Id}
When Id is passed as querystring
How can I get around this issue?
The way you included the css files is not correct!
You should Use ~/ instead of ../. Razor will convert ~ to the root path of your app.
This should work.
<link href="~/assets/global/plugins/bootstrap-switch/css/bootstrap-switch.min.css" rel="stylesheet" type="text/css" />
Assuming assets folder is in your app root.
With this your link's won't be broken irrespective of what page/url you are on.
You should do the same for including js files also.
Sounds like you are missing your shared layout. If you have something like this toward the top of the edit cshtml try taking it out.
#{
Layout = null;
}
If that's not there, maybe you need to specify the layout, you can just replicate whatever is in your create cshtml, for example:
#{
Layout = "~/Views/Shared/MyLayoutPage.cshtml";
}
This is the scenario:
I have layout : main.gsp
and have a page on which this layout is applied: homepage.gsp
I have a div in main.gsp where I display flash message if any.
Now,
when controller sends any flash message, its available in homepage.gsp but when layout is applied on it and page is displayed, flash message is lost.
I want flash message to be available in layout code.
Again, it would be preferable if I need not add any code to homepage.gsp as there are many such pages where controller can return flash message.
How do I handle this?
Any help much appreciated.
This is the code I will used, I have tested and it work.
main.gsp
<body>
<div id="grailsLogo" role="banner"><img src="${resource(dir: 'images', file: 'grails_logo.png')}" alt="Grails"/></div>
<div>
<g:if test="${flash.message }">
${flash.message }
</g:if>
</div>
<g:layoutBody/>
<div class="footer" role="contentinfo"></div>
<div id="spinner" class="spinner" style="display:none;"><g:message code="spinner.alt" default="Loading…"/></div>
<r:layoutResources />
</body>
Controller:
package com.mtsinai
class EmployeeController {
def index() {
flash.message = 'Welcome world'
}
}
index.gsp
<%# page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"/>
<meta name="layout" content="main"/>
<title>Insert title here</title>
</head>
<body>
<div class="body">
</div>
</body>
</html>
Note that the flash message will be displayed on top of the body or the page that will be rendered
<g:if test="${!request?.xhr}">
<!doctype html>
<html>
<head>
<meta name="layout" content="home">
</head>
<body>
<div class="row-fluid">
</g:if>
AJAX
<g:if test="${!request?.xhr}">
</div>
</body>
</html>
</g:if>
I get error: Grails tag [sitemesh:captureBody] was not closed.
In Config.groovy I set grails.views.gsp.sitemesh.preprocess = false but this doesn't help.
What way to use partial view with if statement.
A better way to handle this in grails is to wrap a template containing the main content. For example:
//_body.gsp
AJAX
//view.gsp
<!doctype html>
<html>
<head>
<meta name="layout" content="home">
</head>
<body>
<div class="row-fluid">
<g:render template="body">
</div>
</body>
</html>
Then your controller can render the whole view on a regular request, or just the body on AJAX.
You can check request.xhr in the controller, and determine to render a template or a string based on the results of that if statement.
this is edit of my question that was first how to apply 2 layouts in the same gsp page but now i got problem with 3 layouts :) :
I am fairly new to all that css and layout stuff and i'm using grails 2.0 version
i have the following moduls in my problem:
1. main.gsp layout which basically have a nice header with company logo for all pages.
2. mainTabPanle.gsp layouts which basically contain some main tabs all pages should have
3. reportTab.gsp layout which basically contain nice report tabs and short javascript code to manipulate chosen tab color that all reports gsp pages should have.
what i am trying to do is to use this reportTab layout in all the reports gsp pages.
so this is what i got so far:
main.gsp:
<!doctype html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"type="text/css">
<g:layoutHead/>
<r:layoutResources />
</head>
<body style="height:100%">
<div>some nice header in here </div>
<g:layoutBody/>
<r:layoutResources />
</body>
</html>
mainTabPanle.gsp (also located in layout folder)
<g:applyLayout name="main">
<!doctype html>
<html>
<head>
<g:layoutHead/>
<r:layoutResources />
</head>
<body>
<div>some main tabs here </div>
<g:layoutBody/>
</body>
<script type="text/javascript">
//script to manipulate main tabs
</script>
<r:layoutResources />
</body>
</html>
</g:applyLayout>
reportTabPanel.gsp:
<g:applyLayout name="mainTabPanel">
<!doctype html>
<html>
<head>
<g:layoutHead/>
<r:layoutResources />
</head>
<body>
<div>some reports tab panel </div>
<g:layoutBody/>
</body>
<script type="text/javascript">
//some script to manipulate report tab item
</script>
<r:layoutResources />
</body>
</html>
</g:applyLayout>
and now im using in moneyreport.gsp header the following line:
<meta name="layout" content="reportTabPanel" />
what i want to see is the nice header and the maintabsPanel and the reportTabPanel but all i see is the body of moneyreport.gsp
the weird thing is that if i use this:
<meta name="layout" content="mainTabPanel" />
inside moneyreport.gsp i see mainTab and the body of moneyreport.gsp as expected.
what am i doing wrong? i cannot use 3 layout on the same page?
thanks for your help guys ...
You can apply 2 layouts on the same page. In order to apply a different layout in a layout file, you need to use the applyLayout tag. Your reportTab should be something like this:
<g:applyLayout name="main">
<!doctype html>
<head>
<g:layoutHead/>
<r:layoutResources />
</head>
<body>
<div> some nice tabs here </div>
<g:layoutBody/>
</body>
<script type="text/javascript">
few line script handling chosen tab color in here
</script>
<r:layoutResources />
</body>
</html>
</g:applyLayout>
The best way is using templates because you can use as many as you want. I have this main HTML where I want to include different templates, like a menu and a generic content page:
<!doctype html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<title>
<g:layoutTitle default="Loto Tasks"/>
</title>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<g:layoutHead/>
</head>
<!-- Including menu -->
<g:render template="/templates/menu" />
<!-- Including generic content page -->
<g:render template="/templates/genericcontent" />
<g:layoutBody/>
</body>
</html>
I have a package named templates inside a views package, and inside templates I have two files, _menu.gsp and _genericcontent.gsp. The _genericcontent.gsp file looks like the following simple code. I could see that this is a little confusing if I insert a <head> with imports to other files, but you can import in the main file and it works:
_genericcontent.gsp
<div id="mainSearchPanel" class="searchPanel">
Ă—
Filter panel here
</div>
<div id="search-icon" class="animate__animated animate__heartBeat animate__infinite animate__slower">
<i class="fas fa-search fa-2x"></i>
</div>
first thanks for your reply Anuj !
it kind of work but in a wrong way cuz i was getting weird html source:
i was getting 2 headers and 2 body tags so basically grails just copy paste all the layout
together and that wasn't good html page even that the browser display it right!
i found what i needed and that is simply using templates!
for example i have file called "_mainHeader.gsp" which look like this:
<!-- this is my main header for all gsp pages -->
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>IntentIQ Management System</title>
<link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"type="text/css">
<link rel="shortcut icon" href="${resource(dir:'images/myImg',file:'favicon.ico')}" type="image/x-icon">
and from all pages i can use those lines like for example in page1.gsp:
<g:render template="/templates/mainHeader" />
</head>
<body>
<h1> this is page1 with header from mainHeader.gsp template </h1>
</body>
</html>
pay attention for who ever who read this to:
1.temmplate file name are with '_' character
2.the closing body tag in "page1.gsp" is closing the body tag started at "_mainHeader.gsp" file.
so basically this tempaltes stuff is kind of copy paste of parts of gsp pages and its working great!
thanks for your reply never the less!