Fairly new to the Grails model, and having a little trouble getting around using a service for my database transactions.
Service:
class ReportService {
def dataSource
def listDatatypeValues(Datatype dt) {
def sql = new Sql(dataSource)
def list = sql.rows (dt.statement)
return list
}
}
Controller:
def run(Long id) {
def reportInstance = Report.get(id)
def listPromptValues = populatePrompts(reportInstance)
if (!reportInstance) {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'report.label', default: 'Report'), id])
return
}
[reportInstance: reportInstance, listPromptValues: listPromptValues]
}
def populatePrompts(Report rp){
//for a prompt in the report, go out and get it's values
rp.prompts.each {
List list = reportService.listDatatypeValues(it.datatype)
}
}
View snippet:
<g:if test="${reportInstance?.prompts}">
<li class="fieldcontain">
<g:each var="prompt" in="${reportInstance.prompts}">
<g:if test="${prompt.datatype.type == 'DropDown'}">
<g:select id="prompt.name" from="${listPromptValues}" name="prompt.name" value="" noSelection="['':'']"/>
</g:if>
</g:each>
</li>
</g:if>
We have a report object, that contains prompts, which in turn contain a datatype. For any given report, when it is pulled up on the UI, it will give the report details, and then list the prompt value for a give prompt. The problem is the current setup is listing the object reference as the prompt value and not the list of values returned from the service.
And example would be Report 1 has 2 prompts, Starting Term Code and Ending Term Code. Both of them use Term Code as the datatype since it is the same SQL query, and the list returned from listDataTypeValues would be a list of 70+ term codes that are stored in the database.
Any thoughts or direction?
I tried following along with this but I can't get it to work.
Thanks!
Your populatePrompts function isn't returning a meaningful value. If you iterate with collectMany instead of each the value of the expression will be the concatenation of all the results from your queries. Try something like this:
def populatePrompts(Report rp){
rp.prompts.collectMany {
reportService.listDatatypeValues(it.datatype)
} //.unique()
}
You may also want to call unique on the result to avoid duplicates in your g:select input.
Related
My Domain Classes simplified look like this:
class ScheduleTimeExp{
Data date
}
class ScheduleAction{
ScheduleTimeExp scheduleTimeExp
}
I have a select box in my gsp:
<g:select id="scheduleTimeExp" name="scheduleTimeExp.id" from="${tao.marketing.ScheduleTimeExp.list()}" optionKey="id" required="" value="${tao.marketing.ScheduleAction?.scheduleTimeExp?.id}" class="many-to-one"/>
Rather that letting the user select from all ScheduleTimeExp
from="${tao.marketing.ScheduleTimeExp.list()}"
I would like to show only those ScheduleTimeExp where a relation between ScheduleTimeExp and ScheduleAction does not exist for any other ScheduleAction. In other words only those time expressions which have not yet been selected in another ScheduleAction.
To enforce logic from presentation separation, you want to fill the list inside controller action:
def dataSource
def someAction() {
final Sql sql = new Sql( dataSource )
def scheduleTimeExps = sql.rows( 'select ste.id, ste.date from Schedule_Time_Exp ste where ste.id not in (select sa.Schedule_Time_Exp_id from Schedule_Action sa)' ).collect{ it as ScheduleTimeExp }
[ ..., scheduleTimeExps:scheduleTimeExps ]
}
Note: make sure the case and naming of the tables and columns are correct
and then in gsp:
<g:select .. from="${scheduleTimeExps}"/>
In the groovy Controller Code I call the function:
def wiki =
{
def currentNode = params.nodePath
def conceptName = nodeService.retrieveConceptName (currentNode);
render (template:'wiki', model:[conceptName : conceptName])
}
In the service class I define the function retrieveConceptName:
def retrieveConceptName(currentNode)
{
groovy.sql.Sql sql = new groovy.sql.Sql(dataSource);
def row= sql.firstRow(" SELECT cname FROM Person WHERE FULLNAME= ?",[currentNode]);
return row;
}
In my output(wiki template(gsp view)) I get flowerbrackets along with field header , How to get only value of column and not the flower braces or field header?
You haven't shown the GSP code that displays the row, but I guess it looks like either ${it} or ${row}. If so, replace it with either
${it.cname} or ${row.cname}
I have a search webpage where user's can filter the search results by a person's ethnicity, as a checkbox group. There are 12 'ethnicity' checkboxes. The params get passed into g:paginate as the following, so that the user can page through the results and preserve what was checked in the ethnicity checkboxes:
<g:paginate controller="search" action="list" total="${resultCount}" params="${params}"/>
What gets output for the links includes a bunch of unnecessary data for each built URL:
2
I'd like the pagination link URLs to be output without all the extra _ethnicity variables that get passed back in the original search post:
2
How can I get the params into the paginate tag without all the extra unnecessary fields? Functionally it works, but the URLs for the paginate get requests are too long and look hideous.
Try this..,.
<g:paginate controller="search" action="list" total="${resultCount}" params="${params.findAll { it.key == 'ethnicity' && it.value }}"/>
it gives you
2
One of the dirty way to achieve what you want is
<g:paginate controller="search" action="list" params="${
params.findAll { a ->
if (a.value instanceof Collection) {
def c = a.value.findAll { b ->
return b
}
if (c) {
return c
}
} else {
return a.value
}
}
}"/>
EDIT:
spock99 answer is much better than mine, one more way is
params="${params.findAll { !it.key.toString().startsWith("_") }}"
Per the previous user, this works to filter out the extra fields, though it is ugly.
params="${params.findAll { a ->
if (!a.key.toString().startsWith("_")) {
return a.value
}
}
}"
EDIT:
Actually a cleaner way is to put this in the controller:
params.keySet().asList().each { if (it.toString().startsWith("_")) params.remove(it) }
Then in the g:paginate you can stick with
params="${params}"
I have a simple Tag class with only two fields, name and value,
class Tag {
String name
String value
}
and I'm trying to render an XML where I want to search for parts of both parameters via findBy...Ilike().
def getXml = {
render Tag.findAllByNameAndValueIlike("%${params.name}%", "%${params.value}%") as XML
}
But this doesn't give my any results. If I use only one parameter, it works as I expect:
def getXml = {
render Tag.findAllByNameIlike("%${params.name}%") as XML
}
My next question is probably going to be about filtering the results, and adding other "similar" tags to the returns list, so is there a way to solve the above with something like:
def getXml = {
list = Tag.findAllByNameIlike("%${params.name}%")
list.add(Some other stuff)
list.sortBy(Some thing, maby name length)
}
For your multiple-field ilike query you can use withCriteria:
def result = Tag.withCriteria {
ilike('name', "%${params.name}%")
ilike('value', "%${params.value}%")
}
This will return a list of Tag domains whose name matches the provided name and value matches the provided value.
The Criteria DSL will probably let you do most of the filtering you need, but you can also consider using some of the Groovy collection examples here.
You have to put the restrictions(InList, NotNull, etc) on each field of a dynamic finder. If you do not, it assumes equals. Here is what you were looking for:
Tag.findAllByNameIlikeAndValueIlike("%${params.name}%", "%${params.value}%")
Both answer are good. I tried both, but I have to say I like the withcCritia the best. It seems very flexibly.
def result = Tag.withCriteria {
if(params.name != null)
ilike('name', "%${params.name}%")
if(params.value != null)
ilike('value', "%${params.value}%")
}
result.add(new Tag('name': "something"))
render result as XML
Basically what I want is:
<g:fancyJoin in="${myList}" var="item" separator=", ">
<g:link controller="foo" action="bar" id="${item.id}">${item.label}</g:link>
</g:fancyJoin>
and for
def mylist = [[id:1, label:"first"], [id:2, label:"second"]]
it should output:
first, second
The key difference between this and the existing join tag is that I need it to basically do a collect and apply tags over the initial list before performing the join operation
You shouldn't do this in a GSP. Cluttering your view with loops and conditionals makes it hard to maintain the code and forces you to test with functional tests which are quite slow. If you do this in a taglib you clean up the view and testing is very easy.
You could define a custom tag, something like:
def eachJoin = {attrs, body ->
def values = attrs.remove('in')
def var = attrs.remove('var')
def status = attrs.remove('status')
def delimiter = attrs.remove('delimiter')
values.eachWithIndex {entry, i ->
out << body([
(var ?: 'it') : entry,
(status ?: 'i') : i
])
if(delimiter && (i < values.size() - 1)) {
out << delimiter
}
}
}
Usage:
<g:eachJoin in="${myList}" var="item" delimiter=", ">
<g:link controller="foo" action="bar" id="${item.id}">${item.label}</g:link>
</g:eachJoin>