Announcement Announcement Module
Collapse
No announcement yet.
Best practices with Spring Roo , JSON and Ajax Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Best practices with Spring Roo , JSON and Ajax

    Hello,

    I am very new to Spring Roo and also new to Spring MVC ....

    So I have the following problem:

    I need a filterable list which has several filteroptions, like lets say a product finder while browsing the page.

    I want this list to be updated dynamically.

    My approach was to write a JSON based Spring controller (using the @RequestBody annotation and the ContentNegotiatingViewResolver) with all the finders I need and then using DOJO and normal HTML Inputelements to create this list. Is this the "Roo/Spring" way, or is there any component library where I should choose and extend an existing list (like a taglib or something)

    Help would be really appreciated !
    Last edited by cblicious; Feb 12th, 2011, 04:38 AM.

  • #2
    You can indeed use JSON to do Ajax quickly with Roo. The good news is that Roo includes FlexJSON to make that easy, and also that you already have a number of AJAX-ready components available with Dojo, which is also built in to Roo.

    (edit: I just re-read your original post and see you already know Dojo - that's going to save you a bit of time as you already know most of the Dojo side of this post - but hopefully this will be a guide for others too.)

    If you want to emit Ajax from a controller method the easiest way, do two things:
    • Add @RooJson to your class-level annotations on your entity or bean that you want to send as Ajax - for bean Foo, Roo creates Foo_Roo_Json.aj, which includes static toJson(), fromJson(), toJsonArray() and fromJsonArray() methods. This happens when you run the Roo shell after saving your update to the bean.
    • Use a @ResponseBody on the method to return the Ajax data as JSON

    So your method would look something like:

    Code:
    @RequestMapping
    public @ResponseBody String getAjaxList() {
        Foo result =     // do something here...
        return ResultObject.toJson(result);
    }
    Viola! You could also pass it parameters, etc...

    On to the client component. You can install a Dojo widget (what?) around a select box. Roo already does something like this on scaffolded pages with the Roo tag library form field form:select, but you will need to do your own.

    The trick in the scaffolded pages is that you'd need to disable the existing input field or dropdown, using the z="user-managed" setting. That causes Roo to skip installing the field itself. Then you write your own to replace it. If you don't use scaffolding, you can build your own pages, and do what you want. But since you're new to Spring MVC, stick with the scaffolding at first...

    I would suggest using a Roo custom tag to set up your ajax dropdowns, after you get one working in-line, so that you can dry up the page a bit.

    Before reading the next bit, take an hour or two to get a good look at the tag libraries - specifically /WEB-INF/tags/form - the create.tagx, list, show, etc., and the /WEB-INF/tags/form/fields tags. The one to zero in on is the select.tagx one. You'll see a Javascript tag in a number of places calling something called Spring.addDecoration - this is installing a Dojo widget.

    In those tag libraries, the actual tags use the Spring MVC forms library. They set up regular Spring MVC widgets, then 'decorate' them with the Spring.addDecoration javascript function, which is from a Dojo helper library called Spring Javascript. So, they do something like:

    Code:
       (in select.tagx):
       <form:select id="_${sec_field}_id" items="${items}" path="${sec_field}" 
             disabled="${disabled}" multiple="${multiple}"
             itemValue="${fn:escapeXml(itemValue)}" />
    <br />
        <form:errors cssClass="errors" id="_${sec_field}_error_id" 
          path="${sec_field}" />
    Coupled with, at the top of the tag, defining the use of the Spring MVC tag library:
    Code:
    <jsp:root xmlns:c="http://java.sun.com/jsp/jstl/core"
           xmlns:field="urn:jsptagdir:/WEB-INF/tags/form/fields" 
           xmlns:fn="http://java.sun.com/jsp/jstl/functions"      
           xmlns:spring="http://www.springframework.org/tags" 
           xmlns:form="http://www.springframework.org/tags/form" 
           xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0">
    Take note of the xmlns:spring and xmlns:form entries. The spring taglib provides things like message and URL lookups, and the form taglib provides access to the form data fields - like with form:select and form:error.

    If you want to use the Spring MVC tags in your Roo scaffolded pages so you can experiment with Dojo, you'll have to mount the tag library with a different name than form: - call it springform: and add it to your declarations on the form:list tag at the top.

    The thing that makes them Dojo widgets is the next step below in each tag:
    Code:
    <script type="text/javascript">
      Spring.addDecoration(
         new Spring.ElementDecoration({
             elementId : '_${sec_field}_id', 
             widgetType: 'dijit.form.FilteringSelect', 
             widgetAttrs : {hasDownArrow : true}})); 
    </script>
    That (strongly re-formatted) snippet tells Dojo that the dropdown installed in the script should be configured, via CSS and Javascript magic, into a Dojo widget.

    To get Ajax to happen, you need to learn Dojo's event model. It's not very hard, just something you need to wrap your head around. Suggestion, if you're new to all of this - INSTALL FIREBUG and learn to use it to watch AJAX and resource requests, and debug javascript. It will really help you.

    Dojo has two key methods - addOnLoad and connect - that really help you wire things together. The addOnLoad triggers setup of something when the page is loaded, but not visible:

    Code:
    dojo.addOnLoad(function() {
    
        // find a widget with the ID of myDropDownId and wire a 
        // javascript function to it when the user clicks.
        var myDropDown = dijit.byId("myDropDownId");
        dojo.connect(myDropDown, "onClick", function() {
            // do something when you click the button
        });
    
    });
    To get an ajax call to fire on load, it's actually quite easy:

    Code:
    dojo.addOnLoad(function() {
       dojo.xhrGet({
          url: "ajaxUrlhere",
          handleAs: "json",
          load: function() {
               // this is where you call whatever Dojo APIs you 
               // need to on your widget
          },
          error: function(e) {
              console.log("Ajax call failed", e);
          }
    });
    If you're new to Javascript, hit up Crockford's Javascript, the Good Parts. That will explain things like the function() { } syntax everywhere...

    You can see all of the available dojo widgets by heading over to http://dojotoolkit.org/reference-gui...ml#dijit-index and browsing around. The user documentation for the Dojo widget (they call them 'dijits' FilteringSelect, which is what the form:select tag installs, is avilable at http://dojotoolkit.org/reference-gui...ilteringselect. There is an example using a JSON datastore and it feeds data from http://dojotoolkit.org/reference-gui...ta/states.json - this gives you an idea of how the Dojo widget expects the data to be formatted.

    I'll give you an even easier way to try experiment with Dojo quickly - installing the page parser and lets you decorate the HTML on the fly. Here's what you do. At the top of your page, (inside of the outer tag such as form:list or whatever) install dojo parsing like this:

    Code:
    <script type="text/javascript">
      // dojo is modular, it expects things to only be loaded when asked for
      dojo.require("dojo.parser");
      // why this?  we'll see in a second...
      dojo.require("dijit.form.FilteringSelect");
      // now install parsing
      dojo.addOnLoad(function(){ 
         dojo.parser.parse();
      }
    </script>
    Now, you can add Dojo attributes to any field like this:
    Code:
      <select dojoType="dijit.form.FilteringSelect" hasDownArrow="true"/>
    (Note how you have that dojo.require statement in the top of the prior script, one for dojo.parser and one for the dijit.form.FilteringSelect - you need to install each form widget that you use. That's what the Spring.addDecoration tag does automatically, but I actually find using the page parser to be easier to read and understand.)

    The thing you'll get caught up in with the Roo scaffold is that you are using Roo's form tags (which, in reality, actually wrap Spring MVC's form tags and that confuses new Spring MVC people when they look at a Roo application).

    As I said above, spend a few hours digging through the tag libs, and if you want to do Ajax, you can use the Spring.addDecoration tags, Dojo's API itself, or the Dojo page parser - something I get into in a lot of detail in chapter 6, but since we don't have many examples on the forum, I wanted to dump a little getting started information for you.

    Final note - if you want to install jQuery and do that instead, go ahead - you can still use the Spring MVC @ResponseBody tag and the @RooJson annotation. However, since Dojo is so embedded within Roo, and all of the widgets are styled using Dojo (specifically the Dojo tundra theme), the jQuery widgets may look out of place alongside of a Dojo widget until you do some CSS magic.

    You may not even need the form: stuff, especially if these are filters that each trigger each other, and are just artifacts for helping you search.

    Originally posted by cblicious View Post
    Hello,

    I am very new to Spring Roo and also new to Spring MVC ....

    So I have the following problem:

    I need a filterable list which has several filteroptions, like lets say a product finder while browsing the page.

    I want this list to be updated dynamically.

    My approach was to write a JSON based Spring controller (using the @RequestBody annotation and the ContentNegotiatingViewResolver) with all the finders I need and then using DOJO and normal HTML Inputelements to create this list. Is this the "Roo/Spring" way, or is there any component library where I should choose and extend an existing list (like a taglib or something)

    Help would be really appreciated !
    Last edited by krimple; Feb 13th, 2011, 06:16 AM. Reason: Explanation of why I go into detail about Dojo - missed OP comment on Dojo

    Comment


    • #3
      thank you very very much for this great post !

      Comment


      • #4
        @jQuery ... I tried this first, but at the moment I am really giving Dojo a try ...

        Comment


        • #5
          ExtJS

          Ken, For my purposes ExtJS seems more appropriate, even as Dojo is part of Roo. Timeconstraint reasons mostly. 75% of my time with Roo goes into figuring out what Roo have done, why and how to get what I want. Even so its way faster and likely working better than without, but the Spring parts are enough to learn for me now. Dojo can wait.

          Using ExtJS would work similarly to JQuery?

          Comment


          • #6
            MiB,

            Hey there! Yeah, I know. I don't know ExtJS, but my same comment holds at the moment. Since Roo was built using Dojo at the tag library level, right now Dojo holds the most direct visual integration - all of the client side validation, the panels, the widgets for text areas, etc, are written in Dojo.

            I am pretty sure you could sit down and figure out how to use the CSS to make the Tundra theme stylings work with ExtJS widgets. That's far more complicated for me than just using Dojo - once you get the hang of it, there are dozens of controls, and it does make some good sense how they organize it. Everything is modular, but they vet the controls so generally they seem to work pretty well together.

            IMO that's different than jQuery, where you have a huge plugin community but every plugin is its own world, with potentially different licenses, developers, support modes, etc... I'm not complaining, either one has its good points.

            I also would consider this analogy, from my somewhat limited view: jQuery is to Ruby as Dojo is to Java - Dojo is more formal and drawn out, jQuery is more terse and wicked powerful in just a line or two of code. Both can get the job done. Maybe a bad analogy but basically holds.

            I'd love to see a Roo 1.2 tackle a pluggable widget library system. It would be fantastic if we could just say

            Code:
              <roo:select .../>
            and then have something like a configuration parameter where we could say something like
            Code:
              roo.ui.ajaxtoolkit=ExtJS|jQuery|Dojo etc
            That would be pretty darn useful. Right now I think it's a matter of resources and priorities. But I think long term the best way forward is to pull things out of the core of Roo that should be changeable. And you could make each of those toolkits specific add-ons, so that if they are registered somehow they could be used.

            Anyway, just a thought. Back to coding my webflow chapter example...

            Comment


            • #7
              Just another small Question,

              if i want to use the integrated Dojo in Roo , how do i turn on "parseOnLoad" on order to add HTML/Dojo parts like this ?

              Code:
              	<span dojoType="dojo.data.ItemFileWriteStore" 
              		jsId="jsonStore" url="../../../dijit/tests/_data/countries.json">
              	</span>
              	<div class="heading">Grid Test</div>
              
              	<table dojoType="dojox.grid.DataGrid"
              		jsid="grid" id="grid" class="grid" autoHeight="15" noDataMessage="Sorry, there is no data available."
              		store="jsonStore" query="{ name: '*' }" rowsPerPage="20" rowSelector="20px">
              		<thead>
              			<tr>
              				<th field="name" width="300px">Country/Continent Name</th>
              				<th field="type" width="auto">Type</th>
              			</tr>
              		</thead>
              	</table>

              Comment


              • #8
                You need to call dojo.parser.parse() - and to do this, you need to call it when the page loads. There is a addOnLoad method that gets called on startup (before the page renders) similar to the jQuery document.ready function. Just do this (let's say you're using a button and an enhanced grid):

                Code:
                <script type="text/javascript">
                        dojo.require("dojo.parser");
                        dojo.require("dojox.grid.EnhancedGrid");
                        dojo.require("dijit.form.Button");
                        dojo.addOnLoad(function() {
                            dojo.parser.parse();
                        }
                </script>
                
                <div id="addButton" dojoType="dijit.form.Button">Submit</div>
                <div id="grid" dojoType="dojox.grid.EnhancedGrid"
                    structure="...."
                />
                Put any attributes in as additional parameters to the div.

                I really don't want to plug my book, but I go into pretty deep detail in Roo in Action (MEAP) on using Spring w/Dojo so I refer you there for more depth around dijits, ajax interactions and such. If you want an existing book that covers this stuff, see Mastering Dojo - it's a very good guide. I referred to the dojotoolkit.org site w/the reference guide (which has a great amount of examples), FireBug, and that book while working on my chapter 6.

                Ken
                Last edited by krimple; Feb 14th, 2011, 09:45 AM.

                Comment


                • #9
                  Thanks I just overread it in the post above sorry ... When will the book be ready ? I am going to buy it for the company ...

                  Comment


                  • #10
                    oky ... last question ...

                    I wrote my own JSON controller , which has got a lot of finders ...

                    Now I am going to display the data with pagination etc in a dojo.datagrid, which is also working quite nice.

                    Now it happens that i want to have additional Queryparameters which can be modified through select boxes. Updating the query through javascirpt isn't a problem either ...

                    But ... the selectboxes are ...

                    Some of those are filled with values coming from the Controller / Model others are just Inputrields where the user can enter a random searchparameter...

                    At first i tried the <field:select > tag from Spring Roo, but this was way to much hacking to acess the Value of the selected item through JavaScirpt it seems to Store the value in a hidden inputbox below. The "normal" Spring Selectboxes aren't accessable somehow ...

                    So do I have to write my own selectbox with inline Java in the JSP ?
                    like
                    out.print("<select .... ");
                    for ($items ...)
                    out.print <option>

                    or is there a better way to achieve this ?

                    Comment

                    Working...
                    X