Flash message contents lost in layout - grails

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

Related

MVC Login Page with Custom Layout and ViewStart

I have a problem I cannot wrap my head around, it is driving me crazy. I used the default template for MVC projects in VS2013 and everything works fine. I can login with users I've created using the Forms Authentication, etc. The problem I have is that when I drop a _ViewStart into the Account views folder, and use a custom layout for the login pages ... I keep getting redirected to the login page everytime I try to login. My Login Post method is also not being called, only the Default Login ActionResult fires. If I take the ViewStart file out and use the default layout, I have no problems.
Here is my _LoginLayout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Corporate</title>
<link rel="stylesheet" type="text/css" href="~/Content/style.css">
#Scripts.Render("~/bundles/modernizr")
#Scripts.Render("~/Scripts/jquery-1.10.2.min.js")
</head>
<body>
<div class="holder login">
<div class="row">
<div class="col-lg-5 left">
<img src="~/images/logo.png" alt="logo" />
</div>
</div>
<div class="row">
<div class="col-lg-6 border">
<img src="~/images/corporate.png" alt="corporate" />
<br />
<form>
#RenderBody()
</form>
</div>
</div>
<footer>
<p>© #DateTime.Now.Year - Application. All Rights Reserved.</p>
</footer>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</div>
</body>
</html>
Here is the ViewStart...
#{
Layout = "~/Views/Shared/_LoginLayout.cshtml";
}
The login page is basically the same boiler plate page provided when you start the project. Everything works until I start trying to use a custom layout and viewstart.
Ok. I'm dumb.
#using (Html.BeginForm("Login", "Account",....
Creates Form tags. My layout had Form tags wrapping the RenderBody(). I was essentially nesting form tags which is a nono. Mystery solved.
It's the little things that get you.

Overloading blocks with dust.js for nested templates

I have a layout called layouts/master.dust
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{+title /}</title>
<link rel="stylesheet" href="css/app.css" />
</head>
<body>
<div id="wrapper">
<h3>This is the master header</h3>
{+body /}
</div>
</body>
</html>
I then have a template called index.dust:
{>"layouts/master" /}
{<body}
<h1>{#pre type="content" key="greeting"/}</h1>
{/body}
Predictably, that outputs
This is the master header
Hello, Alex!
(when supplied with the relevant json)
My issue is, I'm creating another "nested" or "child" template: layouts/admin.dust that looks like:
{>"layouts/master" /}
<h4>This is an admin header</h4>
{+body /}
and a template adminIndex.dust that uses layouts/admin/dust like this:
{>"layouts/admin" /}
{<body}
<p>This is some stuff for admin</p>
{/body}
My problem, is the output is:
This is the master header
This is some stuff for admin
This is an admin header
This is some stuff for admin
So, my {+body} block is being called twice, and not overridden by my nested template
Is there a way to do that?
Edit
As per my comment, a more 'realistic' example of admin.dust would be:
{>"layouts/master" /}
<h4>This is an admin header</h4>
<div style="float: left; width: 200px;">
<strong>left nav</strong>
<ul>
<li>Link one</li>
<li>Link two</li>
</ul>
</div>
<div style="float: right">
{+ body /}
</div>
Where by in templates that use the admin layout, their body is in a div floated right (for example)
Your {+body} block is being overridden by your {<body} inline partial in your adminIndex.dust template. The contents of an inline partial (in your case <p>This is some stuff for admin</p>) will be inserted wherever a block is found in your template. If you are hoping to have the master header be replaced by the admin header, you would need your templates to look like this:
layouts/master.dust
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>{+title /}</title>
<link rel="stylesheet" href="css/app.css" />
</head>
<body>
<div id="wrapper">
{+header}<h3>This is the master header</h3>{/header}
{+body /}
</div>
</body>
</html>
layouts/admin.dust
{>"layouts/master" /}
{+header}<h4>This is an admin header</h4>{/header}
adminIndex.dust requires no change.
Note: I have added a {+header} block to layouts/master.dust with a default value, and added a {header} inline partial and removed the {+body} block from layouts/admin.dust. This will output:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
<link rel="stylesheet" href="css/app.css" />
</head>
<body>
<div id="wrapper">
<h3>This is the admin header</h3>
<p>This is some stuff for admin</p>
</div>
</body>
</html>

Why won't JQuery Mobile toolbar appear

I am trying to create a mobile version of my site using JQuery Mobile. I'd like a fixed header toolbar and a fixed footer toolbar to appear on all pages. However, those portions of the page are instead being written out as simple HTML lists. Here is the relevant header code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>Nightscape Creations Wallpapers</title>
<link rel="stylesheet" href="themes/NCMobile.min.css" />
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile.structure-1.3.2.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>
</head>
<div data-role="header" data-position="fixed">
Back
<h1>Nightscape Creations</h1>
Home
<div data-role="navbar">
<ul>
<li>Live Wallpapers</li>
<li>Static Wallpapers</li>
<li>Products</li>
<li>About</li>
</ul>
</div>
</div>
This code is visible at www.NightscapeCreations.com on the mobile site.
It seems like the JQuery code is either not being included correctly or is not being initialized. I'm not sure if maybe I missed something obvious in the installation that I just need a second set of eyes on.
If it's relevant, the remainder of the page might be similar to:
<body>
<div data-role="page" id="home">
Some text
</div>
<div data-role="page" id="liveWallpapers">
Some text
</div>
<div data-role="page" id="products">
Some text
</div>
<div data-role="page" id="about">
Some text
</div>
<div data-role="page" id="staticWallpapers">
Some text
</div>
</body>
<div data-role="footer" data-position="fixed">
<h1>All images, animations, and content © Nightscape Creations</h1>
Visit Desktop Site
</div>
</html>
EDIT 1
Per a suggestion by mwfire I have moved all of my visible code inside of the body tags. A simplified version of the page is now available with this code:
<!DOCTYPE html>
<html>
<head>
<title>Nightscape Creations Wallpapers</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link rel="stylesheet" href="themes/NCMobile.min.css" />
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.2/jquery.mobile.structure-1.3.2.min.css" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.2/jquery.mobile-1.3.2.min.js"></script>
</head>
<body>
<div data-role="header" data-position="fixed">
Back
<h1>Nightscape Creations</h1>
Home
<div data-role="navbar">
<ul>
<li>Live Wallpapers</li>
<li>Static Wallpapers</li>
<li>Products</li>
<li>About</li>
</ul>
</div>
</div>
<div data-role="page" id="home1">
<div style="font-weight:bold; text-decoration:underline;">Welcome</div>
Welcome to Nightscape Creations Mobile. Here you will find animated live wallpapers, static wallpapers, and links to physical products
with the wallpaper images included. Use the header button above to browse the mobile site, or
click here to visit the main site instead.
</div>
<div data-role="footer" data-position="fixed">
<h1>All images, animations, and content © Nightscape Creations</h1>
Visit Desktop Site
</div>
</body>
</html>
However, this does not cause the toolbars to appear.
Actually all your HTML code belongs inside the body tag. I bet you don't see any footer as well ;)
Edit
Just to clarify, the structure is supposed to be like that:
<!DOCTYPE ...>
<html>
<head>
<title>Page title</title>
</head>
<body>
<!-- All visible HTML content goes here! -->
</body>
</html>
No HTML tags should be outside the body tag (except head, body & Doctype).
You can find more on page structures here.
Edit2
In addition to this, header and footer are supposed to be inside the data-role="page" div. jQuery displays one page at a time, think of it as a single HTML page. It has to include the complete structure of a single page (if you want header and footer, of course), like:
<div data-role="page">
<div data-role="header">
<h1>Test</h1>
</div>
<div data-role="content">
Content
</div>
<div data-role="footer">
<h3>Footer</h3>
</div>
</div>

Mixing single page and multiple page documents in jQuery Mobile

I'm starting with jQuery Mobile and I have a problem. I have two HTML documents:
page1.html
page2.html
page2a
page2b
The problem is the following:
when I browse from page1.html to page2.html, it displays page2a, but I can't browse to page2b
when I browse from page1.html to page2a, it stays on page1.html
when I browse from page2.html to page2a or page2b, it works well
What is wrong with my solution? Is there any good solution to have that working properly?
Here is a code for reference:
Page1.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page 1</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.0-rc.1/jquery.mobile-1.3.0-rc.1.min.css" />
<script src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.0-rc.1/jquery.mobile-1.3.0-rc.1.min.js"></script>
</head>
<body>
<div data-role="page">
<div data-role="header">
<h1>Single page</h1>
</div>
<div data-role="content">
<p>See page 2.</p>
<!-- <p>See page 2a.</p> -->
</div>
</div>
</body>
</html>
Page2.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Page 2</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.3.0-rc.1/jquery.mobile-1.3.0-rc.1.min.css" />
<script src="http://code.jquery.com/jquery-1.9.0.min.js"></script>
<script src="http://code.jquery.com/mobile/1.3.0-rc.1/jquery.mobile-1.3.0-rc.1.min.js"></script>
</head>
<body>
<!-- Start of first page: #a -->
<div data-role="page" id="a">
<div data-role="header">
<h1>Page 2a</h1>
</div>
<div data-role="content" >
<p>Show page "2b"</p>
</div>
</div>
<!-- Start of second page: #b -->
<div data-role="page" id="b">
<div data-role="header">
<h1>Page 2b</h1>
</div>
<div data-role="content">
<p>Back to page "2a"</p>
</div>
</div><!-- /page b -->
</body>
</html>
Check the below question. It seems it only works with data-rel="external".
JQM Multipage
UPDATE:
Note: You cannot link to a multipage document with Ajax navigation active because the framework will only load the first page it finds, not the full set of internal pages. In these cases, you must link without Ajax (see next section) for a full page refresh to prevent potential hash collisions. There is currently a subpage plugin that makes it possible to load in multi-page documents.
Source: JQM - Linking pages

Grail partial view for ajax request

<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.

Resources