Groovy/Grails Tools Suite (GGTS) code-assist in GSP pages for model objects - grails

I am a newbie in Grails, and still learning.
I have the following code for the model:
class Book {
static constraints = {
}
String title
String author
}
and controller:
class KillController {
def index() { render "kill world" }
def view() {
def book = new Book( author: "Mike", title: "nuff sed")
[ model: book ]
}
}
And for view.gsp, I have the following:
<html>
<body>
Author: ${ model.author }<br />
Title : ${ model.title }
</body>
</html>
Everything is working, and the correct output is produced. However, in the GSP editor, when I type ${ model. }, I don't get any proposals from code-assist. Pressing ctrl+space after typing the dot does not help.
Pressing Ctrl+space inside ${ } works though, and it correctly recognizes model as a Book object.
Is code assist for models not yet supported in the GSP editor? Thanks! :D

This is a bug. It should be working and it does in many other situations. When I try it, I do see that an exception is being thrown:
org.eclipse.core.runtime.OperationCanceledException
at org.codehaus.groovy.eclipse.codeassist.processors.GroovyProposalTypeSearchRequestor.checkCancel(GroovyProposalTypeSearchRequestor.java:356)
at org.codehaus.groovy.eclipse.codeassist.processors.GroovyProposalTypeSearchRequestor.processAcceptedPackages(GroovyProposalTypeSearchRequestor.java:618)
at org.codehaus.groovy.eclipse.codeassist.processors.PackageCompletionProcessor.generateProposals(PackageCompletionProcessor.java:56)
at org.codehaus.groovy.eclipse.codeassist.requestor.GroovyCompletionProposalComputer.computeCompletionProposals(GroovyCompletionProposalComputer.java:162)
at org.grails.ide.eclipse.editor.gsp.adapter.CodeCompletionDelegate.codeComplete(CodeCompletionDelegate.java:71)
at org.codehaus.jdt.groovy.model.GroovyCompilationUnit.codeComplete(GroovyCompilationUnit.java:598)
at org.eclipse.jdt.internal.core.CompilationUnit.codeComplete(CompilationUnit.java:359)
at org.eclipse.jst.jsp.ui.internal.contentassist.JSPJavaCompletionProposalComputer.computeJavaCompletionProposals(JSPJavaCompletionProposalComputer.java:237)
at org.eclipse.jst.jsp.ui.internal.contentassist.JSPJavaCompletionProposalComputer.computeCompletionProposals(JSPJavaCompletionProposalComputer.java:114)
at org.eclipse.wst.sse.ui.internal.contentassist.CompletionProposalComputerDescriptor.computeCompletionProposals(CompletionProposalComputerDescriptor.java:284)
at org.eclipse.wst.sse.ui.internal.contentassist.CompletionProposalCategory.computeCompletionProposals(CompletionProposalCategory.java:290)
at org.eclipse.wst.sse.ui.contentassist.StructuredContentAssistProcessor.collectProposals(StructuredContentAssistProcessor.java:475)
at org.eclipse.wst.sse.ui.contentassist.StructuredContentAssistProcessor.computeCompletionProposals(StructuredContentAssistProcessor.java:254)
at org.eclipse.wst.sse.ui.internal.contentassist.CompoundContentAssistProcessor.computeCompletionProposals(CompoundContentAssistProcessor.java:127)
at org.eclipse.jface.text.contentassist.ContentAssistant.computeCompletionProposals(ContentAssistant.java:1839)
at org.eclipse.jface.text.contentassist.CompletionProposalPopup.computeProposals(CompletionProposalPopup.java:566)
at org.eclipse.jface.text.contentassist.CompletionProposalPopup.access$16(CompletionProposalPopup.java:563)
at org.eclipse.jface.text.contentassist.CompletionProposalPopup$2.run(CompletionProposalPopup.java:498)
...
I'll have to see what is going on here.
UPDATE:
Raised this issue: https://issuetracker.springsource.com/browse/STS-3337
Found the problem and pushed a fix. Will be available in next snapshot build.

Related

Grails command object not binding to 'def' type

Having issues trying to bind a param to a command object field defined as 'def'.
I have the following command object:
package command
import grails.validation.Validateable
#Validateable
class TestBindCommand {
String fieldType
def fieldValue
}
I have the following controller to test whether the params have binded correctly:
package command.binding
import command.TestBindCommand
class TestBindingController {
def index() { }
def testBinding(TestBindCommand testBindCommand) {
println("fieldType: " + testBindCommand.fieldType)
println("fieldValue: " + testBindCommand.fieldValue)
render("fieldType: ${testBindCommand.fieldType} - fieldValue: ${testBindCommand.fieldValue}")
}
}
Finally, I have the following ajax request to post the params to the testBinding method above:
<%# page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>Index</title>
</head>
<g:javascript library="jquery" plugin="jquery"/>
<script>
$( document ).ready(function() {
$.post('/command-binding/testBinding/testBinding', { fieldType: "String", fieldValue : "hello world"},
function(returnedData){
console.log(returnedData);
});
});
</script>
<body>
Index Page
</body>
</html>
If you change the type of fieldValue to String it begins binding. If you then switch it back to def it still works?! If you do a grails clean and restart the app with fieldValue set as def then it won't work again!? I've debugged down into the DataBindingUtils.java and it appears that the field isn't getting added to the whitelist when it is of type 'def'.
Sample project can be found here:
https://github.com/georgy3k/command-binding
Grails version 2.5.6
I've debugged down into the DataBindingUtils.java and it appears that
the field isn't getting added to the whitelist when it is of type
'def'.
That is correct, and by design. By default dynamically typed properties do not participate in mass property data binding.
From https://grails.github.io/grails2-doc/2.5.6/ref/Constraints/bindable.html:
Properties which are not bindable by default are those related to
transient fields, dynamically typed properties and static properties.
If you really want to make a dynamically typed property participate in mass property binding, you have to opt into that with something like this:
class TestBindCommand {
String fieldType
def fieldValue
static constraints = {
fieldValue bindable: true
}
}
That said, for command objects in particular, there is no good reason to have a dynamically typed property.
I hope that helps.

Grails display data from database

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

PageRenderer in Controller

Can we implement PageRender in controller (grails 3.2.8)? I tried in a service and it worked perfectly as expected.
But when I tried in a controller, I am not getting the expected results.
Controller:
class TestcontrollerController {
def RenderService
def gsp= "grails"
PageRenderer groovyPageRenderer
def index(String gsp) {
render creategsp()
}
def creategsp() {
groovyPageRenderer.render view: '/email/confirm', model: [gsp: findgsp()]
}
def findgsp() {
'<g:select from="${18..65}" value="${age}" />'
}
}
index.gsp:
<g:render template="/test/samplePage" />
samplePage.gsp:
<g:render template="/email/welcome" />
_display.gsp:
Hi ,{username} <br>
PageRenderer is not rendering any of the custom tags or grails tags.
Any suggestions?
Yes this is completely possible. Just define it at the top of your controller:
PageRenderer groovyPageRenderer
Note that you need to strongly type this, and not just "def" it.
Then when you use it, it will render pages to strings:
String renderViewResult = groovyPageRenderer.render(view: "/myViewName", model: renderModel)
If you update your question with more details like what you did, and what isn't working, possibly someone can help you more, but big picture: yep, it works!

there is a strange thing happened in my grails controller, why?

my enviroment:
java version "1.6.0_38"
Grails 2.1.1
grails create-app test
cd test<br>
grails create-controller com.test.Test
There is NO SPECIAL CONFIG in UrlMapping.
com.test.TestController:
package com.test
class TestController {
def getA(){
def ret = []
println "in getA"
render ret
}
def index() {
println "in index"
render view:"index"
}
}
grails-app/test/index.gsp:
<html>
<body> hello </body>
</html>
when i try to access [ http://HOSTNAME/PRJNAME/test/index ]
i suppose that would happend:
HTML:
<html>
<body>
hello
</body>
</html>
Console :
in index
BUT,things not like that, actually, it's like this:
HTML:
[]<html>
<body>
hello
</body>
</html>
Console :
in index
in getA
Why??
Grails calls all methods that start with "get" to find closures that are used as actions. Since the syntax def foo = { ... } defines a closure as a property, Groovy adds a getter and setter (getFoo and setFoo), so the closures are discovered by finding properties and calling the getters to check if the return type is a Closure. Since controllers are (by default) prototype scoped they're created for each request, each public getter method gets called for each request.
So the workaround is to not start action methods with "get".

Grails "render" renders the template

In my Grails controller I'm responding to an AJAX call and using render to return the text:
def ajaxRandomPersonName = {
def person = get a random person ...
render "Name: ${person.name}"
}
The problem is that render renders the whole template. So instead of just rendering "Name: John" it renders all the icons, navigation, etc defined in the template. How do I get render to just render without the template?
I'm pretty much following Chapter 1 of "Grails in Action" (page 28) using Grails 1.1.1.
Follow up:
Returning false per Rhysyngsun's suggestion has no impact. I also tried setting the template to null but it still renders the template:
def ajaxRandomPersonName = {
def person = get a random person ...
render (template:null, text:"Name: ${person.name}")
}
render has its heart bent on rendering it through the template no matter what I do.
Follow up 2: Parallel discussion on grails-user mailing list.
Follow up 3: Sample code:
I paired down my code the bare minimum and it still exhibits the undesired template rendering.
controllers/PersonController.groovy:
class PersonController {
def index = { }
def home = { [message:"Hello"] }
def ajaxTest = {
println "ajaxTest called"
render text: "ajax message"
}
}
views/person/home.gsp (view page for home method)
<html>
<head>
<title>Home View</title>
<g:javascript library="prototype" />
</head>
<body>
<p>
<g:remoteLink action="ajaxTest" update="test1">ajax call</g:remoteLink>
</p>
<p>Message = ${message}</p>
<p id="test1">Blank</p>
</body>
</html>
views/layouts/person.gsp (layout template for person controller)
<html>
<head>
<title>Test App - <g:layoutTitle/></title>
<g:layoutHead/>
</head>
<body>
<h1>Test App</h1>
<g:layoutBody/>
</body>
</html>
I access person controller with the home view:
http://localhost:8080/test/person/home
the page renders as:
Test App
ajax call (hyperlink)
Message = Hello
Blank
"Test App" is from the template. When I click "ajax call" it makes an asynchronous call to PersonController's ajaxTest method (verified with println). All ajaxTest does is println and render static text. This resultant in the following:
Test App
ajax call
Message = Hello
Test App
ajax message
Note that the template is being rendered within "test1" <p> which results in the second "Test App".
I'm running Grails 1.1.1. Any ideas? The code seems straightforward. I downloaded the Grails source and looked at RenderDynamicMethod.java. It doesn't do any template rendering unless template is in the argument list, which it isn't. So my only guess is something up steam is rendering the template again.
Resolved: Adding contentType results in the template not being rendered:
render text: "Name: ${person.name}", contentType: "text/plain"
Make your client side javascript code handle a JSON respond and render your response with:
render [text:"Name: ${person.name}"] as
JSON
You might be getting burnt by the 'layout-by-convention' feature in Grails. If your layout name matches the controller name prefix, for example, Grails will apply the layout to every view managed by that controller. Unfortunately, it even applies to text and templates. There are currently a few JIRAs logged regarding this (see http://jira.grails.org/browse/GRAILS-7624 for example).
I got burnt by this today. I resolved it by simply renaming my layout gsp such that it doesn't match any controller name. My layout was initially named 'storefront.gsp' and I have a controller named StorefrontController. I renamed the layout to 'public.gsp'.
We've found that explicitly returning false from the action fixes this.
I believe doing render foo as JSON returns false implicitly.

Resources