can't display model in gsp page - grails

So I've just started using Grails/Groovy for my senior capstone project and I'm having a bit of a rocky start. The issue I'm having is when I set up a mapping of my model in the controller I can loop through it and print it to the console but when I try and access it from the view I get blank page.
The Domain class is simple:
package ot
class CrewDeskMapping {
String crewDesk
String desk
}
And the Bootstrap file that creates the test data:
...
new CrewDeskMapping(crewDesk:"North",desk:"MON1").save()
new CrewDeskMapping(crewDesk:"North",desk:"TWI1").save()
new CrewDeskMapping(crewDesk:"North",desk:"NWE1").save()
...
Here is my controller:
import ot.CrewDeskMapping;
class DashboardController {
def index() {
def desks = CrewDeskMapping.list()
[desks:desks]
for (d in desks) {
System.out.println(d.desk);
}
}
}
and the console output looks as it should:
MON1
TWI1
NWE1
CHI1
COL1
...
And the relevant part of my index.gsp
<body>
<g:each in="${desks}">
<p>Title: ${it.crewDesk}</p>
<p>Author: ${it.desk}</p>
</g:each>
</body>
The most perplexing part is if I try this same code but with a different Domain it works just fine. I've been at this problem for a couple days now with no avail so any help would be greatly appreciated!

def desks = CrewDeskMapping.list()
[desks:desks]
for (d in desks) { ...
does not return your [desks: desks]
Swap the for and the [desks: ...] or add a proper return statement at the end like this:
def index() {
def desks = CrewDeskMapping.list()
desks.each{ log.debug it.desk } // groovier debug print
// must be last in the method like a regular return in java,
// but groovy allows implicit return of the last statement
/*return*/ [desks:desks]
}

Related

GRAILS: findALL() vs FindBy---(params.id)

Greeting everyone,
I am trying to pass a parameters from a URL to a findAll() method.
LINE3 I use findAll() to define mouse.
LINE2 def house will bring in the parameter DELAWARE when I go to the page: http://localhost:8080/TestApp/home/county/DELAWARE
House will only show one instance instead of a list.. is there anyway to pass the url instead of ["DELAWARE"]? (please see line 3) thanks :)
def county() {
def house = Home.findByCounty(params.id) //sends only user related address to view
def mouse = Home.findAll("from Home h where h.county= ?", ["DELAWARE"]);
if (!house) {
response.sendError(404)
} else {
[house:house, mouse:mouse ]
}
}
Working Code +1 #Danilo
def county() {
def house = Home.findAllByCounty (params.id) //sends only county specified thru URL e.g. http://localhost:8080/TestAPP/home/county/DELAWARE
if (!house) {
response.sendError(404)
} else {
[house:house ]
}
}
findBy* will return at most one row, if you want to get all rows use findAllBy*
In order to understand how the URL will be used by Grails you have to have a look at conf/UrlMappings.groovy. You may find something like this:
static mappings = {
"/$controller/$action?/$id?(.$format)?"{
}
}
this means that when you call TestApp/home/county/DELAWARE what Grails is trying to do is use the home controller (HomeController), invoking the county method (def county(){...}) and passing DELAWARE as id.
This should work correctly if inside county method of the HomeController you have:
def filteredInstances = Home.findAllByCounty(params.id)

how to make Drop Down Lists in gsp from BootStrap.groovy

I want to make a drop down using the data given in the BootStrap.groovy.
My City domain class
package city.model
class City {
String cityName
static constraints = {
cityName(maxSize: 50) }
}
In my Service class
public class CityService {
def citySelect(String cityName) //this is just a sample
{
City city = new City()
city.cityName = city.findByCityName(cityName)
}
}
controller
public class CityController {
def cityService
def
def selCity() {
def selectCity = cityService.citySelect(params.cityName){
if(selectCity != null){
render view // my view
}
else{
render view // error select again view
}
}
}
BootStrap.groovy
import city.City;
class BootStrap {
def init = { servletContext ->
for(String cityName in ['Addis Ababa', 'Semera','Asosa','Gondar', 'Jijiga','Harar', 'Dire Dawa', 'Bahir Dar',
'Hawassa', 'Arba Minch', 'Adama', 'Mekelle']) {
City.findOrSaveByCityName(cityName).save()
}
}
def destroy = {
}
}
i used this
<g:select name="cities" from="${City.list()}" optionKey="id" optionValue="cityName"/>
in my view but showing error cannot envoke method list on null object
What is wrong within mu code and what should i do to make it work. please any suggestions
<g:select name="city" from="${city.model.City.list()}" optionValue="${cityName}"
noSelection="['':'-Please select the City-']" optionKey="id"/>
this could work fine.
Maybe you have misunderstood the point of Bootstrap.
Bootstrap as per the naming convention is the part that is triggered when your site is booting up.
You would typically use it to ensure required db table records are generated before it has booted up i.e. admin account or in your case generation of some cities.
You would not be using Bootstrap to interact with the records you generated in the way of editing or selecting.
Once this has all be done and saved - you would have also used the Controllers/Views to list/view/update/add cities.
You would create your g:select tags in these views and matching controllers that would query the records you have saved via bootstrap
E2A:
Ok Just read your comment
Either use an import on the top of your gsp
<%# page import="city.City" %>
or call full packaged path to City domainClass city.City.list
<g:select name="cities" from="${city.City.list()}" optionKey="id" optionValue="cityName"/>
To create a list of the Cities you inserted into the Database in the Bootstrap.groovy (in a view i.e [viewName].gsp)
Mark up is like so
<g:select name="city" from="${city.model.City.list()}" value="${city.name}"
noSelection="['':'-Please select the City-']" optionKey="id"/>
However, the Bootstrap should be for initialization of Database and Application defaults, Also to perform start (Startup in the init closure while shutdown in the destroy Closure).
This should work:
<g:select name="cities" from="${city.model.City.list()}"
optionKey="id" optionValue="cityName"/>
However, executing queries like city.model.City.list() in a GSP is not a recommended practice. Instead you should retrieve your data (the list of cities) in a controller action or a service and pass that via the model to the GSP.

Grails Web Flow - passing map to first step/state

I'm learning Grails so forgive me if I'm missing something basic.
I'm trying to create a wizard/web flow using the Grails Web Flow plugin. I'd like for the first step of the flow to render some variables. From what I've read about normal controllers, typically this would be done by passing those variables from the controller to the view using a map. In the WebFlow model though, I don't know where to initialize these variables and how to pass them to the first step. I tried creating an initialize "action" and putting the variable into the flash scope, knowing that it should pass through one redirect, but it doesn't render on the gsp.
How is this done?
Here's a snip of the controller, which prints "4" in the console:
class ServicesController {
def index() {
redirect(action: "initialize")
}
def initialize() {
flash.assessmentTypes = AssessmentType.list()
println flash.assessmentTypes.size
redirect(action: "request")
}
def requestFlow = {
selectAssessments {
on("next") {
// capture assessments
}.to("productInfo")
on("cancel").to("finish")
}
...
And a snip of the gsp, which throws a nullpointer when rendering the size:
${flash.assessmentTypes.size}
<g:each var="assessmentType" in="${flash.assessmentTypes}">
<li><g:checkbox name="assessmentType" value="${assessmentType.id}" />${assessmentType.name}</li>
</g:each>
No problem...
Use a flow initializer to act as the first step in the flow and then move it to the first step on success of the initFlow.
def wizardFlow = {
initFlow {
flow.assessmentTypes = AssessmentType.list(); //<-- put them in the flow so you can access it in step1.gsp
}
on('success').to('step1')
on(Exception).to('handleFlowError')
step1{
on('next'){
flow.asessmentType = AssessmentType.get(params.assessmentType.id);
println("They picked ${flow.asessmentType}.");
}.to('step2')
on('exit').to('exit')
}
step2{
on('next'){ /* do stuff */ }.to('finish')
on('previous').to('step1')
on('exit').to('exit')
}
exit( /* exit flow before finish */ )
finish( /* finish up */ )
handleFlowError( */ not good :( */)
}
step1 GSP....
<g:select name="assessmentType.id" from="${assessmentTypes}" optionKey="id" value="${assessmentType?.id}" />
This is untested but it should work just fine. Enjoy :)

Grains repetead code for actions in controllers

I have already posted this question, but i realised the aswer was not what i was looking for. Imagine this controller:
class exampleController{
def action1 = {
...
[lala: lala, lele: lele]}
...
}
def action15 = {
...
[lala: lala, lele: lele]
}
I want to be able to return in all the action in this controller the same params. Imagining this:
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
Is there any way of doing this, besides writing all the same code on all the actions? I have tried this method and it isnt working:
def action5 = {getModel()}
private getModel() {
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
}
}
It is not working because, and my thought is, he doest accept multiple [return1: aaa, return2: bbb]. Any suggestion please ? I have also tried filters like in here: Grails controllers repeated code for all actions
but i couldnt managed to make it work. I would apreciated a detailed explanaintion about any of the solutions if possible:p Thanks in advanced,
VA
So it's not the same model, but a model with a repeated part.
You should know that the return value is an ordinary Map.
So, return value can be constructed like return getCommonModel() + [book: currentBook] where getCommonModel() returns another Map.
If you want to return the same model from all your actions, this approach should work:
class ExampleController {
def action5 = {getModel()}
def action1 = {getModel()}
//etc.
private getModel() {
def book = Book.findAllByIsbn(Isbn.get(1))
[book: book]
}
}
If you want to return the same model and render the same view from all your actions, you could return the same ModelAndView from each action, but then I would ask why do you need separate actions if they're all doing exactly the same thing?
I don't really understand your hypothesis
It is not working because, and my thought is, he doest accept multiple [return1: aaa, return2: bbb]
If your suggesting that getModel() can only return a model with a single entry, I find that very hard to believe. Can you elaborate a bit on this, or post some more information (e.g. stacktrace, unit test) that shows how/why it's not working?
Update
After reading your comments below I think I finally understand what you want to achieve, which is to append the model returned by getModel() (above) to the model returned by various other actions. Does this work:
class ExampleController {
def action5 = {
def action5Model = [foo: 'bar']
return addBookModel(action5Model)
}
def action1 = {
def action1Model = [foo2: 'bar2']
return addBookModel(action1Model)
}
//etc.
private Map addBookModel(Map model) {
def book = Book.findAllByIsbn(Isbn.get(1))
model.book = book
return model
}
}
This approach will only work when you want to add the book model within a single controller. If you want to add the book model in several controllers you can do this by:
putting addBookModel in an abstract class that the controllers extend
putting addBookModel in a class that is mixed-in with the controllers (using #Mixin)
putting addBookModel in a filter that is executed after the controller actions
If you are using exact same model in multiple pages. I would recommend you use a taglib for it.

Sending data to "View" from "Controller"

In my controller class have the following code
class MyController {
def flickrService
def index = {
def data = flickrService.search {
tags 'tag,tag2,tag3'
page 3
perPage 14 // Look ma!
}
[urls:data.urls,page:data.page,pages:data.pages]
}
}
I have also created an index.gsp file.
As I am new to groovy grails - i could not figure it out how to access data returned by flickrservice in the view. Can I just access "data" defined above in the index view or I need to set it in the controller before I can loop through the returned data? Any help would be highly appreciated. Thanks
Yes, now you can access data from the view, for example,in index.gsp:
<html><head>Test</head><body>${urls} <br/> ${page} </body></html>
Generally saying, grails return the last value in function by default, so if you want to access many data, you can do like this:
class MyController {
def flickrService
def index = {
def data = ...
def data1 = ...
def data2 = ...
// Here's the return result:
[view_data:data,view_data1:data1, view_data2:data2]
}
}
Then you can access ${view_data},${view_data1},${view_data2} in view.

Resources