ncbiXML.GBSeq.'GBSeq_feature-table'.GBFeature.each{feature ->
if((feature.GBFeature_key as String) == "CDS")
{
feature.GBFeature_quals.children().each{qual ->
}
}
Tuesday, June 29, 2010
XMLSlurper trying to annoy me
Just a little note: If you ever wonder why you're iteration of XMLSlurper elements does not work: Try inserting a .children() before the .each(). Have a look at this code, where you have one case where it works without and in the second place only with .children():
Parsing XML: two stumbling blocks and a problem with params
Today I wanted to parse some XML content from NCBI into my grails application. I followed the instructions on:
http://www.ibm.com/developerworks/java/library/j-grails05208/index.html
Although the connection did not seem to have any problems, the parsing from a XMLSlurper object to a map did. There were in fact two problems I had to face and luckily I found the solution for both of them here:
http://stackoverflow.com/questions/1849547/groovy-xmlslurper-not-parse-my-xml-file
The first problem was that you cannot have a dash in your XML node unless you embrace it with hyphens like this:
I guess dashes are otherwise interpreted like dots (separators). I imagined something like that when I encountered the error "no property like that".
After fixing this the code ran through. The tests however still failed as only empty values were returned. The solution was to ignore the top node of the XML input. Starting one node below everything worked fine.
Now, equiped with a nice map I wanted to create domain objects following the helpful steps at the end of this article:
http://thediscoblog.com/2009/02/19/restful-grails-services-in-3-steps/
To make the properties editable before submission, I added a new action to a controller that redirects to "create" and hands over the xml parsed map from XMLSlurper as params.
That would probably have worked if it hadn't been for one property that was not a string, but an object. I thought no problem, all I have to do is use a dynamic finder to get my object with the string. This produces errors as grails interpreted this parameter as String and threw conversion exceptions when trying to parse a string to my object:
I have googled for hours and tried everything, but finally I found the very simple solution. You have to put it like this to convince grails that it has to look up for a domain object itself via id:
Again, the hyphens are very important. In the beginning I tried different things without them and then grails tries to resolve the dot instead of letting the parameter go.
Now everything works fine and I hope someone can use this to get started real fast on this (not like me :-)
http://www.ibm.com/developerworks/java/library/j-grails05208/index.html
Although the connection did not seem to have any problems, the parsing from a XMLSlurper object to a map did. There were in fact two problems I had to face and luckily I found the solution for both of them here:
http://stackoverflow.com/questions/1849547/groovy-xmlslurper-not-parse-my-xml-file
The first problem was that you cannot have a dash in your XML node unless you embrace it with hyphens like this:
ncbiXML.GBSeq.'GBSeq_accession-version' as String
I guess dashes are otherwise interpreted like dots (separators). I imagined something like that when I encountered the error "no property like that".
After fixing this the code ran through. The tests however still failed as only empty values were returned. The solution was to ignore the top node of the XML input. Starting one node below everything worked fine.
Now, equiped with a nice map I wanted to create domain objects following the helpful steps at the end of this article:
http://thediscoblog.com/2009/02/19/restful-grails-services-in-3-steps/
To make the properties editable before submission, I added a new action to a controller that redirects to "create" and hands over the xml parsed map from XMLSlurper as params.
That would probably have worked if it hadn't been for one property that was not a string, but an object. I thought no problem, all I have to do is use a dynamic finder to get my object with the string. This produces errors as grails interpreted this parameter as String and threw conversion exceptions when trying to parse a string to my object:
Cannot convert value of type [java.lang.String] to required type
I have googled for hours and tried everything, but finally I found the very simple solution. You have to put it like this to convince grails that it has to look up for a domain object itself via id:
ncbiMap.'organism.id' = organism.id
Again, the hyphens are very important. In the beginning I tried different things without them and then grails tries to resolve the dot instead of letting the parameter go.
Now everything works fine and I hope someone can use this to get started real fast on this (not like me :-)
Labels:
dash,
grails,
hyphens,
parameters,
parsing,
type conversion,
xml,
xmlslurper
Monday, June 28, 2010
grails-ui autocomplete with "onSelect" event
Today I had my first try in integrating an autocomplete feature. I was more successful than expected due to the very easy to use grails-ui library. You have to put code like that in your controller to serve data to the taglib:
As you can see you need to provide your data JSON formatted. You also have to use the parameter "query" to filter results that fit what the user has already typed in. Furthermore you can collect only those properties of your domain class that are really necessary for the autocomplete. These are namely an id and a label to display and search. Okay now that we've seen this part, let's have a look at the GSP:
Here you can see different options that you can influence, e.g. how many letters one has to type in before the taglib starts AJAX-calling. Although more or less self-explaining, I will say a few words about those properties:
It took some time to find out how to do this, but finally it worked. What one has to know is:
What event do I have to subscribe to and even more complicated how do I access information about the selected entry? The event's name was itemSelectEvent and I managed to access the DOM element to get the selection's value, but I would be very interested to access the ID of the selected entry, too. Up until now, I could not find the ID anywhere in the DOM. Any comments on this problem are welcome!
def searchResultsAsJSON = {
def jsonList = Gene.list().findAll{it.name.startsWith(params.query)}.collect{[id: it.id, label: it.name]}
def jsonResult = [
results: jsonList
]
render jsonResult as JSON
}
As you can see you need to provide your data JSON formatted. You also have to use the parameter "query" to filter results that fit what the user has already typed in. Furthermore you can collect only those properties of your domain class that are really necessary for the autocomplete. These are namely an id and a label to display and search. Okay now that we've seen this part, let's have a look at the GSP:
<gui:autoComplete
minQueryLength="3"
queryDelay="0.5"
id="quickSearch"
resultName="results"
labelField="label"
idField="id"
controller="quickSearch"
action="searchResultsAsJSON"
/>
Here you can see different options that you can influence, e.g. how many letters one has to type in before the taglib starts AJAX-calling. Although more or less self-explaining, I will say a few words about those properties:
- idField is the name of the ID field in the JSON output
- labelField is the name of the label that is displayed for search in the JSON output
- resultName is the name of the top node used in JSON. In the above example this was results.
YAHOO.util.Event.onDOMReady(function() {
GRAILSUI.quickSearch.itemSelectEvent.subscribe(function(type, args) {
${remoteFunction(controller:"quickSearch", action:"showResult", params: '\'name=\'+GRAILSUI.quickSearch.getInputEl().getValue()', update: [success:'body',failure:'body'])};
});
});
It took some time to find out how to do this, but finally it worked. What one has to know is:
What event do I have to subscribe to and even more complicated how do I access information about the selected entry? The event's name was itemSelectEvent and I managed to access the DOM element to get the selection's value, but I would be very interested to access the ID of the selected entry, too. Up until now, I could not find the ID anywhere in the DOM. Any comments on this problem are welcome!
Wednesday, June 23, 2010
add drag and drop functionality to GRAILS-UI datatable editors
In my application I have added a GRAILS-UI datatable with in-line cell editing functionality at the bottom of my page. Problem was that the date picker element, which is a big fat, didn't fit onto the page and was unusable though. I asked the mailing list for help about that and Matthew Taylor adviced me to try and manipulate the position via CSS. That did not work for me as I figured out that the position was hard-coded in the style property of the div tag.
When I googled for a solution I found a post where it is explained how drag and drop functionality can be added to a YUI calendar widget. I adapted the solution here. Unfortunately I found no better way as to manipulate GRAILS-UI's source code. I edited DataTableTagLib.groovy around line 215 like this:
With this, the date picker has become draggable and can be of use for my users again.
When I googled for a solution I found a post where it is explained how drag and drop functionality can be added to a YUI calendar widget. I adapted the solution here. Unfortunately I found no better way as to manipulate GRAILS-UI's source code. I edited DataTableTagLib.groovy around line 215 like this:
case 'date':
editorConstruction += """
var ${editorName} =
new YAHOO.widget.DateCellEditor();\n
${editorName}.subscribe('showEvent', function()
{var dd = new YAHOO.util.DD(
${editorName}.getContainerEl());});\n"""
break;With this, the date picker has become draggable and can be of use for my users again.
Wednesday, June 16, 2010
grails-ui menubar and ajax with remoteFunction
I wanted to turn the links of the grails-ui menubar into ajax remoteFunctions or remoteLinks. This was - once more - far more complicated than I had anticipated. Fortunately almighty google brought me to the solution. The ugly thing: One has to change the code like stated in the jira. Now another ugly thing about the solution is - as indicated by the author - that one still has to provide a url. Not a problem I thought, but the whole thing did not work at all. I had to spend some time, before I could figure out what was going on:
Both - the URL and the remoteFunction - are executed. The remote function comes first (which is a good thing as we will see), but then the URL kicks in and you have a double page change behaviour. The fix is as easy as you can imagine (I wish someone had told me). You have to add 'return false' at the end of the remote function. This stops the URL href feature from being executed at all. VoilĂ remote function can reign in peace now.
Both - the URL and the remoteFunction - are executed. The remote function comes first (which is a good thing as we will see), but then the URL kicks in and you have a double page change behaviour. The fix is as easy as you can imagine (I wish someone had told me). You have to add 'return false' at the end of the remote function. This stops the URL href feature from being executed at all. VoilĂ remote function can reign in peace now.
javascript event mechanism for my application
The more and more I ajaxify my grails application,the harder it gets to keep all information on a site up-to-date. In my worst-case scenario there are dozens of dependencies and it is impossible to think of all of them. So the time for a event mechanism has finally come. Why haven't you done that a long time ago, you might ask. Well, I am not really familiar with javascript and as there is no in-editor correction like in my early Java days on Eclipse, I have had a hard time finding bugs in my code.
Lucky me: the cool guys from the YUI project have already taken the worst complexity of the problem of my shoulders. This means that I have used the YUI2 event utility. There are benefits I can not even imagine as a newbie, but features like automatic scope correction, object pass-throughs, etc. sound very cool and benefitial to me. Here is how I have set the whole thing up:
I have modified the main.gsp to introduce an event handler object. Putting it here makes sure that it will be available on every page:
I have not imported any js files as the necessary files have already been included by other grails plugins (mainly grails-ui). Read the doc if you have to.
One a page where I want to have event functionality I first declare an event (in this case it was within a taglib):
Now, whenever necessary I declare a callback function and register it with the event handler as listener:
The callback functions then usually make use of ${remoteFunction} to update a specific part of the page. I would not have guessed it, but if you got rid of spelling mistakes it works like a charm!
Lucky me: the cool guys from the YUI project have already taken the worst complexity of the problem of my shoulders. This means that I have used the YUI2 event utility. There are benefits I can not even imagine as a newbie, but features like automatic scope correction, object pass-throughs, etc. sound very cool and benefitial to me. Here is how I have set the whole thing up:
I have modified the main.gsp to introduce an event handler object. Putting it here makes sure that it will be available on every page:
I have not imported any js files as the necessary files have already been included by other grails plugins (mainly grails-ui). Read the doc if you have to.
One a page where I want to have event functionality I first declare an event (in this case it was within a taglib):
Now, whenever necessary I declare a callback function and register it with the event handler as listener:
The callback functions then usually make use of ${remoteFunction} to update a specific part of the page. I would not have guessed it, but if you got rid of spelling mistakes it works like a charm!
Bookmark TagLib
Today I have created a taglib for creating bookmarks. It needs two attributes attrs.type and attrs.id, where type corresponds to the class name. There is only JS code for Internet Explorer and Firefox included, so unfortunately it won't work on other browsers (yet).
def includeBookmarkThisPageLink = {attrs ->
def url = request.getRequestURL().toString().replaceFirst(".dispatch", "").replaceFirst("/grails", "") + '/' + attrs.id
def title = attrs.type.get(attrs.id)
out << """
Bookmark this page"""
}
Subscribe to:
Posts (Atom)
