tags:

views:

61

answers:

1

I have this code in a custom taglib that calls the GrailsUI Autocomplete tag:

def renderAutoComplete(uicName,isDisabled,theValue) {

    params.tableId = 3 // THIS ISN'T AVAILABLE TO AUTO COMPLETE ACTION

    out << gui.autoComplete(id:uicName,resultName:"lookUpData",controller:"lookupTable",action:"autoCompleteJSON") {}

}

Here's my action that get's called to populate the autocomplete:

def autoCompleteJSON = {

    def lookupTable = LookupTable.get(3) // PARAM NEEDS TO BE SET IN TAGLIB
    def list = LookupValue.findAllByLookupTableAndThevalueLike(lookupTable,"${params.query}%")
    def jsonList = list.collect { [ id: it.id, name: it.thevalue ] }
    def jsonResult = [
        lookUpData: jsonList
    ]
    render jsonResult as JSON //render only works in a controller

}

Everything works fine using the hard coded:

def lookupTable = LookupTable.get(3)

but of what I need is:

def lookupTable = LookupTable.get(params.tableId)

and params.tableId isn't available to the auto complete.

So how can I set a param in a taglib?

UPDATE

It turns out that gui.autocomplete provides two more params that I wasn't aware of. filterBy and filter can be used for precisely the need of passing a filter param to your controller. So now I do:

out << gui.autoComplete(id:uicName,resultName:"lookUpData",controller:"lookupTable",action:"autoCompleteJSON",filterBy:"lookupTable",filter:"${theTagtype.lookupTable.id}", queryDelay:"0.5", value:"${theValue}") {}

and it works perfectly. So my immediate problem is solved. But the general question remains: How can I set a param in a taglib?

+1  A: 

It seems a little strange that you'd need access to params in your tag closure since the output should really only depend on the tag attributes and the body. It's quite possible I have just misunderstood something, but if you need access to a request parameter in your tag I would expect the flow to be more like this.

First in the controller, send the params value to the GSP View/Template:

//Some controller method
def viewSomething = {
  render(view:'viewWithTag', model:['tableId':params.tableId])
}

Then in your GSP, set the tableId as an attribute on the tag so it doesn't need to know anything about the request parameters directly:

...
<renderAutoComplete tableId="${tableId}" /> 
...

Then in your taglib closure:

def renderAutoComplete = { attrs, body ->
   def t = Table.get(attrs.tableId)
   ...
}

Hope this helps! If I misunderstood your question let me know.

Update:

Okay, I think I understand the point of confusion now. Rendering the output of your tag is inherently part of the response whereas the built-in params is inherently part of the request. So your tag cannot set request parameters directly. Part of the functionality of gui.autoComplete and its YUI counterpart is that it generates the URL that will be used later on to send an AJAX request to your action. That URL contains HTTP request parameters in the typical ?name=value form. Grails automatically will populate those into the params variable available to you in the action.

This works much the same way as the grails createLink tag does. You can specify request parameters by defining a params attribute value:

<g:createLink action='act' controller='cont' params="[foo: 'bar', boo: 'far'] />

Within the implementation of createLink it is just setting HTTP parameters and grails is shoving those into params so that you have them in the controller logic. As an aside, you may also be able to set request parameters by including the same params attribute in your call to gui:autoComplete. I haven't tested this, but the code that is used to implements this seems to ultimately do a pass through to the grails createLink and I think by coincidence it may set the request parameters for you. Again, I haven't tested it and may be interpreting it wrong (see code here). If you test it out, let me know if it actually works.

proflux
What I'm doing is rendering a form dynamically. So renderAutoComplete actually get's called from the main function in my taglib. There's also renderTextBox, renderSelect, etc. I don't know what needs to be rendered until run time. In fact renderAutoComplete might be called multiple times, and need to render different data in the AC.I needed to set the value of the param in my taglib so that it was available to autoCompleteJSON, so it could gen the data for the AC.Turned out that the AC taglib provided what I needed. But I suspect there may be other use cases, so I didn't delete the ?.
Brad Rhoads