I'm having difficulties getting my ajaxform working properly. I'm using Grails 2.4.4 and have the following remoteForm code.
view usedProducts
<div id="updateMe">
<g:each in="${productList}" var="product">
${product.item} Success1
</g:each>
</div>
<g:formRemote name="myForm"
url="[controller:'product', action: 'save']" update="updateMe">
<g:textField name="item" required="" value="${newProduct?.item}" />
<g:submitButton name="Save" />
</g:formRemote>
Controller ProductController
def usedProducts = {
[productList:Product.findAll()]
}
#Transactional
def save(Product productInstance) {
productInstance.save flush:true
[productList: Product.findAll()]
}
Console Error
POST http://localhost:8080/TekDays/product/save
404 Not Found
54ms
jquery-...e=false (line 9631)
"NetworkError: 404 Not Found - http://localhost:8080/TekDays/product/save"
I'm afraid you cannot do that this way you're trying to do.
Note that when the AJAX call is effectively being performed by the user there are no more GSP tags. There are only CSS, HTML and Javascript. It's the browser world.
Please put the render in front of what you're returning and test.
#Transactional
def save(Product productInstance) {
productInstance.save flush:true
render Product.findAll()
}
You'll see that the content of the DIV updateMe will be replaced by the content rendered by the save method. The content is a list returned by findAll method with all Product objects.
When you use render the content returned (a GSP template, the content of a variable or a HTML) will be rendered in the current HTML, for instance, through an AJAX call.
For other side when you use the return keyword is expected a GSP with the same name as the controller method. Because of that you're getting a 404, since a save.gsp isn't found. Note: if you omit the return keyword (as you're doing) then the groovyc (Groovy compiler) will implicitly put it for you.
If I understand well what you're trying to do then you must render the content (not return it).
Related
I'm creating a Grails app following this tutorial: http://grails.asia/grails-tutorial-for-beginners-display-data-from-the-database
When I try to display data from database though, nothing happens. Below is my controller code:
def index(){
def users = User.list();
[users:users]
}
def displayUsers(){
if(User.count()==0){
render 'User list is empty!';
}else {
render(view: 'userlist.gsp');
//a little test
println User.list().size();
println User.count();
for(User u : User.list()){
println u.username;
}
}
}
The User.count() is working, because I can see the usernames in console and userlist.gsp renders every time, but it seems that my view code doesn't see the list. Here's the userlist.gsp code:
<body>
userlist.gsp
<g:each in="${users}" var="user" status="i">
<h3>${i+1}. ${user.username}</h3>
</g:each>
</body>
What can be wrong with this code? I've been making precisely the same steps as in the tutorial above in my analogical app, but it doesn't seem to work. This is especially weird, since I've found a similar question under this link: grails: show list of elements from database in gsp
and it's been marked as accepted answer. Why does exacly the same way not work in my app?
render gsp view as follows (pass data as a model).
render(view: "userlist", model: [userList : User.list()])
Now get model data in gsp as follows.
<body>
userlist.gsp
<g:each in="${userList}" var="user" status="i">
<h3>${i+1}. ${user.username}</h3>
</g:each>
</body>
You can do with many options:
rename your gsp action in controller from def index() to def userlist()
or rename index.gsp file to userlist.gsp
you can redirect to userlist.gsp with ${users} object
So change in controller def index() action
[users:users] to redirect(action: "userlist", params: ["users": users])
Note: 2nd method will show parameters in url.
Refer Grails Doc
You can use chain
e.g. chain(action: "userlist", model: ["users": users])
Refer Grails Doc
every gsp action (page) needs to be injected
Here is my Grails (2.3.6) controller:
class WidgetController {
def index() {
render(
view: "createNew",
model:[
]
)
}
def execute() {
println "Executing form submission!"
redirect(action: "listAll")
}
def listAll() {
// Does some stuff
}
}
The index URL is, say, http://localhost:8080/myapp/widget. The idea is that when someone goes to this URL, they are presented with an HTML form. When they fill out the form, they are sent (on the server side) to the execute() method, which does some heavy duty stuff and then redirects them to the listAll() method which does some final stuff and renders a web page for them to see.
Here is the HTML form on the createNew.gsp (rendered from the index() method:
<g:form name="create-new-form" url="[action:'execute',controller:'widget']">
<table class="pure-table pure-table-bordered">
<tr>
<td class="row-header">Fizz:</td>
<td><g:textField id="app-fizz" name="fizz" /></td>
</tr>
<tr>
<td class="row-header">Buzz:</td>
<td><g:textField id="app-buzz" name="buzz" /></td>
</tr>
</table>
<g:actionSubmit value="Create" />
</g:form>
When I go to this URL and submit the form (clicking the Create button) I get redirected to http://localhost/myapp/widget/execute which displays one of my customized error pages (basically a "Sorry this page is unavailable"-type error.
Additionally, in the log outputs, my println stating "Executing form submission!" is not firing. This tells me that I don't have something wired correctly: Grails is trying to redirect to an /execute URL but somehow isn't linking that URL with my controller's execute() method. Ideas?
Try with:
<g:actionSubmit action="execute" value="Create" />
If you specify only value for g:actionSubmit it creates button with this label and also redirect to action based on this value. If action name is different than button label you should specify action and value attributes. Take a look at documentation.
Note that if you use g:actionSubmit then action attribute of g:form will be ignored (which you specified btw.). You'll find more info where it may be useful in docs linked above.
use plain <input type="submit" value="go"/>. thus the form is submitted to the URI defined in <g:form> tag
g.actionSubmit or g.submitButton are needed, if you want to submit your form somewhere ELSE.
I am maintaining a grails 1.1.1 application. There is an include code which works if we include from a regular gsp. But when I try to include it from _header.gsp it doesn't work. I am using exactly the same statement. It actually calls the method in the controller but nothing gets returned in the view.
Following is the code which works from a regular gsp
<g:include controller="abcGenericComponent" action="visitOurBoardsComponent" />
This is the method in controller
def visitOurBoardsComponent = {
def visitOurBoardsContent = abcGenericComponentService.getVisitOurBoardsComponent(request)
log.debug "Calling vistitboards ${visitOurBoardsContent}"
[visitOurBoardsContent: visitOurBoardsContent]
}
The log statement is showing up in the logs. That means the method is getting executed.
This is the included gsp
<ul>
<g:each var="ourBoards"
in="${visitOurBoardsContent}">
<li>
${ourBoards?.displayName}
</li>
</g:each>
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.
Here is the Problem: I have a remoteForm, which itself works fine. I debugged the controller and every command runs through. However if an Exception occures and I set a flash.error message. The message will only be displayed AFTER I manually press F5 (Refresh). I do not understand why the AJAX call works, but the flash messages are empty.
I have a remote form (in index.gsp):
...
<g:formRemote name="remoteForm"
url="[ controller: 'document',
action: 'search']"
onLoading="showSpinner();"
update="searchBlock"
action="${createLink(controller: 'document', action:'search')}"
>
<div class='info_message'>
${flash.message}
</div>
<div id="searchBlock">will be exchanged</div>
......
A controller:
......
} catch (Exception e){
log.error(e)
flash.error = e.getMessage()
flash.message="HINTTEST"
render (template:'searchNoResult')
return
}
.....
The template (of _searchNoResult) has the following content:
<span>Sorry, your search yielded no result.</span>
<g:if test='${flash.error}'>
<div class='error_message'>
Error: ${flash.error}
</div>
</g:if>
<g:if test='${flash.messages}'>
<div class='info_message'>
Hint: ${flash.message}
</div>
</g:if>
Documentation says: the the flash scope lives through the current request and the call after that. If I use a normal form and submit everything works, but I want to use ajax and render templates, so I do not have to repeat code so often.
Edit 1
First the index.gsp is rendered. The remoteForm changes the seachBlock div with the template, which contains the flash.messages. They are not filled.
Grails Version 1.3.7 an upgrade is not possible at the moment.
Edit 2
The exception e, was not the Exception, which was original thrown by me. The message was null, which resulted in null for messages....
From the code you've shown nothing is updating the info_message div with a message when the ajax request returns a response. The formRemote is only updating the searchBlock element. If the page doesn't refresh the flash.message can't be rendered.