Grails: Dynamically call another action - grails

Is it possible to call another controller-action with the name of the controller-action being passed as a parameter. Something like this:
View:
<g:createLink controller="book" action="list"
params="[id: '1', onCompleteController='nextCon', onCompleteAction='nextAct']"/>
Controller (Book):
def list = {
... //Do something like save book
**execute onCompleteController/onCompleteAction**
return render(text: [success:true] as JSON))
}

you can do that by using forward or redirect (which ever fits in your case).
Some thing like
redirect(controller:onCompleteController, action: onCompleteAction, model:[])
forward(controller:onCompleteController, action: onCompleteAction, params:[])

Related

implement "create another like this" functionality in grails

After saving a new instance of a domain class in grails, I have a "create another like this" button that brings up another create screen where the fields are populated with the values of the instance I just created.
In the first try, I passed all the existing field values as params in an alternate create button:
<g:link class="create" action="create"
params="[app:volInstance.app.id,
ass:volInstance.assessment.id,
name:volInstance.volName,
type:volInstance.volType.id,
note:volInstance.volNote,
recommendation:volInstance.recommendation,
discovered:volInstance.dateFound,
url:volInstance.urlParam]">
Create Another like this
</g:link>
and then doing a lot of <g:if> on the next create.gsp to see if the parameters are present. I then advanced to just sending the instance id as a param
<g:link class="create" action="create"
params="[vid:volInstance.id]">
and changed the create method in the controller. This simplified things (no longer have a huge params list):
def create() {
if (params.vid) {
def id = params.vid
def v = Vol.findById(id)
params.volNote = v?.volNote
params.volType = v?.volType
etc......
}
respond new Vol(params)
}
This works nicely and eliminates all the <g:if>s but still have a lot of lines of params.x = v.x
would there be a way to get rid of those lines and just pass the object as a param?
Looks like a good place for a Command Object. You can declare it in your controller, and then pass it as an argument to your action. You can even add validation if you want.
class MyCommand {
Long id
String volNote
String volType
static constraints = {
volNote (blank: false)
//...
}
}
Then in your action:
def create(MyCommand cmd) {
Long id = cmd.id
//...

Grails custom tag doesn't work with <g:link params>

I have in my GSP page a <g:link action="test" params='["present": "yes"]' tag which, when clicked, sends me to a URL ending with /test?present=yes.
If I define this custom tag lib:
class HelperTagLib {
static defaultEncodeAs = 'html'
static returnObjectForTags = ['passthrough']
def passthrough = { Map attrs, Object body ->
return attrs
}
}
and add it to the tag, <g:link action="test" params='${passthrough(["present": "yes"])}', suddenly my URL ends with /test, completely losing the params.
Why does this happen and how can I work around it?
Allow your taglib to render that link for you. Try this </g:passthrough> in gsp and in taglib
def passthrough = { attrs, body -> out << g.link(controller: 'foo', action: 'test', params: [present: 'yes']) }
i can see you miss g.taglibname in your call to taglib, it should be like this
<g:link action="index" params="${g.doSomething(present:true)}">Ir</g:link>
i did it my self and its work fine
but if what you want is to intercept some params, and then procesit before complete the request maybe a better solution is using beforeInpreceptor feature or some filter.
more info about interceptors here http://www.grails.org/doc/2.3.x/ref/Controllers/beforeInterceptor.html
hope it can help

Grails render changes url to index

I've got this method on my controller, which basically validates and saves entity or renders errors if any:
def initCreateProduct() {
render view: "/admin/product/createProduct"
}
def createProduct(params) {
def product = new Product(params)
if (product.validate()) {
flash.message = "product.createSuccess"
product.save(failOnError: true);
redirect action: "initCreateProduct"
} else {
render view: "/admin/product/createProduct", model: [product: product]
}
}
It works fine in case if validation is successfull (URL in browser is "product/initCreateProduct", which is ok), but in case if validation fails my URL changes to "product/index", which is wrong. What I need is to get the same URL in both cases (it's the same page after all). Thanks in advance.
Update: finally solved it.
The problem is caused by used in my gsp, which basically changes action url to index, and sends real action as post-method parameter. To save action in url I have used instead of
It is doing a controller redirect and not being able to resolve an URL. IIRC, grails will pass additional parameters to the index method to find that action.
If you do something like this, it won't do it:
if (product.validate()) {
flash.message = "product.createSuccess"
product.save(failOnError: true)
initCreateProduct()
}

Detect redirect in Grails

At the end of my save action I redirect to the show action like this:
redirect(action: "show", id: exampleInstance.id)
In my show action I want to be able to detect if someone came directly to this action via a url, or if they were redirected here from another action. I tried request.isRedirected() but it always returns false.
How do I detect if I am in an action as the result of a redirect from another action?
I guess you want to display a confirmation message. Grails has a built-in feature for this kind of use-case:
http://www.grails.org/doc/2.1.0/ref/Controllers/flash.html
Have a look at the example:
class BookController {
def save() {
flash.message = "Welcome!"
redirect(action: 'home')
}
}
In the view you can print or check against flash.message.
In theory, isRedirect checks request attributes. It is equivalent to
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
if(request.getAttribute(GrailsApplicationAttributes.REDIRECT_ISSUED) != null){
println "request was redirect"
}
Try it directly and tell me what happens.
It looks like in the Grails source that isRedirected() is only applicable to the save action, as it gets set in the redirect() method logic, and so wouldn't be set in the show action.
Instead, here are some manual options. One is to add a flag to the flash object, which is then tested in the redirect action. Since it is in flash scope it will be cleared at the end of the show action:
def save() {
// Do stuff
flash.redirectFrom = "save"
redirect(action:"show")
}
def show() {
if (flash.redirectFrom) {
// Respond to redirect
}
// Do other stuff
}
Another option is to issue a chain() call instead of a redirect() and test for the implicit chainModel object. The chainModel won't exist when the show action is requested from an external URL:
def save() {
// Do stuff
chain(action:"show",model:[from:'show'])
}
def show() {
if (chainModel) {
// Respond to redirect
}
// Do other stuff
}

grails access controller from taglib

Is it possible to access the current controller instance from within a TagLib? For example:
class FooTagLib {
static namespace = 'foo'
def msg = { attrs, body ->
// Can I get a reference to the current controller here?
}
}
I want to do this because I store some data in a property of the controller and want to access it within the TagLib. I realise this may sound strange, but just humour me....
Inside your msg tagLib:
grailsApplication.getArtefactByLogicalPropertyName('Controller', pageScope.controllerName)
Like Views, you have access to the current controller and action through controllerName and actionName
Try something like this...
def ctl = grailsApplication.getArtefactByLogicalPropertyName('Controller', 'whateverController')

Resources