Search

Dark theme | Light theme
Showing posts with label GrailsGoodness:GSP. Show all posts
Showing posts with label GrailsGoodness:GSP. Show all posts

December 9, 2013

Grails Goodness: Using Closures for Select Value Rendering

To generate an HTML select we can use the Grails tag <g:select .../>. We use the optionValue attribute to specify a specific property we want to be used as the value. But we can also define a closure for the optionValue attribute to further customize the value that is shown to the user.

Suppose we have a simple domain class Book with a couple of properties. We want to combine multiple properties as the text for the HTML select options. In the following GSP we define first a <g:select .../> tag where we simply use the title property. In the next <g:select .../> tag we use a closure to combine multiple properties.

We can also pass the closure as model property to the GSP from a controller. In a controller we define the transformation in a closure and pass it along to the GSP page. On the GSP we can use this closure as a value for the optionValue attribute of the <g:select .../> tag. The following GSP shows all three scenarios.

<%@ page import="com.mrhaki.grails.sample.Book" contentType="text/html;charset=UTF-8" %>
<html>
<head>
    <title>Simple GSP page</title>
    <meta name="layout" content="main"/>
    <style>
        p { margin-top: 20px; margin-bottom: 5px;}
    </style>
</head>

<body>

    <h1>Select</h1>

    <p>Use title property of book for option values</p>

    <g:select from="${Book.list()}"
          optionKey="id"
          optionValue="title"
          name="bookSimple"/>

    <p>Use closure for optionValue</p>
    <g:select from="${Book.list()}"
              optionKey="id"
              optionValue="${{ book -> "${book.title} - ${book.isbn}" }}"
              name="bookCustom"/>

    <g:set var="bookOptionValueFormatter"
           value="${{ book -> "${book.title} (${book.isbn}, ${book.numberOfPages})" }}"/>

    <p>Use bookOptionValueFormatter that is defined as variable on this page</p>
    <g:select from="${Book.list()}"
              optionKey="id"
              optionValue="${bookOptionValueFormatter}"
              name="bookVar"/>

    <p>Use bookFormatter that is passed as a model property from SampleController.</p>
    <g:select from="${Book.list()}"
              optionKey="id"
              optionValue="${bookFormatter}"
              name="bookModel"/>

</body>


</html>

Here is a sample controller which passes the transformation to the GSP:

package com.mrhaki.grails.sample

class SampleController {

    def index() {
        final formatter = { book -> "$book.title (pages: $book.numberOfPages)" }
        [bookFormatter: formatter]
    }
}

When we run the application and open the page in a web browser we get the following HTML source:

...
<h1>Select</h1>

<p>Use title property of book for option values</p>

<select name="bookSimple" id="bookSimple" >
  <option value="1" >It</option>
  <option value="2" >The Stand</option>
</select>

<p>Use closure for optionValue</p>
<select name="bookVar" id="bookCustom" >
  <option value="1" >It - 0451169514</option>
  <option value="2" >The Stand - 0307743683</option>
</select>

<p>Use bookOptionValueFormatter that is defined as variable on this page</p>
<select name="bookVar" id="bookVar" >
  <option value="1" >It (0451169514, 1104)</option>
  <option value="2" >The Stand (0307743683, 1472)</option>
</select>

<p>Use bookFormatter that is passed as a model property from SampleController.</p>
<select name="bookModel" id="bookModel" >
  <option value="1" >It (pages: 1104)</option>
  <option value="2" >The Stand (pages: 1472)</option>
</select>
...

The optionKey attribute also allows closures as arguments.

Code written with Grails 2.3.2.

November 18, 2013

Grails Goodness: Generating Raw Output with Raw Codec

Since Grails 2.3 all ${} expression output is automatically escaped on GSPs. This is very useful, because user input is now escaped and any HTML or JavaScript in the input value is escaped and not interpreted by the browser as HTML or JavaScript. This is done so our Grails application is protected from Cross Site Scripting (XSS) attacks.

But sometimes we do want to output unescaped HTML content in the web browser. For example we generate the value ourselves and we know the value is safe and cannot be misused for XSS attacks. In Grails 2.3 we can use a new raw() method in our GSPs, tag libraries or controllers. The method will leave the content unchanged and return the unescaped value to be displayed. Alternatively we can use encodeAsRaw() on the content we want to leave unescaped. Finally the encodeAs tag accepts Raw or None as values for the attribute codec and will return the unescaped value.

In the following sample GSP we display the value of the content model property passed to the page. The value is set by a controller and is <em>sample</em> content.

...
  <h2>Raw output samples</h2>

  <table>
      <tr><th>Expression</th><th>Result</th></tr>
      <tr>
          <td>${'${content}'}</td>
          <td>${content}</td>
      </tr>
      <tr>
          <td>${'${raw(content)}'}</td>
          <td>${raw(content)}</td></tr>
      <tr>
          <td>${'${content.encodeAsRaw()}'}</td>
          <td>${content.encodeAsRaw()}</td>
      </tr>
      <tr>
          <td>${'<g:encodeAs codec="Raw">${content}</g:encodeAs>'}</td>
          <td><g:encodeAs codec="Raw">${content}</g:encodeAs></td>
      </tr>
      <tr>
          <td>${'<g:encodeAs codec="None">${content}</g:encodeAs>'}</td>
          <td><g:encodeAs codec="None">${content}</g:encodeAs></td>
      </tr>
  </table>
...

In our web browser we see the following output:

Code written with Grails 2.3.

August 28, 2013

Grails Goodness: Use Services in GSP with g:set Tag

In Grails we can use the set tag to define a variable with a value on a GSP. But we can also use the same tag to access a Grails service on a GSP. We must use the bean attribute with the name of the Grails service. We can even pass the name of any Spring managed bean in the application context of our application.

In the following sample GSP we access a Grails service with the name BlogService. We invoke the method allTitles() and use the result.

<html>
<head>
    <meta content="main" name="layout"/>
</head>
<body>
%{--Use BlogService--}%
<g:set var="blog" bean="blogService"/>

<ul>
    <g:each in="${blog.allTitles()}" var="title">
        <li>${title}</li>
    </g:each>
</ul>

</body>
</html>

June 3, 2013

Grails Goodness: Compiling GSP from the Command-Line

Normally Groovy Server Pages (GSP) are compiled to class files when we create a WAR file of our application. If we want to compile the GSP without creating a WAR file we use the command-line argument ---gsp. Grails will compile the source code of our application and also the Groovy Server Pages. This way we can detect for examples faulty import statements in the GSP source code.

$ grails compile ---gsp 
...
| Compiling 12 GSP files for package [sampleGrails]
...

Code written with Grails 2.2.2.

March 5, 2012

Grails Goodness: Render GSP Views And Templates Outside Controllers

In a Grails application we use Groovy Server Pages (GSP) views and templates to create content we want to display in the web browser. Since Grails 2 we can use the groovyPageRenderer instance to render GSP views and templates outside a controller. For example we can render content in a service or other classes outside the scope of a web request.

The groovyPageRenderer instance is of type grails.gsp.PageRenderer and has a render() method like we use in a controller. We can pass a view or template name together with a model of data to be used in the GSP. The result is a String value.
The class also contains a renderTo() method that can be used to generate output to a Writer object. For example we can generate files with the output of the GSP rendering by passing a FileWriter instance to this method.

In the following sample we create a GSP view confirm.gsp and a GSP template _welcome.gsp. We also create a Grails service with two methods to use the GSP view and template.

%{-- File: grails-app/views/email/_welcome.gsp --}%
Hi, ${username}
%{-- File: grails-app/views/email/confirm.gsp --}%
<!doctype html>
<head>
    <title>Confirmation</title>
</head>

<body>

<h2><g:render template="/email/welcome" model="[username: username]"/></h2>

<p>
    Thank you for your registration.
</p>

</body>
</html>
// File: grails-app/services/page/renderer/RenderService.groovy
package page.renderer

import grails.gsp.PageRenderer

class RenderService {

    /**
     * Use the variable name groovyPageRenderer to enable
     * automatic Spring bean binding. Notice the variable
     * starts with groovy..., could be cause of confusing because
     * the type is PageRenderer without prefix Groovy....
     */
    PageRenderer groovyPageRenderer

    String createConfirmMessage() {
        groovyPageRenderer.render view: '/email/confirm', model: [username: findUsername()]
    }

    String createWelcomeMessage() {
        groovyPageRenderer.render template: '/email/welcome', model: [username: findUsername()]
    }

    private String findUsername() {
        // Lookup username, for this example we return a
        // simple String value.
        'mrhaki'
    }
}

Next we create a integration test to see if our content is rendered correctly:

// File: test/integration/page/renderer/RenderOutputTests.groovy
package page.renderer

import org.junit.Assert
import org.junit.Test

class RenderOutputTests {

    RenderService renderService

    @Test
    void welcomeMessage() {
        Assert.assertEquals 'Hi, mrhaki', renderService.createWelcomeMessage().trim()
    }

    @Test
    void confirmMessage() {
        final String expectedOutput = '''
        <!doctype html>
        <head>
            <title>Confirmation</title>
        </head>

        <body>

        <h2>
        Hi, mrhaki</h2>

        <p>
            Thank you for your registration.
        </p>

        </body>
        </html>'''

        Assert.assertEquals expectedOutput.stripIndent(), renderService.createConfirmMessage()
    }
}

We can run our test and everything is okay:

$ grails test-app RenderOutputTests
| Completed 2 integration tests, 0 failed in 1051ms
| Tests PASSED - view reports in target/test-reports

We can use tags from tag libraries in our GSP views and templates. The Sitemesh layouts cannot be used. The PageRenderer works outside of the request scope, which is necessary for the Sitemesh layouts. Because we are outside of the web request scope we cannot generate absolute links in the GSP view directly. If we change the confirm GSP view and add a tag to create an absolute link we get an UnsupportedOperationExeption with the message You cannot read the server port in non-request rendering operations.

%{-- File: grails-app/views/email/confirm.gsp --}%
<!doctype html>
<head>
    <title>Confirmation</title>
</head>

<body>

<h2><g:render template="/email/welcome" model="[username: username]"/></h2>

<p>
    Thank you for your registration.
</p>

<p>
    To use the application can you directly go to the
    <g:link absolute="true" controller="index">home page</g:link>.
</p>

</body>
</html>

But we can simply workaround this issue. Remember that since Grails 2 we can use the grailsLinkGenerator to generate links in for example a service. So we create our absolute link with the grailsLinkGenerator and pass it as a model attribute to our GPS view.

package page.renderer

import grails.gsp.PageRenderer
import org.codehaus.groovy.grails.web.mapping.LinkGenerator

class RenderService {

    PageRenderer groovyPageRenderer

    LinkGenerator grailsLinkGenerator

    String createConfirmMessage() {
        final String homePageLink = grailsLinkGenerator.link(controller: 'index', absolute: true)
        groovyPageRenderer.render(view: '/email/confirm', model: [link: homePageLink, username: findUsername()])
    }

    String createWelcomeMessage() {
        groovyPageRenderer.render template: '/email/welcome', model: [username: findUsername()]
    }

    private String findUsername() {
        // Lookup username, for this example we return a
        // simple String value.
        'mrhaki'
    }
}
%{-- File: grails-app/views/email/confirm.gsp --}%
<!doctype html>
<head>
    <title>Confirmation</title>
</head>

<body>

<h2><g:render template="/email/welcome" model="[username: username]"/></h2>

<p>
    Thank you for your registration.
</p>

<p>
    To use the application can you directly go to the
    <a href="${link}">home page</a>.
</p>

</body>
</html>

November 28, 2011

Grails Goodness: Get GrailsApplication and ApplicationContext in GSP

Several variables are injected to Groovy Server Pages (GSP) in a Grails application. Two of them are the ApplicationContext and GrailsApplication objects. They are bound to the variables applicationContext and grailsApplication.

When we have access to the ApplicationContext we could for example load resources or get references to beans in the context. Via the grailsApplication variable we have access to for example the configuration values and metadata of the application.

<%-- File: grails-app/views/view/index.gsp --%>
<html>
    <head>
        <title>GSP Sample</title>
    </head>
    <body>
        <h1>ApplicationContext</h1>

        <dl>
            <dt>applicationContext</dt>
            <dd>${applicationContext}</dd>
            <dt># beans</dt>
            <dd>${applicationContext.beanDefinitionCount}</dd>
            <dt>beans</dt>
            <dd>${applicationContext.beanDefinitionNames.join(', ')}</dd>
        </dl>

        <h1>GrailsApplication</h1>

        <dl>
            <dt>grailsApplication</dt>
            <dd>${grailsApplication}</dd>
            <dt>configuration</dt>
            <dd>${grailsApplication.config}</dd>
            <dt>metadata</dt>
            <dd>${grailsApplication.metadata}</dd>
        </dl>
    </body>
</html>

When we open this GSP in our browser we get the following output:


November 25, 2011

Grails Goodness: Access Action and Controller Name in GSP

In our GSP views we can see the name of the action and controller that resulted in the view. We can use this for example to show or hide certain information based on the values for the action and controller name. Grails injects the variables actionName and controllerName automatically and sets the values based on the action and controller.

// File: grails-app/controller/com/mrhaki/sample/ViewController.groovy
package com.mrhaki.sample

class ViewController {

    def index = {}
}
<%-- File: grails-app/views/view/index.gsp --%>
<html>
    <head>
        <title>GSP Sample</title>
    </head>
    <body>
        <h1>Action and Controller Name</h1>

        <ul>
            <li>controllerName: <strong>${controllerName}</strong></li>
            <li>actionName: <strong>${actionName}</strong></li>
        </ul>
    </body>
</html>

When we open the GSP we get the following output:


April 13, 2011

Grails Goodness: Applying Layouts in Layouts Revisited

In the blog post Applying Layouts in Layouts we learned how to reuse layouts in a Grails application. Peter Ledbrook added a comment suggesting to use the <g:applyLayout/> in the Groovy Server Pages in the layouts directory instead of in the views. So this way we can use the default method of applying layouts in our views (using for example the <meta/> tag) and keep all <g:applyLayout/> tags in the layout pages. In this post we see how we can support this for our applications and still reuse the layouts like before.

Please read the previous blog post to see the layout structure of our sample Grails application. The main layout page is still grails-app/views/layouts/page.gsp and doesn't need to be changed:

<%-- File: grails-app/views/layouts/page.gsp --%>
<!DOCTYPE html>
<html>
<head>
    <title><g:layoutTitle default="Grails"/></title>
    <link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"/>
    <link rel="stylesheet" href="${resource(dir: 'css', file: 'layout.css')}"/>
    <link rel="stylesheet" href="${resource(dir: 'css', file: 'fonts.css')}"/>
    <link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon"/>
    <g:layoutHead/>
</head>
<body>
<div id="header" class="clearfix">
    <div id="logo">
        <g:link uri="/"><g:message code="nav.home"/></g:link>
        <p><g:message code="title.website"/></p>
    </div>

    <div id="searchform">
        <g:form controller="search">
            <fieldset class="search">
                <input type="text" class="search-input" value="${message(code:'search.box.search')}" name="search" id="search-phrase" maxlength="100"/>
                <input type="submit" value="${message(code: 'search.box.submit')}" />
            </fieldset>
        </g:form>
    </div>

    <div id="navmenu">
        <ul>
            <li><g:link uri="/"><g:message code="nav.home"/></g:link></li>
            <li><g:link controller="product" action="list"><g:message code="nav.products"/></g:link></li>
        </ul>
    </div>
</div>

<g:layoutBody/>

<div id="footer">
    <p>Copyright © 2011 Hubert A. Klein Ikkink - <a href="http://www.mrhaki.com">mrhaki</a></p>
</div>
</body>
</html>

The layout for the homepage is defined by fiveblocks.gsp in the layouts directory. We change this file and use <g:applyLayout/> to apply the main page layout instead of using <meta name="layout" content="page"/>:

<%-- File: grails-app/views/layouts/fiveblocks.gsp --%>
<g:applyLayout name="page">
    <html>
    <head>
        <title><g:layoutTitle/></title>
        <g:layoutHead/>
    </head>
    <body>
    <div id="banner">
        <g:pageProperty name="page.banner"/>
    </div>

    <div id="left">
        <g:pageProperty name="page.left1"/>
        <g:pageProperty name="page.left2"/>
        <g:pageProperty name="page.left3"/>

        <div id="box-left">
            <g:pageProperty name="page.box-left"/>
        </div>

        <div id="box-right">
            <g:pageProperty name="page.box-right"/>
        </div>
    </div>

    <div id="right">
        <g:pageProperty name="page.right1"/>
        <g:pageProperty name="page.right2"/>
        <g:pageProperty name="page.right3"/>
    </div>
    </body>
    </html>
</g:applyLayout>

And now we use <meta name="layout" content="fiveblocks"/> in the homepage Groovy server page and define the content for our Sitemesh content blocks.

<%-- File: grails-app/views/templates/homepage.gsp --%>
<html>
<head>
    <meta name="layout" content="fiveblocks"/>
    <title><g:message code="title.homepage"/></title>
</head>
<body>
<content tag="banner">
    <h1>Welcome to Grails Layout Demo</h1>
</content>

<content tag="left1">
    <p>...</p>
</content>

<content tag="box-left">
    <p>...</p>
</content>

<content tag="box-right">
    <p>...</p>
</content>

<content tag="right1"> 
    <p>...</p> 
</content> 
</body> 
</html> 

We notice the changes aren't big compared to the previous solution, but using <meta name="layout" content="..."/> in the views is more compliant to what we already learned when using layouts in views.

Also keep in mind Peter Ledbrook's warning about having layouts nested more than one deep:

Finally, if you do have layouts nested more than one deep (not necessarily a good idea, but that's what grails.org is currently doing) then it's worth noting that every layout must have the <g:layout*/> and <g:pageProperty/> tags, otherwise the contents don't propagate properly.

Sources of the sample Grails application can be found at GitHub.