6.1.3 Models and Views - Reference Documentation
Authors: Graeme Rocher, Peter Ledbrook, Marc Palmer, Jeff Brown, Luke Daley, Burt Beckwith
Version: null
6.1.3 Models and Views
Returning the Model
A model is a Map that the view uses when rendering. The keys within that Map correspond to variable names accessible by the view. There are a couple of ways to return a model. First, you can explicitly return a Map instance:def show() {
[book: Book.get(params.id)]
}The above does not reflect what you should use with the scaffolding views - see the scaffolding section for more details.If no explicit model is returned the controller's properties will be used as the model, thus allowing you to write code like this:
class BookController { List books
List authors def list() {
books = Book.list()
authors = Author.list()
}
}This is possible due to the fact that controllers are prototype scoped. In other words a new controller is created for each request. Otherwise code such as the above would not be thread-safe, and all users would share the same data.In the above example the
books and authors properties will be available in the view.A more advanced approach is to return an instance of the Spring ModelAndView class:import org.springframework.web.servlet.ModelAndViewdef index() { // get some books just for the index page, perhaps your favorites def favoriteBooks = ... // forward to the list view to show them return new ModelAndView("/book/list", [ bookList : favoriteBooks ]) }
attributesapplication
Selecting the View
In both of the previous two examples there was no code that specified which view to render. So how does Grails know which one to pick? The answer lies in the conventions. Grails will look for a view at the locationgrails-app/views/book/show.gsp for this list action:class BookController {
def show() {
[book: Book.get(params.id)]
}
}def show() {
def map = [book: Book.get(params.id)]
render(view: "display", model: map)
}grails-app/views/book/display.gsp. Notice that Grails automatically qualifies the view location with the book directory of the grails-app/views directory. This is convenient, but to access shared views you need instead you can use an absolute path instead of a relative one:def show() {
def map = [book: Book.get(params.id)]
render(view: "/shared/display", model: map)
}grails-app/views/shared/display.gsp.Grails also supports JSPs as views, so if a GSP isn't found in the expected location but a JSP is, it will be used instead.Rendering a Response
Sometimes it's easier (for example with Ajax applications) to render snippets of text or code to the response directly from the controller. For this, the highly flexiblerender method can be used:render "Hello World!"// write some markup
render {
for (b in books) {
div(id: b.id, b.title)
}
}// render a specific view render(view: 'show')
// render a template for each item in a collection
render(template: 'book_template', collection: Book.list())// render some text with encoding and content type render(text: "<xml>some xml</xml>", contentType: "text/xml", encoding: "UTF-8")
MarkupBuilder to generate HTML for use with the render method be careful of naming clashes between HTML elements and Grails tags, for example:import groovy.xml.MarkupBuilder … def login() { def writer = new StringWriter() def builder = new MarkupBuilder(writer) builder.html { head { title 'Log in' } body { h1 'Hello' form { } } } def html = writer.toString() render html }
MarkupBuilder). To correctly output a <form> element, use the following:def login() {
// …
body {
h1 'Hello'
builder.form {
}
}
// …
}
