Tag Archives: extjs

A Note on Helpers

In my previous post on Spring and ExtJS, you might have noticed the usage of a class called ExtData in the methods of the ContactController. I didn’t explain it at the time, but want to clarify what it is and why I created it.

There is a lot of boilerplate code involved in sending a response back to a request from ExtJS. You’re always going to return a Map, which has a success property, and possibly data, total and message properties. A typical response would look like this:

This gets annoying after you’ve done it a couple dozen times in the same application, so like every good (lazy) programmer, I implemented a simple class to deal with this. Take a look at the ExtResponse and ExtData classes in the org.sporcic.extjs package.

ExtResponse is the base class that simply deals with the success and message properties. The message property is only serialized if if is not null, thanks to this Jackson JSON attribute:

The ExtData class extends this class and knows how to deal with the data and total properties. It provides a simple method to add data to an internal list and correctly calculate the total property. This simplifies the controller methods to look like this:

Technically, I only removed one like of code from the previous example, but using the ExtData abstraction makes the code easier to read and eliminates tracking down a hard-to-find error in case you mis-type the name of one of the properties.

More ExtJS and Spring

It has been a while since I wrote my previous post which outlined a sample application using ExtJS and Spring. Since then, we’ve seen a new major version of both frameworks released, with ExtJS up to v3.3 and Spring sitting at 3.0.5.

ExtJS added a lot of cool features on the path to 3.3, but the most significant amount of cool stuff happened with the release of Spring 3.0. This release of Spring made it significantly easier to use JSON and REST, which eliminated a lot of the hackery that I had to do in my template with Spring 2.5.

I’ve been working on an updated version of my template, which makes use of all these new features, and decided to present it as a work-in-progress. The first part I want to talk about is how to get an Ext.data.JsonStore talking to a Spring MVC controller for CRUD operations. Loiane Groner wrote a pretty nice post on getting this wired in with an EditGrid, but it missed some of the real coolness with Spring 3.0.

I’ve pushed my sample application to GitHub to make it easier to get the big picture. The sample is a very simple webapp which uses a single domain object called Contact. The full project includes the Maven POM file along with a whole project which uses an HSQLDB with a full MVC stack in Spring. I’m going to ignore everything below the controller for this tutorial, but you can check out the rest in the full project.

Let’s start simple by demonstrating the GET operation, which will retrieve a list of all the contacts we have in our repository. Here is the application snippet from ContactController. Note, I’m using images so I can easily highlight sections. You can grab the raw source from the GitHub link above.

So the easy stuff first. I’ve annotated the ContactsController class with the @Controller stereotype from Spring to enable auto discovery. The @RequestMapping attribute says that this controller with catch all requests for ‘/contacts’. The getContacts() method is setup to catch any HTTP GET request, thanks the @RequestMapping annotation on the method itself. Finally, the real magic happens with the @ResponseBody annotation on the method return value.

@ResponseBody tells Spring it should not try to find a view and should just encode whatever object you are returning and send it back to the browser. Since we’re going to make an XMLHttpRequest from the browser, Spring will automagically encode the response in JSON format. The only caveat is that the Jackson JSON processer must be on the classpath, which my Maven POM file takes care of.

On the client side, the App.js file defines the Ext.data.Record, Ext.data.Reader, Ext.data.Proxy and Ext.data.Store. For simple applications, it is usually overkill to declare them like this, but I’m explicitly defining them to show how they will integrate with the Writer for updates.

For the Proxy, I’m setting restful to true, which means it will use the HTTP verbs GET, POST, PUT and DELETE for the CRUD operations. The url is set to send all those to the our controller above.

To make things interesting, I include a date field in the definition of the Record. This is used to show off one of the cool features of Jackson JSON and how it handles serialization.

Finally, I create the Store with the Proxy and Reader. I set autoSave to false, so I can manually force saves and loads from the console in Chrome.

In the current state, I haven’t wired in any widgets, so I’ll use the console to exercise the store. If you run the WAR file after generating it with Maven (mvn package), you can open up the JavaScript console in Chrome when you’re on the main page. Here’s how the store is loaded:

After executing the load() method of the store, you can see it loaded 10 items. If you enabled resource tracking, you can see the actual request looked like this:

The response is a JSON string that looks like
{"data":[{"id":10,"firstName":"Robert","lastName":"Bluegill","dob":"1975-06-04"},{"id":9,"firstName":"Lavern","lastName":"Knuckles","dob":"1980-12-16"},{"id":8,"firstName":"Kim","lastName":"Lavendar","dob":"1971-05-22"},{"id":7,"firstName":"John","lastName":"Cogsley","dob":"1965-10-15"},{"id":6,"firstName":"Larry","lastName":"Grissom","dob":"1983-04-01"},{"id":5,"firstName":"Larry","lastName":"Stewart","dob":"1981-08-08"},{"id":4,"firstName":"Jill","lastName":"Angel","dob":"1977-02-20"},{"id":3,"firstName":"Brandon","lastName":"Smythe","dob":"1968-11-10"},{"id":2,"firstName":"Susan","lastName":"Smith","dob":"1976-04-13"},{"id":1,"firstName":"John","lastName":"Smith","dob":"1984-07-03"}],"total":10,"success":true}

This is the typical response an Ext.data.Reader is looking for. Notice that the dates are correctly formatted as YYYY-MM-DD. This is handled via a custom attribute on the Contact domain object:

The method itself returns a Date. Without the @JsonSerialize attribute, this property would be serialized in the JSON response by calling its toString() method, which is not a desirable outcome. The ExtDateSerializer class does custom serialization of the Date object to convert it to a String using a DateFormat. The @JsonProperty annotation configures what name the property should have when serialized to a JSON object. Without this annotation, the property would have the name birthDate. I’m overriding that, specifying it should be called dob when serialized.

Now lets try to go the other direction and write (POST) a new Record from our Ext.data.Store to the ContactsController. Here is the (incorrect) Writer. We’ll get to that “incorrect” part in a minute, but first the easy stuff:

You must set encode to false, or else the Writer will try to send the payload as HTTP form data, not JSON. The error you get looks like this if you don’t set encode to false:

Note the HTTP error code is 415. Every other error you get will be a 500. It is only if you don’t set encode to false that you’ll get a 415.

Next we set writeAllFields to true. If you don’t do this, only the properties that have changed for a Record will be transmitted. We want everything server side for deserialization, so this ensures the whole object shows up at the server.

Finally, I set listful to true. This is hugely important for getting JSON deserialization to work correctly in the controller. This option says to wrap all updates inside a JSON array, even if there is only a single Record being sent. Since you can’t overload controller methods in Spring MVC controllers, we need to be able to catch both single and multi-record updates with a single method. Setting the writer to listful ensures that happens.

The controller method catching our new Record looks likes this:

The @RequestMapping annotation says that this method will catch all POST requests to the /contacts URL. The @RequestBody is new in Spring 3 and is the incoming analog to @ResponseBody. It basically tells Spring to attempt to deserialize the incoming payload into a Java object, in this case an array of Contacts. The deserialization is determined by the request headers. In this case, Spring will see it is JSON and will automagically use Jackson JSON to try and deserialize the payload to the correct object type.

Note that I return a list of Contact objects. ExtJS is expecting the return value to be a list of the same objects, post-save, with the id property set. It assumes these are in the same order that was sent, so do not shuffle the order around.

Setting listful to true in the Writer is what allows us to configure this method to accept an array of Contact objects. Even if there is only one Record coming from the Ext.data.Writer, it will be wrapped in a JSON array and deserialized into an array of Contact objects.

Now what about the birthdate property? Again, I use a Jackson JSON annotation to configure what field gets read (“dob” in this case), and how that field gets turned back in to a java.util.Date instance.

My ExtDateDeserializer class does the opposite of the ExtDateSerializer class. It uses a DateFormat to parse the string in the JSON property for dob back into a java.util.Date.

So lets try to create a new Contact and save it. Here’s the console output:

This is where we get to that “incorrect” thingy I mentioned above. The default Writer will attempt to serialize this save() request like this:

So the Writer is sending a JSON object, which contains a property called “data” which contains the array of new App.Contact records we recreated. The problem is that Spring and Jackson are looking for a simple JSON array that contains the new App.Contact records. So we need to customize the Writer to make this work right. Here is the custom Writer implementation:

I override the render method of the default Writer to directly output the JSON array of Records, and not put the wrapper object around it. Using this SpringWriter instead of the default Writer results in a payload like this:

Notice there is no longer the wrapper. When we run the console code again, we get a successful save:

So that covers reading the list of Contacts and adding a new Contact. Again, the code is available on GitHub so you can dig in to it. I’ll follow-up with another post on the PUT (update) and DELETE methods, along with wiring this in to some widgets.

Tuning Your ExtJS Theme

ExtJS is my favorite JavaScript favorite. The guys at Sencha have done an excellent job at building the best JavaScript framework for building intranet RIAs. The only flaw of ExtJS is the lack of themes. Although the provided blue and gray themes are very nice, after looking at them for two years you start to long for more variety.

There have been some attempts to theme ExtJS. Extthemes has built a pretty nice collection of commercial themes, but sometimes all I need is a little bling without the need to completely re-theme the framework. For example, on a recent project, I’m starting to introduce ExtJS and am making use of the Ext.Panel widget for laying out div elements.

Here’s what a basic Panel looks like in ExtJS:

ExtJS default panel

And here’s the code I used to create the panel:

var panel = new Ext.Panel({
      width: 200,
      height: 200,
      title: 'Test Panel',
      renderTo: 'box'
});

I’ve got a div specified in the HTML like this <div id="box"></div> which is where the Panel is being rendered to. This is very nice if your site’s look-and-feel is baby blue, but this won’t cut it if you need a different color scheme. Fortunately, Panels are extremely easy to stylize through some simple CSS overrides.

The first step is to decide what color you need for the Panel’s header. The default theme uses a gradient image, which looks better than just specifying a background color. Gradients are pretty easy to created in Photoshop, but you can get a very nice gradient that exactly matches your needs by taking advantage of the Themeroller tool for JQuery UI. Use the Header/Toolbar customization and choose the color and gradient effect you want for the header.

After you have the header just the way you want it, download the whole theme bundle, extract it someplace and copy the image file for the header into your project directory.

There are three CSS selectors you need to override to apply your customization to the Panel. They are .x-panel-header, .xpanel-header-text and .x-panel-body. For my example, I just borrowed the header image for the Eggplant theme and configured these selectors to produce the following:

ExtJS styled panel

Here is what I specified in my CSS file to override the default style:

.x-panel-header {
  background: url(resources/images/eggplant.png) center left repeat-x;
  text-align: center;
  border-color: #000;
}
 
.x-panel-body {
  border-color: #000;
  background-color: #fafad2;
}
 
.x-panel-header-text {
  font: bold 14px Consolas, Arial, san-serif;
  color: #eee;
}

In the .x-panel-header selector, I specified the background to be the header image I got out of the Themeroller theme. For a little added bling, I changed the text alignment to center the text and set the border color to black. Note, I renamed the gradient image from the cryptic name Themeroller created to eggplant.png.

For the .x-panel-body selector, I set the border color to match the one I specified in the selector above. If you don’t do this, you’ll still have the default border around the center. I also specify a light-yellow background color for the contents of the Panel.

Finally, for the .x-panel-header-text section, I change the appearance of the font from the default blue text to a white text in a different font.

Now you have a panel which can perfectly match any color scheme you need to support and it gives you a simple way to introduce ExtJS without it standing out from what you are already doing. For example, on my project, I’m going to use a pair of Ext.Panel widgets on the sidebar for navigation and a most-recently-used files list, which looks something like this:

ExtJS custom panels

In this example, the theme is still blue, but I changed the header gradient, the shade of blue for the lines, and applied a light-gray background.

Some Tips

  1. Firebug or Webkit (Chrome/Safari) are your friends. Use the element inspectors to look at what classes are applied to the various ExtJS widgets. Theming ExtJS is all about overriding the existing styles.
  2. Panels are about the easiest thing to style, and it gets harder from there. If you really want to get a custom theme, I suggest start by working with the x-theme-gray.css and then overriding from there. The gray theme will give you widgets that blend pretty easily with any theme, and then you can selectively add some bling to the elements you care about.
  3. Remember that your overridden styles must come after the stylesheet link for ExtJS. For example, if your stylesheet with the overridden styles is called custom.css, ensure your header section contains this:
    <link rel="stylesheet" type="text/css" href="extjs/resources/css/ext-all.css"/>
    <link rel="stylesheet" type="text/css" href="extjs/resources/css/xtheme-gray.css"/>
    <link rel="stylesheet" type="text/css" href="stylesheets/custom.css"/>

(Ext.)Direct Miss

One of the biggest announcements from last month’s ExtJS Conference was the new Ext.Direct functionality in ExtJS 3.0. My criticism at the time was that there was a lot of smoke, but no fire. Almost every session mentioned it in some way or another, but they weren’t producing any enterprise-worthy server code showing how it is implemented.

Now, a month later, more details are starting to emerge, including implementations for various technologies. I sat down yesterday morning intending to take a look at the server side code in the Ext.Direct Pack; in particular the .NET and Java implementations. I was pretty disappointed with what I saw.

To understand my disappointment, you need to understand a bit of history around what Ext.Direct is attempting to do. Ext.Direct is going to be an RPC layer that exposes stub objects on the client JavaScript side that remotes the method calls to the server using JSON (or POST parameters). The protocol definition is designed to be technology-agnostic and easy to implement. In implementation, it would be the near-equivalent of DWR, except it would also run on PHP, C#, Ruby, etc…

Since I’m familiar with CORBA, RMI, SOAP and WCF, I approached Ext.Direct with a more critical eye. The biggest glaring hole in Ext.Direct is the parameter passing. Let’s take a look at a couple examples to demonstrate the problem. All the examples will assume a Java backend, and the service we’ll expose is the PersonService. I’ll work from the interface, since we don’t care about the implementation details:

public interface PersonService {
 
}

Easy

We’ll add a method to PersonService to demonstrate the simplest scenario:

public int getPersonCount();

The payload from Ext.Direct would look something like this:

{ "action":"PersonService",
   "method":"getPersonCount",
   "data":[],
   "type":"rpc",
   "tid":2}

This is the absolute easiest method to deal with. The operation takes no parameters, and the return value is a primitive. Ext.Direct can deal with this easily, but so could any AJAX library, so no secret sauce here.

Object

One of the key advantages to an RPC protocol is the ability to pass Objects. Well complicate things a bit by adding the following method to the PersonService:

public Person getPerson(int id);

For our example, we’ll assume the Person class looks like this. I’m not including setters/getters to try and keep it short:

public class Person {
  private int id;
  private String name;
  private int age;
  private Date birthDate;
}

In the method I added above, the JSON payload from Ext.Direct stays pretty simple:

{ "action":"PersonService",
   "method":"getPerson",
   "data":[1],
   "type":"rpc",
   "tid":2}

This should return the Person with the ID of 1, and depends on the server code to correctly serialize the Person object to JSON.

Harder

Now let’s make things painful. I’m going to include a method to add a Person.

public void addPerson(Person person);

This is where the wheels fly off of Ext.Direct. Since the protocol specifies the data element as an array, I’m not clear on how Ext.Direct would deal with this from the client side. Every example so far works with primitives as parameters, so I haven’t determined what it would do with a Person.

Ext.Direct would be much happier if I defined the addPerson method like this:

public void addPerson(int id, String name,int age, Date birthdate);

Then, the JSON payload would look like this:

{ "action":"PersonService",
   "method":"addPerson",
   "data":[1,"John Doe", 25, "Sun May 01 1985 00:00:00 GMT-0500 (Central Daylight Time)"],
   "type":"rpc",
   "tid":3}

Even in this “happy path” scenario for dealing with an object, your server-side implementation would need to be able to correctly deserialize the stringified javascript date object, which is not anything the current implementations handle.

The protocol specification states that the data element can also be a JSON object with named parameters, but it is not supported in the first implementation. This is going to be absolutely critical if Ext.Direct is going to evolve into a real RPC protocol. For example, using a JSON object for the data element in the above example would result in a JSON payload like this:

{ "action":"PersonService",
   "method":"addPerson",
   "data": {id: 1,
           name: "John Doe", 
           age: 25, 
           birthdate: "Sun May 01 1985 00:00:00 GMT-0500 (Central Daylight Time)"},
   "type":"rpc",
   "tid":3}

This would at least allow the server code a means to try and instantiate an instance of the Person object, as long as the server code is implemented in a language that allows for reflection of the Object.

My grief with Ext.Direct is that correctly implementing the server-side code to support the specification is a non-trivial endeavor. One big piece missing is the metadata. In other RPC mechanisms, there is strongly-typed metadata which can be used to create the stubs. For example, CORBA has IDL and SOAP has WSDL.

Ext.Direct is missing a metadata layer to facilitate the passing of Object values. It is going to be difficult to implement a complete server-side stack to handle the permutations that will arise. Developers will either need to dumb-down the exposed services to handle the limitations of Ext.Direct, or else they will end up doing a lot of custom work on top of the server side implementation to handle the type coercion.

I’m still not convinced Ext.Direct is the right path for ExtJS to be barking down. There are already established, tested protocols for handling RPC via JavaScript (DRW, WCF), and ExtJS already works quite well with basic AJAX over the HTTP protocol. Ext.Direct is adding a level of complexity to ExtJS which could easily turn into a rabbit hole that sucks up all their time. I would prefer they focus their precious development hours on the client library and leave the communication layers decisions to us. RPC is a complicated problem with a lot of history around it, and there is no reason for them to try and invent a new wheel in this space.

Ext Conference, Day 3

The third day of Ext Conference 2009 was only a half-day, which turned out to be a good thing given the trainwreck start. They were an inexcusable 20 minutes late in opening the door for what should have been 15 minutes of closing remarks. Instead, it turned into a 30+ minute demo of the new UI designer. Yes, the designer is awesome and will rock the ext world, but it is beyond me why they would improvise a demo on the morning of the last day. This should have been either on day one or possibly part of Jack’s keynote on day two.

With events now running 45 minutes late, the final two sessions ended up being pretty disorganized. I went to the “Mainframe to Web” presentation by Rich. I had just done a similar project and was interested in what he had to say. Turns out their showcase pretty much faked an integration with the backend by using a screen scraper on the server side which translated terminal session screens to ExtJS metadata. They didn’t change any of the backend code at all. I’ll give them credit for finding a clever solution, but I’m not convinced it is the best one. When we confronted a similar problem, we ended up wrapping backend functionality in AS/400 stored procedures we called from the middle-tier.

The positive side effect of the wheels-off schedule was that Rich rushed his presentation to try and wrap up on time. The other presentation, ExtJS deployment, was only halfway done, so I jumped in to catch the last half of it. In this case, it seemed like the heart of the presentation was in the last half, so I basically got the best of both presentations.

The deployment presentation covered a lot of the useful tools for bundling up your JavaScript. I had heard of JS Builder before, but plan on taking a deeper look now. It can create a single JavaScript file from many smaller files. YUI Compressor is the recommended tool for really putting the squeeze on your JavaScript files, but even then, Jamie still recommended ensuring you use GZip/Deflate on the web server for JavaScript files. He also talked about a tool for creating a multi-image sprite file of several small images that can also have a big impact. I came away with a lot of things to research and this should be a top presentation to check out when they put them online.

The final session for the day was Scott covering the Ext.Writer. This has got to be one of the coolest features of ExtJS 3.0 and they really should have moved this earlier rather than waiting for the last minute. The Writer addresses the problem of handling CRUD operations for Stores. It can use REST-like URLs like /app/update/1 or /app/delete/1 with the record ID as the final parameter. It pushes a JSON object back to the server containing the information that needs to be acted on. It even addresses passing a primary key back to the Store on a create operation. This is looking a whole lot cooler than Ext.Direct and I want to give it a try for my application.

I didn’t sit through the final Q&A session as I needed to bugout for the airport. Based on the tweets so far, it doesn’t look like much was discussed. Overall, the conference was excellent and I can chalk up the final day to growing pains. What will be interesting to see is what happens in the coming weeks. Ext.Direct was talked up in about every session, but there is an incredible lack of detail for how it will be implemented with mainstream enterprise technologies (Java/C#). Abe talked about the Marketplace, which sounds like the equivalent of RubyForge for ExtJS. If they can get it up, it will be cool. Finally, the UI Designer is what everyone really wants but it is slated for v3.1, and no one would talk timelines for it.