Grails controllers pass parameters - grails

My controller is the folowing:
def participated = {
def temp = ConferenceUser.get(params.temp)
def prizes = Prizes.findAllByConferenceUser(temp) // find all rooms where current computer is
def subms = Submissions.findAllByConferenceUser(temp) // find all rooms where current computer is
[temp: temp, priz: prizes, subm: subms]
}
But somehow, when I successfully update a conference value, I wanna go back to the initial page (participated) but I don't know how to pass back the params.temp. (if I do a simple redirect, as the controller is expecting params.temp, it will give me an error because I cannot search prizes with a null object as parameter. So, imagine my update controller is the following:
def update = {
def saveParamshere = params.temp
...
...
(code here)
...
...
redirect(action: "participated", params: [temp: saveParamshere])
}
This code isn't working. How can I successfully go back to my main page and pass in params.temp ?

I think the problem may be, that you are calling update action by submitting form (I suppose). Maybe you are not passing temp value from that form? You can do it by embedding temp as hidden input field into form, or apply it to url by param attribute on form tag.
Using hidden field it might be something like this (in your view file):
<g:form controller="somecontroller" action="update">
(...)
<g:hiddenField name="temp" value="${temp}" />
(...)
</g:form>
Using params attribute:
<g:form controller="somecontroller" action="update" params="[temp : temp]">
(...)
</g:form>
I didn't test any of these so there might be some issues, especially in the second approach.

You could put the params in the flash scope, which lives for two requests, or put them in the session and retrieve them that way.
Here is a link to the grails docs on usage of flash scope:
Grails - Controllers - Controller Scopes

Related

How to pass parameters in <a href tag in grails gsp

This is the code I am using in the gsp file to fetch the data to show on the view page:
<datePicker id="startDate" name="startDate" value="${new
Date().minus(2).format('yyyy-MM-dd')}" />
the datepicker I am using in the same page.
Now i need to pass the datepicker parameters to this link
<a id="exportIcon" href="${createLink(controller: entityName, action:
'mrInventoryExcelExport', params: [StartDate:startDate])}" >
the parameter is the startdate which i enter manually in the form
Can anyone tell me how can i achieve this.
You could just use a button & submit the form to the given action then either deal with it in the action directly:
gsp:
<g:actionSubmit name="exportIcon"
action="mrInventoryExcelExport"
value="Export"/>
controller:
def mrInventoryExcelExport() {
def startDate = params.startDate
...
}
Or redirect to another action with the startDate:
gsp:
<g:actionSubmit name="exportIcon"
action="anotherAction"
value="Export"/>
controller:
def anotherAction() {
redirect( controller: 'entityName', action: 'mrInventoryExcelExport', params:[startDate: params.startDate] )
}
You need to understand the mechanics. GSP is a server-side technology. Whatever related you have in there, will be processed and converted to HTML, before it is sent to the client/browser.
Now, what you're asking to include/change a parameter in the link, based on the value picked by user; mind you, the link is already created. No chance? Using JavaScript to create that link is your best bet.
P.S.: Try to see the page source from the browser, for more insight.

Grails best practice on form redirection/rendering

If I have an action def formPage(), I want to be able to save the form on that page, show the form with the previously entered values if there's an error, and show a blank form if it's a success.
My question is: Is it best practice for formPage to call something like saveFormPage(FormPageCommand fpc)? saveFormPage can then render formPage with or without the previously entered values. The problem with this approach is that the user can click the address bar, press enter, and then get a slew of errors since the form hasn't been filled in, and the command object sees all the null or blank values.
Another approach might be to just have a def formPage(FormPageCommand fpc), and ignore errors and just show a blank form if none of the values are filled in.
One might also call saveFormPage(FormPageCommand fpc) and redirect back to formPage() if none of the values are filled in.
What is the best practice here?
Try this example:
Your controller
class MyFormController {
def formPage() {
[cmd: new FormPageCommand()]
}
def saveFormPage(FormPageCommand cmd) {
if (cmd.hasErrors()) {
render view: "formPage", model: [cmd: cmd]
} else {
// Process form
// ......
// Redirect back formPage() to display a new form
redirect action: "formPage"
}
}
}
Your command object
class FormPageCommand {
String optionalValue
String requiredValue
static constraints = {
optionalValue(nullable: true, blank: true)
requiredValue(nullable: false, blank: false)
}
}
Your formPage.gsp
<g:form controller="myForm" action="saveFormPage" method="POST">
<label>Required value *</label>
<g:textField name="requiredValue" value="${cmd.requiredValue}"/>
<g:if test="${cmd.errors.getFieldError('requiredValue')}">
<g:message error="${cmd.errors.getFieldError('requiredValue')}"/>
</g:if>
<label>Optional value</label>
<g:textField name="optionalValue" value="${cmd.optionalValue}"/>
<g:submitButton name="submit"/>
</g:form>
It should serve your need.
Cheers.
I'm not sure I fully understand your question, but to get you started I recommend the book "Grails in Action". It contains a lot of best practices and chapter 7 on data binding and error handling may give you some good advice and ideas.
I encountered this problem before and solved it this way:
My registration form has a button:
<g:submitButton name="register" value="Register" />
So the incoming params map should have the "register" key with "Register" value.
Then I check the existence of this parameter in my controller:
def register(UserRegisterCommand urc) {
if (params.register) {
//some registration actions
}
}
In other words I check in the controller if the "Register" button was clicked, if yes - then perform registration actions. If no - the "register.gsp" is rendered.
I hope this will help.

How to Send a Javascript Variable to a Grails Controller to Query Neo4J

I'm a newbie trying to find uses for Neo4J on Grails.
Basically, I've made 20 grocery item nodes through the Neo4J browser and I want to create a simple Grails site that will let users search a grocery item and visually show the items related to it.
My index.gsp has:
<input id="item" />
My viz.js has:
$('#item').keyup(function() {
var item = $('#item').val();
My Item Domain class has
class Item {
static mapWith = "neo4j"
String name
My ItemController class has:
def index() {
def item = Item.list() [item:item] //No idea, just trying out whatever i find :(
and a query with something like:
def query = Item.cypherStatic ("""start n=node({Item}) match (n)-[r]->(x) where r='partner' return n, x)
Questions:
How can I properly send the JS 'item' variable into the ItemController?
How can I use the 'item' variable to properly query the node names which have a 'partner' relationship with the item?
in addition to Motilals answers, you definetly need a wrapping form with an action that points your controller
like
<g:form controller="itemController" action="index" >
<input type="text" id="item" name="item" value="" />
<input type="submit" value="submit" >
</g:form>
then on clicking submit the for will call your index action and there you could parse the value with
def item = params.item
but it looks more like you want some asynchronous stuff right after keyup-function, therefore you could do sth like this :
$('#item').keyup(function() {
var item = $('#item').val();
$.ajax({
url: "${createLink(controller:'itemController', action:'index')}",
data:"&item="+item
})
.done(function( data ) {
console.log(data)
});
});
in this case, you need to pay attention what your index-action is returning, so you can do in the .done() whatever you want with the response.
also note, that when you name an action "index" it will be available at
.../myproject/item/index
or, and thats important
.../myproject/item/
so if your index method requires the data from the input, it will miss them if a user has gone straight to that url
so your index action would rather render the page with the input
and you define another action for executing your query based on input and returning data
set the item to hidden field and then you can access it directly in your controller using params
here you go:
//in index.gsp add below hidden field and set the hidden filed in your js code
<g:hiddenField name="item" value="" />
$('#item').keyup(function() {
var item = $('#item').val();
//in your controller
def index() {
def item = params.item
print item // you see the value for item
//do your stuff
}
once you have item value you could directly use HQL query or use the domain instance
hope this helps you
Regards
Motilal

Grails - URL mapping/default action and flow

Question -
I've noticed that some applications I test with have calls to another view/controller from an action submit, but when that page is rendered, instead of seeing:
$controller/$page
I see:
$controller/index
Is this an issue with the URL mapping configuration? Default action? Just curious, because it just appears to be the URI mapping to a default instead of the actual action.
view code:
<table>
..
<g:actionSubmit class="stats" action="stats" value="View Stats"/>
..
</table
controller:
def stats() {
def teamId = Team.get(params.id)
def allPlayers = Player.withCriteria {
eq('team', teamId)
and {
eq('isActive', true)
}
}
[allPlayers:allPlayers, teamId:params.id]
}
UrlMapping:
class UrlMappings {
static mappings = {
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}
}
Edit
I actually figured out what it is. Which makes me even more confused.
The grails actionSubmit has an action tied to it. That form was just a normal form, without call:
<g:form>
<g:actionSubmit class="stats" action="stats" value="View Stats"/>
<g:actionSubmit class="schedule" action="schedule" value="View Schedule"/>
<g:form>
So by default, the form redirects the action to $controller/index. If you add an action call in the g:form tag, those two buttons will direct to the correct page, but the URI will now be $controller/$g:form_action.
I guess I don't get the point of the actionSubmit's action if the g:form is needed as a wrapper.
Yes, index is the default action for all controllers. So if you do not specify one, that is the page you will land on for the controller.
It is discussed in further detail on their website. Namely, the rules are:
If only one action is present the default URI for a controller maps to
that action.
If you define an index action which is the action that
handles requests when no action is specified in the URI /book
Alternatively you can set it explicitly with the defaultAction property:
static defaultAction = "list"

Grails pattern to reuse template on error

I have a gsp template, where the data for create view is passed through the controller.
def create = {
def bookInstance = new Book()
bookInstance .properties = params
def map = getDefaultValues()
render(template: "create", model: [bookInstance : bookInstance ,
title: map.title,
somelist: somelist
....])
the gsp template
<g:select optionKey="id" from="${somelist}" name="somelist.id" value="${bookInstance ?.somelist?.id}" noSelection="['null': '']"></g:select>
now, in the save method, if there is an error, it returns currently populated and validated instance (default scaffold implementation)
render(template: "create", model: [bookInstance : bookInstance ])
But the fields in the gsp (error page rendered from save action) is empty. I could see the reason as it looks the value in "${somelist}" , but it is not used in save method. Do i just need to check for null in the gsp and use whichever map is available, or any better method (passing all the map in the save method is not an option) ..
thanks in advance..
I figured it out.. I have to pass the same map as was in the create closure .. the reason why we were passing the maps in create is because we wanted to override the default list.. the populated values in bookInstance is only used to preserve the user selection, but not all the values..

Resources