Grails populating a domain instance - grails

I have been stuck for a couple of days on the same problem and I am not getting anywhere.
I am using a g:formRemote tag to update a messages template
<g:formRemote url="[action: 'updateStatus']" update="messages" name="updateStatusForm"
onSuccess="document.updateStatusForm.message.value='';">
<g:textArea name="message" value="" cols="3" rows="1"/><br/>
<g:submitButton name="Update Status"/>
</g:formRemote>
This form then calls a updateStatus method in my controller
def updateStatus(String message) {
def status = new Post(message: params.message, author: lookupPerson())
status.save(flush: true, failOnError: true)
def messages = currentUserTimeline()
render template: 'profileMessages', collection: messages, var: 'profileMessage'
}
But the def status line should be
def status = new Post(message: params.message, author: lookupPerson(), child: Child.get(childInstance.id)
In my view I have a childInstance which is the selected by the user. Is there anyway I can have a global variable in the controller which is saved or can I send the child instance params id in the formRemote tag. I don't think there is as i've been trying to do it this way all today.
Any help will be good. The only way I know will work will be to write the childInstance.id to a properties file and read it back in but there must be a better way as I think this would be very bad practice.

You can add params to <g:formRemote>
Example from the grails docs:
<g:formRemote name="myForm" update="updateMe"
url="[controller: 'book', action: 'byAuthor', params: [sort: 'title', order: 'desc']]">
Author: <input name="author" type="text" />
</g:formRemote>

You could probably add a <g:hiddenField name="childId" value="${childInstance.id}"/> to your formRemote Tag and this will send it to the server in the same way message is.

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 paginate turning maps into strings

I am trying to create a search action in my grails app that accepts a number of criteria and displays a table (similar to a default index action) of instances that match the criteria.
For search criteria that have many results I would like to use the paginate tag:
<g:paginate total="${alarmInstanceCount ?: 0}" />
By default, this tag forgets the search criteria. I believe that the params attribute allows me to add the search parameters to the links that the paginate tag creates.
To encapsulate my search criteria, I've organized them into their own map called searchParams.
However, when I try to pass my searchParams to the paginate tag:
<g:paginate total="${alarmInstanceCount ?: 0}" params="${[searchParams:searchParams]}"/>
my searchParams are turned into a string.
Here is an example of what I mean.
When I first open the search page the controller reports the params as follows:
[action:index, format:null, controller:alarm, max:10]
null
class org.codehaus.groovy.runtime.NullObject
So, since the params map doesn't contain an entry for searchParams it comes up as null and has the NullObject class. My code handles this case gracefully.
When I enter some text into the channelName field the controller reports the params as follows:
[searchParams.channelName:SWR, searchParams:[channelName:SWR], _action_index:List, _method:PUT, action:index, format:null, controller:alarm, max:10]
[channelName:SWR]
class org.codehaus.groovy.grails.web.servlet.mvc.GrailsParameterMap
So, now the params map has a searchParams entry which refers to a GrailsParameterMap. This is the desired behaviour, and the controller interprets this correctly.
However, if I click on the first entry in the paginate bar, the controller reports the params as follows:
[max:10, searchParams:[channelName:SWR], offset:10, action:index, format:null, controller:alarm]
[channelName:SWR]
class java.lang.String
In this third case, the params map has a searchParams entry that looks correct, but is actually a String object. This causes my code to implode with a:
No such property: channelName for class: java.lang.String.
Is this the expected behaviour of the params attribute of the paginate tag? If so, what is the cleanest way for me to achieve the behaviour I am looking for (i.e. searchParams being passed as a map and not a string to my controller)?
Edit:
Here is the relevant gsp code for my search form:
<g:form url="[action:'index']" method="PUT" >
<fieldset class="form">
<div class="fieldcontain">
<label for="channelName">
<g:message code="alarm.channelName.label" default="Channel Name" />
</label>
<g:textField name="searchParams.channelName" value="${searchParams?.channelName}"/>
</div>
</fieldset>
<fieldset class="buttons">
<g:actionSubmit class="list" action="index" value="${message(code: 'default.button.list.label', default: 'List', args: [entityName])}" />
</fieldset>
</g:form>
and here is my index action:
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
def alarmCriteria = new DetachedCriteria(Alarm)
def channelInterfaceInstances = ChannelInterface.list();
if(params.searchParams?.channelName != null && params.searchParams?.channelName != "" && params.searchParams?.channelName != []) {
alarmCriteria = alarmCriteria.and {
like("channelName", "%${params.searchParams?.channelName}%")
}
}
def results = alarmCriteria.list(params) {}
respond results, model:[alarmInstanceCount: results.totalCount, searchParams: params.searchParams]
}

Can grails g:formRemote tag update more than one div

Can g:formRemote update more than one div in grails, What would be a viable strategy for updating multiple divs? can anyone explain me this with an example...
Yes you can control the update of your page. Instead of using the update attribute, use the onSuccess event.
From the docs:
onSuccess (optional) - The JavaScript function to call if successful
Example
View
<g:formRemote name="myForm" onSuccess="updateBook(data)" method="GET"
action="${createLink(controller: 'book', action: 'show')}"
url="[controller: 'book', action: 'show']">
Book Id: <input name="id" type="text" />
</g:formRemote>
<script type='text/javascript'>
function updateBook(data) {
//do what you want here
}
</script>
Controller
def show() {
//TODO: validate if exists and etc..
def book = Book.get(params.id)
render book as JSON //send JSON to the client, handling in the updateBook function.
}
Flow
User inform id
Ajax request is made
g:formRemote will call the javascript function updateBook
data will have the JSON that you can parse and do whatever you want (update divs)

Grails Export Plugin Doesnt Work with namedQuery

I am currently working on grails export plugin. The plugin works if I will just do simple list(). But if I associate it with namedquery, it doesn't work anymore. This is part of the code.:
def buildReport(){
if(params?.format && params.format != "html"){
response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
response.setHeader("Content-disposition", "attachment; filename=report.${params.extension}")
exportService.export(params.format, response.outputStream,Building.selectStatus(params.q).list(params), [:], [:])
}
}
The above code doesn't work. It throws this error :
Cannot invoke method getSuperclass() on null object. Stacktrace follows:
Message: Cannot invoke method getSuperclass() on null object
Can anyone help? Thanks.
Update:
I have this in my list.gsp:
<g:form action="list" controller="building">
<g:select id="user" name="q" from="${myapp.Construction.list()}" optionKey="id" required="" value="${constructionId?.id}" class="many-to-one" />
<g:submitButton name="Execute"/>
</g:form>
If I submit that form, it will list or display the the building with the same construction Id. And somewhere down that code is:
<export:formats
formats="['csv', 'excel', 'ods', 'pdf', 'rtf', 'xml']" action="buildReport"/>
That code will call the buildReport. But unfortunatedly the q or params.q of the select is null when calling the buildReport.
By the way, all this code is in one gsp file and it will display the same gsp when submitting the form.
Okay, I think I know why it doesn't works. Its because the params.q of
Building.selectStatus(params.q)
is actually null! I don't know why its null. I have this in my list.gsp to pass the parameter:
<g:textField name="q" value="${params.q ?: ''}" />
So what should be in the gsp to pass the params? Because here, I just found out that it is null.
By the way, before the buildReport is being called, the textfield has a value which the user will input.

Grails - communicating between controllers and views

I'm wondering how I can populate a text box in my view from a list in my controller, I have been searching for examples for awhile, but haven't really found anything. I'm uncertain on how to access the text field from the view exactly, where as in Java you could do something as simple as jTextField.getText(). I'm also wondering on how to grab the text in my text box as well.
Below I'll post some example code of what I'm doing.
Controller:
def loadFile = {
def propFile = "c:/props.txt"
def propMap = [:]
def propList = []
new File(propFile).eachLine { line ->
def (key,value) = line.split(':').collect { it.trim() }
propMap."$key" = "$value"
if(propMap) {
propList << propMap
propMap = [:]
}
}
}
def saveFile = {
//get contents of text box
//over-write props.txt with new information
}
View:
<g:textField name="properties"/>
<span class="menuButton"/><g:link action="loadFile" controller="myController">Load File</g:link>
<span class="menuButton"/><g:link action="saveFile" controller="myController">Save File</g:link>
So, my question seems relatively straight forward, how do I access the text box when I want to populate it and save the data from it?
.
.
.
EDIT
After checking out some of the examples submitted by you guys, I have one last question.
Why does the following code act different when clicking the Load File button?
<g:form controller="drive">
<g:textArea name="properties" value="${params.param1}" rows="50" cols="6"/>
<br/>
<g:submitButton name="loadFile" value="Load File"/>
<g:submitButton name="saveFile" value="Save File"/>
</g:form>
<span class="menuButton"/><g:link action="loadFile" controller="drive">Load File</g:link>
When clicking the g:submitButton dealing with loadFile it redirects me to the list gsp. However, when I click the menuButton it loads the textArea with the text from the file. The reason I ask is because with the second option, the button isn't located where I would like it to be.
Wrap your text field in form tag. This way, when you submit it, you can access your field in controller.
<g:form controller="myController" action="saveFile">
<g:textField name="properties"/>
<g:submitButton name="saveFile" value="Save File" />
</g:form>
Then, you can access your properties field in controller:
def saveFile = {
def properties = params.properties
// do whatever you need
}
EDIT:
To address some of the issues that came up later in comments, I'll try to provide some more insight.
Let's assume that your controller is called Drive and view (the form to submit properties) is drive/properties.gsp. If want your load button to load your properties into the text area, you can do something like this:
def loadFile = {
// your code here
render(view: 'properties.gsp', model=[properties:propList])
}
And in your view:
<g:form controller="drive">
<g:textArea name="properties" value="${properties?.join("\n")}" rows="50" cols="6"/>
<br/>
<g:actionSubmit name="loadFile" action="loadFile" value="Load File"/>
<g:actionSubmit name="saveFile" action="saveFile" value="Save File"/>
</g:form>
This should render your form with values from your file, each property in new line. But I didn't test it.
jjczopek's answer shows how to get access to the data in the controller after it has been submitted from the view.
You can pass a default value through from the controller to the view by setting a parameter in the controller eg...
params.param1 ='value to pass'
render(view:"testView")
Then in your view you can retrieve it again with...
<g:textField name="text1" value="${params.param1}"/>
You may also find this question and these docs useful.
If want to pass domain objects through then one of the following specific render methods might be better...
Grails Controller - Render

Resources