decorate Grails tag - grails

The taglib provided by the Grails bean fields plugin uses a naming convention to determine the label key that should be used for each <input> element it generates. I would like to change the details of this convention without changing the plugin's source code directly.
The approach I'm considering is to create my own tag lib
class MyBeanTagLib {
static namespace = 'mybean'
private void setLabelKey (attrs) {
if (!attrs.labelKey) {
// in reality calculation of the default key is a bit more complicated :)
attrs.labelKey = 'my.default.key'
}
return attrs
}
// renders a combo box
def select = { attrs ->
attrs = setLabelKey(attrs)
// Now call the bean-fields select tag, passing along attrs
}
// renders a datePicker
def date = { attrs -
attrs = setLabelKey(attrs)
// Now call the bean-fields date tag, passing along attrs
}
}
My first question is how to invoke the tag I'm trying to decorate. In other words, what code should replace the comment
// Now call the bean-fields...
I could do this:
new BeanTagLib().select(attrs)
But I doubt this is the correct way to invoke one taglib from another.
Secondly, is there a more elegant way to decorate a taglib than this? In reality there are a lot more tags than just select and date that I need to decorate and the code in each decorating tag will be almost identical. I'd like to eliminate this duplication if possible?

Invoke other taglibs' tags by their namespace, like g.link([controller: 'one'], { 'link text' }), or bean.select(attrs).
You can try writing getProperty in your taglib and return proper closures - I'm not sure.

Related

prevent encoding of taglib output

In my Grails app, I've defined the following tag which outputs a Map
class DataBindingTagLib {
static namespace = "bind"
def domainParamList = { attrs ->
def params = [:]
// put stuff in the map
return params
}
}
When I call this tag and store the result in a variable
<g:set var="chartParams" value="${bind.domainParamList([:])}"/>
If I inspect the type of this variable, it's a StreamCharBuffer. So it seems that the value output by the taglib is automatically being converted to this type. I tried to prevent this by changing the line above to
<g:set var="chartParams" value="${raw(bind.domainParamList([:]))}"/>
But it made no difference. Is there a way to prevent this from happening such that I can store the Map instance returned by the tag in the chartParams GSP variable? I'm not sure if this is relevant, but I have the following automatic encodings defined in Config.groovy
grails {
views {
gsp {
encoding = 'UTF-8'
htmlcodec = 'xml' // use xml escaping instead of HTML4 escaping
codecs {
expression = 'html' // escapes values inside ${}
scriptlet = 'none' // escapes output from scriptlets in GSPs
taglib = 'none' // escapes output from taglibs
staticparts = 'none' // escapes output from static template parts
}
}
}
}
You need to instruct your tag library to return an object as a result, by default tag libraries are expected to modify the output stream.
First, let the tag library know you need this particular method/closure to return an object by using the returnObjectForTags static hint. Then, simply modify the method/closure to return your object instead of modifying out. With these two changes your tag will return an object and you can use it as such.
class DataBindingTagLib {
static namespace = "bind"
static returnObjectForTags = ['domainParamList']
def domainParamList = { attrs ->
def params = [:]
// put stuff in the map
return params
}
}

How can I use path variables in grails controller?

I have been trying to use a path variable in grails controller but I am not able to achieve it.
The intention behind is to validate the parameter submitted to the url which I need to make mandatory. I could not achieve it through RequestParam so I switched to PathVariable so that the url submitted without the required param should be filtered off by grails controller itself rather than me adding if/else checks for validity.
So, I can illustrate as below:
My URL is something as below:-
'<appcontext>/<controller>/<action>?<paramName>=<something>'
Now, to make 'paramName' mandatory I am not finding any way in Grails(Spring MVC provides #RequestParam annotation which can enable me for 'required' as true).
Another alternative I thought was to use path variables so that 'paramName' can be included in URL itself. So I tried like following:
'<appcontext>/<controller>/<action>/$paramName'
For validating the above URL I wrote specific mapping but some how it does not work too..
Following is the specific mapping I wrote:-
"/<controllerName>/<action>/$paramName" {
controller:<controller to take request>
action:<action to do task>
constraints {
paramName(nullable: false,empty:false, blank: false)
}
}
I tried to use spring annotation like #PathVariable and #RequestParam in controller as given below:-
def action(#PathVariable("paramName") String param){
//code goes here
}
If you name the method argument the same as the request parameter rename, Grails will take care of it for you...
// In UrlMappings.groovy
"/foo/$someVariable/$someOtherVariable" {
controller = 'demo'
action = 'magic'
}
Then in your controller:
// grails-app/controllers/com/demo/DemoController.groovy
class DemoController {
def magic(String someOtherVariable, String someVariable) {
// a request to /foo/jeff/brown will result in
// this action being invoked, someOtherVariable will be
// "brown" and someVariable will be "jeff"
}
}
I hope that helps.
EDIT:
Another option...
If for some reason you want different names for the method arguments you can explicitly map a method argument to a request parameter like this...
import grails.web.RequestParameter
class DemoController {
def magic(#RequestParameter('someVariable') String s1,
#RequestParameter('someOtherVariable') String s2) {
// a request to /foo/jeff/brown will result in
// this action being invoked, s2 will be
// "brown" and s1 will be "jeff"
}
}

Grails: Returning parameters from a taglib

How do I return values from a taglib that has been called in a controller action such that it automatically retains the full type structure of the values setup in the taglib?
I can use the out << approach but this returns strings or array of strings.
I have tried to use a [] mapping as used transfer a set of values at the end of an action to its view.
I have also tried a return statement again unsuccessfully - besides I need to return more than one set of values.
-mike
from the top of the documentation http://grails.org/doc/latest/guide/theWebLayer.html#tagReturnValue
class ObjectReturningTagLib {
static returnObjectForTags = ['content']
def content = { attrs, body ->
someValue()
}
}
I think this could solve your problem
package com.campaign
import java.util.*;
class UserDetailsTagLib {
def springSecurityService
static namespace = "jft"
#here we are defining that this getPrincipal and getArrayListAsObj tag used to return object
static returnObjectForTags = ['getPrincipal','getArrayListAsObj']
#this tag will return obj
def getPrincipal = {
return springSecurityService.principal
}
# this tag is used to return the array list of string
def getArrayListAsObj = { attrs , body ->
ArrayList arrayList = new ArrayList();
arrayList.add("C");
arrayList.add("A");
arrayList.add("E");
arrayList.add("B");
arrayList.add("D");
arrayList.add("F");
return arrayList
}
}
I understand your problem. If you want to have the Intellisense on the var you got from a taglib, the only thing you can have is this (it's a little redundant)
In a gsp for example, if you have a TagLib with namespace myTaglib:
First call the action of your taglib to set the value of a var:
<myTaglib:person var="currentUserFromTaglib" />
Where the person tag in the myTaglib is just for this purpose:
def person = { attrs ->
this.pageScope."$attrs.var" = new Person(name:'Giuseppe', surname:'Iacobucci')
}
After this, you need to write:
<g:set var="currentUser" value="${currentUserFromTaglib as Person}"/>
And include in you gsp:
<%# page import="your.package.Person" %>
After that, in the gsp currentUser is recognized as type Person.
In a controller, you simply call the myTaglib and cast the result like so:
def myvar = myTaglib.person() as Person
Obviously if you need more a complex object as I read from your comments, then create a plain UI object with all information you need inside and do the same trick.

How to nest Grails controller paths

I know it is possible to do something like this:
Controller foo with action bar can be accessed by (1):
/appname/foo/bar
And it can be rewritten using URL mappings - e.g like this:
"/foobar/foo/$action"(controller: "foo")
And then access it via (2):
/appname/foobar/foo/bar
But it is still possible to access it via (1). This is of course because of the default URL mapping:
"/$controller/$action?/$id?"()
But I would rather not delete this, because this basically means I have to manually write mappings to every other controller/action that follows the default pattern.
It is possible to obtain url-patterns for specific controller/actions like (2) without using URL mappings? If not, is there an easy way to "exclude" controllers from the default mapping closure?
The Solution is to change the default mapping, in a way to exclude the whished special controller URL.
class UrlMappings {
static myExcludes = ["foo"]
static mappings = {
"/foobar/foo/$action"(controller: "foo") // your special Mapping
// the rewritten default mapping rule
"/$aController/$aAction?/$id?"{
controller = { (params.aController in UrlMappings.myExcludes) ? "error" : params.aController }
action = { (params.aController in UrlMappings.myExcludes) ? "notFound" : params.aAction }
constraints {
// apply constraints here
}
}
}
}
For the rewritten default rule you have to prevent usage of default variable names $controller and $action. Instead of error/notFound you are also able to redirect to other locations.
If you can make your rule breaking scenario more specific than the Grails default $controller/$action?$id? pattern, then the default can be left as is and will apply to everything outside of your exception pattern. I made a quick Person domain and performed a generate-all. Then I made a BreakRuleController just by itself.
class UrlMappings {
static mappings = {
"/b/$action?/$someVariable?"(controller: "breakRule")
"/$controller/$action?/$id?(.${format})?"{
constraints {
// apply constraints here
}
}
"/"(view:"/index")
"500"(view:'/error')
}
}
With this UrlMapping, if you access the URI "/b/foo/stackoverflow" it will print "Breaking Rules foo: stackoverflow". If you go to "/b", it will print "Breaking Rules index".
Then if you go to the standard Person URI's, all your default Grails scaffolding works fine also (create, edit, etc.) because that gets mapped to the typical "$controller/$action?/$id?" pattern.
class BreakRuleController {
def index() {
print "Breaking Rules index"
}
def foo(String someVariable) {
print "Breaking Rules foo: " + someVariable
}
}

Is possible to overwrite the behaviour of the methods **CreateLink** and **CreateLinkTo**?

Is possible to overwrite the behaviour of the methods CreateLink and CreateLinkTo?
You could use meta programming to replace the closure on ApplicationTaglib.
ApplicationTagLib.metaClass.getCreateLink = {->
return {attrs->
// your code here
}
}
I've never tried it but it might work :)
All you need to do is create a taglib of your own and define the tags yourself ie
class MyTabLib {
def createLink = {attrs, body ->
.... etc ....
}
def createLinkTo = {attrs, body ->
.... etc ....
}
}
Grails will use your taglib first.
Hope this Helps!
This is a little late, but the solutions above didn't work for me. I was able to successfully do this, though:
public class MyTagLib extends ApplicationTagLib {
def oldResource
public MyTagLib() {
// save the old 'resource' value
oldResource = resource;
resource = staticResource;
}
def staticResource = { attrs ->
// dork with whatever you want here ...
// ...
out << oldResource(attrs);
}
}
you're basically extending the original tag lib. Since the 'resource' tag is a property of the object (and not a method) I don't think you can actually override it. Instead, just save the original value and call it after you've make your changes to the tag request.

Resources