Calendar
QuicksearchBookmarksMy del.icio.us
ArchivesCategoriesSyndicate This BlogBlog Administration |
Wednesday, August 2. 2006Creating an autocomplete with Spring and DWR
There is a lot of talk around the web about autocomplete with ajax. I have blogged about a solution with ajaxtags and spring before (link). It is a nice solutions that works pretty well. Still I did not feel right to have to do a lot of configuration within spring and do something special in your normal code. I also had a look at dwr. This is a nice library that lets you expose a serverside service to your javascript. A number of javascript libraries are generated runtime, you can use these libraries from your scripts within the browser. There is a nice integration with script.aculo.us. Now you can use a lot of components out of the box. Next step, use the script.aculo.us autocomplete component with dwr. Well that is easy said. There are some blog items on the web that tell you how to do this. The best way is to have a look at some sample code Bram smeets made on his blog. I used his code to create a sample that uses maven to build and package. I also used the callisto ide, works very good as well. I would not try the maven plugin yet, I did but it fails for now.
After this rather long introduction, time to get the coding done. Step1 Get your environment in place. Run the maven archetype command to create a webproject template. Alter some of the default values to make it your project and put in dependencies on the following libraries to your pom.xml file: spring-webmvc-1.2.7 (org.springframework) dwr-1.1.1 (uk.ltd.getahead) Execute the command to setup your eclipse environment and startup eclipse. commands:
Step 2 Time to explain a little bid what the application is going to do. Actually there is two phases in the application. First search for a known postalcode. If you have found the right one and pushed the search button, the accompanying address is obtained. Sounds easy doesn't it? We are going to expose a service object with two methods:
It should be obvious what the implementation of this interface should do. To be able to do an easy test, I created a mock implementation for this interface. The mock contains a hashtable with some postal codes as a key and the belonging address as the value. The two methods mentioned before use this hashmap to return all postalcodes or the address for a specific postal code.
Fianlly there is a transferobject called AddressTO that contains the following 4 fields: streetname, houseNumber, city, postalCode. Download the source to have a look. We have created the interface and an implementation. Time to do some spring configuration. We only need to create one bean, therefore the config file is very easy
Step 3 After this everything is in place to configure dwr to expose the spring bean. To be able to use dwr, we first need to add the dwr servlet to the web.xml file and load the spring context:
Dwr uses a configuration file to configure the beans that are exposed to your javascripts. This file is next to web.xml and is called dwr.xml.
By default you allow all methods to be called, you should allow only the real ajax usable methods. The create element is like the constructor, I tell dwr to use spring to create the javascript object AddressServiceFacade based on the spring bean addressServiceFacade. Because a use a transfer object for the address I also need the converter. Everything is ready to do the first test. Deploy the application to tomcat and call the following url: http://localhost:8080/ajaxdwrsample/drw You should get a page with a link to AddressServiceFacade, click this link and have a look at the next page: ![]() test page of dwr On this screen you can test your dwr ajax service. Use the execute buttons and input boxes to test the services (see the red box). Great isn't it? Step 4 And now for the webpages. First add the script libraries to your war file. I added the Prototype script and the script.aculo.us. to the folder "scripts". Next to that I added to style sheets (I copied all these files from the sample by Bram Smeets). Out of the box there is no support in script.aculo.us for autocomplete via dwr. Therefore I used the excellent component from Bram to implement it. The component resides in the "autocomplete.js" file. Finally the index.jsp that implements the real automcomplete component. The includes:
Important in the includes is the AddressServiceFacade, this is the generated script file by dwr based on the dwr.xml file. There we configured this name ... javascript="AddressServiceFacade" .... Now the standard scripts are in place, do the html thing:
The constructor for the autocomplete component has 4 parameters:
The callback function looks like this:
Doesn't look very difficult, does it? Beware of the function nameValueSelector, it receives a tag object. This can be a simple object (like in my case, a string). It can also be a javabean representation, then you need an extra method to obtain the property to show in the autocomplete box. If you return a list with AddressTO objects and want to show the postalCode of the address, this line would be : return tag.postalCode. The autocomplete box will now look like the following image: ![]() Your autocomplete is done, there is one extra thing in the sample. You can select the postal code and look for the belonging address. That is done the with the following piece of html and javascript.
The id's of the span elements resemble the fields of the AddressTO javabean. With the help of the dwr utility package we can easily fill these spans with data obtain via dwr. This is done with the following to functions.
The handleAddClick button receives the onClick event from the search button. First we obtain the value from the input field, then we call the dwr javascript object. This method obtains 2 parameters, one more than the real method. The extra parameter is the callback function. This function gets called with the return value of the original java function. We configured the fillAddress function to be the callback function. The special util function "DWRUtil.setValues" sets the values of the address to the spans. The end result looks like this: ![]() Download the sources here : ajaxdwrsample.zip That's it, hope you like this article. Thanks again to Bram Smeets for his autocomplete component and of course the excellent dwr and script.aculo.us frameworks. Trackbacks
Trackback specific URI for this entry
No Trackbacks
Comments
Display comments as
(Linear | Threaded)
Thanks for your writting this article that is very helpful to me. I am deeply appreciated.
Comment (1) Excellent! Worked like a dream. Thanks for taking the time to write this up.
Comment (1) Hmm i have a strange problem,
the autosuggestion-div is not showing up allthough all data is there and the rest works fine.. hmm any ideas ? Comment (1) Ofcourse there can be a lot of problems, did you try a javascript debugger? A lot of this problems arise when you have two components with the same idea, or you html code is not valid (missing a tag, comments not closed). Do you have it running somewhere? Then I can have a look.
Comments (3) Example was good But, can we write MockRemoteAddressServiceImpl class by using spring controller i.e(SimpleFormController ....). IF yes please tell me the example . I am waiting for that.
Comment (1) I am not sure that I understand what you mean. The options for the list are retrieved through the described exposed spring service. Storing the value can be done using SimplFormController the usual way.
Comments (3) Hi. Thanks for a good article. Your code works great! However, in an attempt to improve your code even further I tried to add a a hook to the afterUpdateElement event as described in Bram Smeets' blog. This way the Address fields could be populated right after the user has selected a list item (without having to press the search button).
By doing this I ran into something that seems like a bug. Not sure if this is a bug in Bram Smeets' autocomplete component or the Ajax.Autocomplete DWR component. Does anyone know? Here's a simple way to reproduce my problem: Add the following function to the index.jsp file: function afterUpdate(inputfield, selectedItem, selectedObject){ alert('selectedItem: ' + selectedItem.innerHTML); alert('selectedObject: ' + selectedObject); } Then change the instantiation of the autocomplete component, to something like this: new Autocompleter.DWR('searchPostalCode', 'postalCodeList', updateList,{afterUpdateElement: afterUpdate, valueSelector: nameValueSelector, partialChars: 0 }); Now test the application. Do you see that the alert box does not show the correct value for the parameter 'selectedObject'? Isn't it supposed to be the same as in 'selectedItem'? Any clues on how to fix this bug is greatly appreciated Cheers Comment (1) on change I needed to make in index.jsp
function handleAddClick() { //AddressServiceFacade.findAddressByPostalCode(fillAddress,searchString); AddressServiceFacade.findAddressByPostalCode(searchString,fillAddress,); // or I would get a missing method or missing parameters //message for AddressServiceFacade.findAddressByPostalCode thanks for your blog! Comment (1) Hello,
I like DWR and I very appreciate this arlicle because it helps me with implementation of certain page. But I met the problem in IE 7. It doesn't work for me? It's only my problem? Thank you for any hint. PETER Comment (1) Would you please explain the use of valueSelector option (valueSelector: nameValueSelector, for example.)
Comment (1) This function can be used if the list of obtained objects are not simple objects. If you return AdressTO objects instead of a string in the Set, you need to do some extra work here. Check the comments in the article.
Comments (3) very nice...
seems like it makes more sense to be able to select the item if user has typed exact match (changed != to >=) if (foundPos == 0 && elem.length >= entry.length) { Comment (1) Can any body help ? How to perform the same thing using "struts2" DWR Prototype etc..
If we will use struts2 instead of spring frame work what chages will be needed in above things? Thank you Comments (2) In Opera 9.10 the drop-down box displays at the top . rather then at below the text-box.
Comments (2) There is a mistake in the attached source code
you should change the line in index.jsp to AddressServiceFacade.findAddressByPostalCode(searchString,fillAddress); instead of AddressServiceFacade.findAddressByPostalCode(fillAddress,searchString); Comment (1) Any idea how to make this work with the indicator property specified in the Ajax.Autocompleter docs (http://wiki.script.aculo.us/scriptaculous/show/Ajax.Autocompleter)?
Comment (1) Autocompleter.DWR is not a constructor
http://localhost/w.p?p=index I get this above error, can anybody what could be the problem. Thanks in advance. new Autocompleter.DWR('where-field', 'whereList', updateList, { valueSelector: nameValueSelector, minChars:3, partialChars: 3, frequency:0.1 }); function updateList(autocompleter, token) { LocationService.find(token, function(data) { autocompleter.setChoices(data) }); } function nameValueSelector(tag) { return tag; } alerts.page = "home"; Comment (1) Autocompleter.DWR is not a constructor
http://localhost/w.p?p=index You might be getting this error because your code is not getting the following js files: link rel="stylesheet" type="text/css" href="/ajaxdwrsample/styles/autocomplete.css"/> script type='text/javascript' src='/ajaxdwrsample/dwr/interface/AddressServiceFacade.js'> script type='text/javascript' src='/ajaxdwrsample/dwr/engine.js'> script type='text/javascript' src='/ajaxdwrsample/dwr/util.js'> script type="text/javascript" src="/ajaxdwrsample/scripts/prototype/prototype.js"> script type="text/javascript" src="/ajaxdwrsample/scripts/script.aculo.us/effects.js"> script type="text/javascript" src="/ajaxdwrsample/scripts/script.aculo.us/controls.js"> script type="text/javascript" src="/ajaxdwrsample/scripts/autocomplete.js"> The Solution is: Download the above js files from: http://script.aculo.us/downloads and make them available to the JSP by adding appropriately to your App. structure. (I am having some problems with tags in comments so I removed the tag opening, at least you can see the lines now) Comments (2) I am trying to use this example with struts 1.3 instead of spring but i got the following error message
message[java.lang.IllegalArgumentException: Missing method or missing parameter converters] Can anyone help me to slove this issue..?? Thanks in advance. Comment (1) If I have understood your problem, you can solve it modifying autocomplete.js:
from: if ( (foundPos == 0 && elem.length != entry.length){ in: if ( (foundPos == 0 && elem.length != entry.length) || elem.length == entry.length) { bye roberto Comment (1) Great example, thanks! I got it working with Spring 2 & DWR 2 (eventually). Completely new to AJAX so was good place to start. The problem I've got with it is that the server seems to freeze up after about 10 usages, using a proxy scanner you can see the request from the client to the server is made however the server doesn't respond. I put debug logging on the server and not even the low level DWR code is being called when the request is made, is this normal. Can you suggest something I can look into?
Thanks in advance. Comment (1) seems a little confusing..why not just use PredictAd's autocomplete service - it's free and generates additional search revenue..
Comment (1) its good article.... but come across one problem..
when i enter some chars and data is available based on that then it works but when no data found if gives an error in form of alert instansce.options.element has no properties how to handle this issue.. 2. it only displays 10 record in the div not more than that... i need to display all records found based on that.... and what should i do if i want to add scroll if it gets longer than 20 Comment (1) I am using DWR with Scriptaculaus scripts. The auto-complete functionality is working fine.
When I entered some words in the text-box, the auto-complete selects the first element of the auto-complete list by default. So when i press enter the first element fills my text-box. I dont want that to happen. So I dont want to select the first element by default. It should be selected when I press the down key or up key of the keyboard. Is there any way to do this? Comment (1) I would better suggest you yui autocomplete widget for the functionality you are working on. It can be easily integrated with DWR. The widget handles keypress and mouse move functionalities.
you find the rest information on: http://webbits.pl/yui/examples/autocomplete/ac_states_jsarray.html Comments (2) Is there a way to provide scroll feature for this example? If I have more than 10 results(choices) i want to have a scrollable window. I tried to do this in css by adding overflow:auto but it doesn't work well in IE.
Comment (1) Hi, First of all let me a big thank you for this tutorial. I've followed the steps that you mentioned above on my console I'm getting the following error:
SEVERE: Line=1 Document root element "dwr", must match DOCTYPE root "null". 10-Sep-2008 22:34:30 org.directwebremoting.util.CommonsLoggingOutput error SEVERE: Line=1 Document is invalid: no grammar found. When I try to load the page my javascript debugger fails with the following error: Autocompleter is not defined Any Ideas? Comment (1) Very Nicely written blog.. For people who are very much new to DWR and ajax.. this is an excellent article... Thanks again for taking the time to come up with post..
Comment (1) I am attempting work this example and all seems to work well, except that when I type a character in the object, the autocomplete div shows with the correct number of items, only they all say "[object Object]". I am not sure what the issue is, since all the code is an exact copy of your example. Are you able to help in this matter?
Comment (1) As objects are in any array and you have internal property you need to add the property name to the function as below
employe:{ name age } function nameValueSelector(tag) { return tag.name; } Comments (3) Having problem in IE 7
The options getting populated in the div. not able to see the added elements, but the div is shown when i click on invisible option that particular element is selected. any one facing the same problem? any patches? Comments (3) By commenting the below line in controls.js, show() function
// if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); It worked fine. Comments (3) I tried the code sample and everything works for the most part. However, I was expecting the match to be made for all words in the strings and not just only the first word. I believe this is the default setting of "partialSearch". Also, when setting the partialChars to 2, I still get matched at the first character.
Comments (2) Found the solution myself after skimming through the scriptaculous documents. To match any word in input field, set {token: ','} as option value/parameter when calling the autocompleter. The example here uses the comma as delimiter for tokens, but you can use any character you want. If you want multiple delimiters, define them in array, example:
{ tokens: [',', '\n'] } Comments (2) Hi dudes! i was wondering if it's possible to store not just the description of an object like bean.desc by example after the user choses an element on the div, i mean is it possible to store by example bean.id in a hidden field of the form... you know to send it to the action...sometimes the desc is meaningless what really matter is the id of the object... how can i store that value after the user choses the element... thanks in advance... like its ussual i needed this yesterday...
greetings, sorry for my english! Comment (1) I tried the code sample. But only when we type postal code in the text box, and then click Search button, It shows the address. But the text box does not work as autocomplete. So do u think where is my error? Pls tell me.
Comments (2) When I place all the scirpts files as the same directory with index.jsp file. Autocomplete is Ok. But we can't see autocomplete last long....We don't have time to choose any one.do u think where is my error?
Comments (2) Hi,
I tried this.But in my case the exposed service methods returns a list of Member java objtects.Member have attributes name,memId,familyName where I want to show the names in the auoto complete.How do I do this. Currently my name value selecter looks like function nameValueSelector(tag){ alert("Tag>"+tag); return tag.getName(); } but I am getting "Object doesnt support this property" message.Can anybody help? Shaiju Comments (2) Hi,
I am able to retrieve teh data sucessfully, but I am not getting the choices. new Autocompleter.DWR('memberText', 'memberList', updateList,{ valueSelector: nameValueSelector, partialChars: 0 }); But the div is not getting displayed....... Any suggestions ? Shaiju Comments (2) Hi! The sample works good. But it uses static data.
I make some changes in MockRemoteAddressServiceImpl: the function findCompletePostalCodes now request database (something like "select code from postalCodes" ) and returning the List as it was in the sample! I'm complettely shure the function returns not empty list with some strings.. However I get no choices! I see in debagging messages that the I have data in my list... Any ideas? Comment (1) hi,
i tried with the given ariticle, with the environment eclipse and tomcat webserver. Here, the file AddressServiceFacade.js is not being created. so getting the error "AddressServiceFacade is undefined" Could you plz. help me out.. Comment (1) Hi,
I have a problem.when I input chinese,why can't touch the updateList function?who know this?Thank you ! Comments (2) Hi,
I have a problem.when I input chinese,why can't touch the updateList function?who know this?Thank you ! Comments (2) How can introduce scrollable div property here. I want to have all choices matching the criterion and show then in a scrollable div. pls advise. just like item 8 here :
http://www.javascript-examples.com/autocomplete-demo/ Comment (1) Has anybody tried doing it in a textarea with autocompletes for every new line like wick(http://wick.sourceforge.net/)
Comment (1) hi... thanks for post... It is not working for me... Actually the code is not generating the dynamic javascript. When i click the "inspect element" on the browser it is showing the dynamic js files name and once i click on it to see the content, then it shows page not found.
is there any extra setting??? can you please help me... thanks in advance. Comment (1) hi..i am very new to dwr..so plz solve my problem
i want to call a different function after selecting name from autocomplete list.this finction will display address.it should be called immediately after selecting name and not on button click event.. Comment (1) Sorry, but this is to old to get working. I haven't been using it for years. So I would advise you to do the same. There are a lot better alternatives to be found around the web.
Comment (1) Traveling is something we all look ahead to.
It is a burglary the monotony of every working day daily life. It really is a chance to unwind and are living relaxed for any week or two, from function and all sorts of duties. The following is some advice for the following time you go on holiday. Comment (1) Add Comment
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||

