How to avoid groovy code in GSP? - grails

I've to display check box checked or not based on some logic which is more than 4 lines of groovy code ...
I don't like to write it in GSP page..is there any taglib or some way I can extract the logic out of GSP page.
where I could access model boject and request objects.

You have (at least) 3 options:
Model attribute
If you're only doing the complex logic for a single page or a single controller, do the logic in the controller method and pass the boolean result to the view through a boolean:
// in your controller
def myAction() {
[shouldDrawCheckbox: shouldDrawCheckBox(...)]
}
private boolean shouldDrawCheckBox(/* info for decision making */) {
// decision making
}
Service method
If you're going to access this identical logic from several controllers, you can extract the shouldDrawCheckBox method into a service and again pass the result through the models.
class MyController {
def myService
def myAction() {
[shouldDrawCheckbox: myService.shouldDrawCheckbox(...)]
}
}
class MyService {
boolean shouldDrawCheckBox(...) {
// logic!
}
}
Custom Taglib
If you want to avoid passing the decision through the model, or if the logic is more generally applicable, you can create a custom taglib.
class MyTaglib {
static namespace = "my"
def myCheckbox = { attrs ->
// extract decision info from the attrs
// perform logic with info
if (shouldDrawCheckbox)
out << g.checkbox(attrs: attrs)
}
}
}
In your view:
<my:myCheckbox whateverYourAttribsAre="value" name="..." value="..."/>

A TagLib is a good palce to put your logic, you can pass what you need as attributes and do your test:
class MyTagLib {
static namespace = "my"
def somecheckbox= { attrs ->
def model = attrs.remove('model')
if() { //tests goes here
//you can also test if you need to mark the checkbox as checked
if() {
attrs.checked = "checked"
}
out << g.checkbox(attrs: attrs) //remaining attrs will be applied to the checkbox
}
}
}
myview.gsp
<my:somecheckbox model="${model}" name="checkboxname" value="${checkboxValue}" />

Ideally the logic should go to the controller which renders the gsp and sets a flag in the model object. If the gsp is a child of a template, then the flag has to pass through. DOM manipulations in view layer is not ideal when we have appropriate binding framework available in grails.

Use the g: namespace. http://grails.org/doc/2.2.x/ref/Tags/checkBox.html
<g:checkBox name="myCheckbox" value="${condition}" />
It doesn't get any simpler then this. All the logic should be done inside the controller.
All the data you need on a page can be passed by the controller. Just return a Map.
class MyController {
def index() {
def someCondition = true
[request:request, condition:someCondition]
}
}

Related

Grails data binding field exclusion

I am using Grails 2.5 and use Grails databinding in request methods.
For a basic example of the situation consider the following:
Domain class
class Product {
String field1
String privateField
}
Controller
class ProductController {
def update(Product productInstance) {
productInstance.save()
}
}
If I pass an existing Product to the controller like
{"id":3, "privateField":"newValue","field1":"whatever"}
the old value of privateField is overwritten. I want to enforce, that privateField is never bound from a request and avoid checking if the field is dirty.
Is there a mechanism in Grails to achieve this?
If I have to do the dirty check, how can I discard the new value and use the old one?
Pretty sure there's a "bindable" constraint.
http://grails.github.io/grails-doc/2.5.x/ref/Constraints/bindable.html
class Product {
String field1
String privateField
static constraints = {
privateField bindable: false
}
}
Should keep that field from binding automatically.
You can enforce which values are bound, but you'll need to change your method signature to get more control of the data binding process.
class ProductController {
def update() {
def productInstance = Product.get(params.id)
bindData(productInstance, params, [exclude: ['privateField']]
productInstance.save()
}
}

Grails: Adding an attribute to model Map on every view, when model is not present

I've got a pretty clean filter which is intended to add an attribute to the model Map so that it can be shown on every page:
def filters = {
someFilter(controller:'*', action:'*') {
after = { Map model ->
model.something = 'hey!' // can't, since it's null
}
}
}
If model is null it fails horribly (NullPointerException, as expected). But if I add an if (!model) and try to instantiate it, it's local and doesn't behave as intended.
How can I put an empty map there when model is null?
I think you can do it with a little groovy triks. You can create a groovy interceptor and apply it to all controllers class in bootstrap. The interceptor implements the afterInvoke method in which check for null results and turn them in empty maps [:]
Try this:
def filters = {
someFilter(controller:'*', action:'*') {
after = { Map model ->
model.put('something', 'hey!')
}
}
}

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.

Is there an easier way to do content negotiated responses in Grails?

From what is in the Grails user guide, the recommended way to send different content formats based on the content negotiation is to use a withFormat block:
import grails.converters.XML
class BookController {
def list() {
def books = Book.list()
withFormat {
html bookList: books
js { render "alert('hello')" }
xml { render books as XML }
}
}
}
However, I would like the responses of ALL my controller methods to do this. Is there a better way to get this behavior than to simply copy-paste the withFormat block at the end of every content-returning action?
First two things that popped in my head were Interceptors and Filters:
http://grails.org/doc/1.3.7/ref/Controllers/afterInterceptor.html
http://grails.org/doc/latest/guide/6.%20The%20Web%20Layer.html#6.6 Filters
Interceptors won't work because you can't do the withFormat. Bummer because that's a more global.
Filters will work on a controller per controller basis, but at least you'd be minimizing your duplication at that level.
def afterInterceptor = {model, modelAndView ->
withFormat {
html { model }
js { render "alert('hello')" }
xml { render model as XML }
}
}
This worked for me in my test project. I tried putting that closure into it's own class and mixing in the class so that you could do a more global solution... no dice though.
Maybe have all of your afterInterseptors pass the model, modelAndView to a common class? That seems to work :) (working towards an answer while answering)
#Mixin(AfterInterceptorWithFormat)
class FirstController {
def action1 = {}
def action2 = {}
def afterInterceptor = {model, modelAndView ->
performAfterInterceptor(model, modelAndView)
}
}
class AfterInterceptorWithFormat {
def performAfterInterceptor(model, modelAndView) {
withFormat {
html { model }
js { render "alert('hello')" }
xml { render model as XML }
}
}
}
Give that a whirl and let me know what you think.
What I ended up doing is to simply adjust the default CRUD templates to have the withFormat block at the end of each method.
I realized that what I really wanted was just content-negotiated CRUD, so putting the code into the templates was all I needed for that.
The rest of the controllers for the non-crud parts of my application did not need no-html output, so I didn't need content negotiation on anything but the crud controllers.

Making Grails controllers more DRY?

I am looking for ways on how to cleanup my Grails controller code. In various controllers i more or less have the same logic..
get the object
check if it exists
etc..
Is there a suggested way on making controller actions reuse common code?
--- solution ---
All answers to the question have contributed to the solution we have implemented.
We created a class that is used in our controllers using the Mixin approach. One of the methods that the mixin exposes is the withObject method. This method takes the domainname from the controller and uses this a base for the method. This behaviour can be overridden of course!
def withObject(object=this.getClass().getName()-"Controller", id="id", Closure c) {
assert object
def obj = grailsApplication.classLoader.loadClass(object).get(params[id])
if(obj) {
c.call obj
} else {
flash.message = "The object was not found"
redirect action: "list"
}
}
So all answers have contributed to the solution! Thanks a lot!
I always pull out this blog post when this question comes up:
http://mrpaulwoods.wordpress.com/2011/01/23/a-pattern-to-simplify-grails-controllers/
Basically you have a private helper for various domains in your controllers.
private def withPerson(id="id", Closure c) {
def person = Person.get(params[id])
if(person) {
c.call person
} else {
flash.message = "The person was not found."
redirect action:"list"
}
}
The way you code the getter is very flexible and a typical use for me (that is not covered in the blog) is for editing etc.
I normally code this way (i like the pattern for its clear division and readability):
def editIssue() {
withIssue { Issue issue ->
def issueTypes = IssueTypeEnum.values().collect {it.text }
[issueTypes:issueTypes,activePage:"issue", issue: issue]
}
}
def doEditIssue(IssueCommand cmd) {
if(cmd.validate()) {
withIssue { Issue issue ->
issue.updateIssue(cmd)
redirect(action: "show", id: issue.id)
}
}
else {
def issueTypes = IssueTypeEnum.values().collect {it.text }
render(view: "edit", model:[issueTypes:issueTypes,issue:cmd,activePage:"issue"])
}
}
With my getter helper being:
private def withIssue( Closure c) {
def issue = Issue.get(params.id)
if(issue) {
c.call issue
}
else {
response.sendError(404)
}
}
I do think that the mixin method (very similar to the 'extend a common abstract controller' way) is nice too, but this way gives two advantages:
You can type the helper, like you see I do in the closure giving you access to the methods etc in STS/IDEA (not tested Netbeans)
The repetition is not very high, and the ability to change the getter (to use for example BarDomain.findByFoo(params.id) etc)
In the view I bind to edit() I just put an id="${issue.id}" in the <g:form> and it works seamlessly.
I wouldn't recommend inheritance for that, as you can't spread generic methods in several super classes. Your abstract class would quickly become messy if you have many controllers. You can't use composition (for instance using a Service) because you don't have access to response, render, or params directly from there.
The approach I use is to inject generic methods via Mixins.
#Mixin(ControllerGenericActions)
#Mixin(ControllerUtil)
class BookController {
def show = &genericShow.curry(Book)
def exists = {
render(idExists(Book))
}
}
The first action show uses a generic method in ControllerGenericActions.groovy, with an argument binded to it. The second use of a mixin idExists method is inside a controller action.
Here is an example code for src/groovy/ControllerGenericActions.groovy
class ControllerGeneric {
def genericShow(Class clazz) {
render clazz.get(params.id) as XML
}
}
and in src/groovy/ControllerUtil.groovy
class ControllerUtil {
def idExists (Class clazz) {
return clazz.get(params.id) != null
}
Not very useful in this case, but you get the idea.
Implement abstract controller with common methods (use 'protected' directive) and extend from it your real controllers. Do not use 'get' and 'set' words at the beginning of this method's names. Not good, but it works.

Resources