Scaffolding with Dojo Grid (and Grails)

Posted by: Pratik Patel on 07/14/2008

I've been (very) slowly hacking away at new-and-improved Dojo plugin for Grails. I've found that Dojo, not Grails, has been my bottleneck - primarily because I'm not a Javascript wizard. I might break down and buy one of the 3 new Dojo books that hit the shelves in the last month (note to publisher: if you want a nice review written up, send me the ebook  :) )

Dojo Grid JSON Scaffold

I took a try at creating a completely dynamic Dojo grid scaffold: tell it where to find your JSON, and it will just create a grid based on what's in the JSON. It's obviously not gonna be pretty, but for quick-n-dirty grids, it works pretty good. I've found it's a nice way to throw into a Dojo grid any data contained in a server-side list object. You have to convert it to JSON, but the Grails JSONBuilder makes that pretty easy.

JSON

{"items":[
{"id":1,"class":"Book","author":"Dierk Koenig","price":35,"title":"Groovy in Action"},
{"id":2,"class":"Book","author":"Graeme Rocher","price":25,"title":"The Definition Guide to Grails"},
{"id":3,"class":"Book","author":"Gavin King, Christian Bauer","price":35,"title":"Java Persistence with Hibernate"}
]}

Note that the Dojo ItemFileReadStore requires that the JSON be in an "items" collection.

Grails JSONBuilder

import grails.converters.JSON
...
def listJSON = {
        if (!params.max) params.max = 10
        def json = [items:Book.list(params)]
        render json as JSON
    }

This is so easy using the Grails JSON converter it should be illegal. Again, note how the "items" collection was used to wrap the actual collection of Books.

The Dojo Javascript scaffold

I started with a post I found in the Dojo mail list but it didn't work, so I ended up re-writing it. Here's the Javascript to call the above listJSON server-side action:

    dojo.addOnLoad(go);

    function go() {

        var rowbar = {
            type: 'dojox.GridRowView', width: '20px'
        };

        var rows = {cells: [[
            { name: "dummy", field: "dummy" }
        ]]
        };

        var layout = [rowbar, rows];

        this.jsonStore = new dojo.data.ItemFileReadStore({url: '/dojodev/book/listJSON'});
        this.dataModel = new dojox.grid.data.DojoData(null, null, {store:this.jsonStore,query:"",clientSort:true});
        this.dataModel.findAdditionalFields = function(items, columns)
        {
            console.log("findAdditionalFields called");
            var item = items[0];
            console.debug("item", item);
            for (var j in item)
            {
                console.debug("j:", j);
                if (j != '__id' && j[0] != '_' && j != 'class')
                {
                    columns.push({name: j, field:j, width:'auto'});
                }
            }

            // we want to keep the rowbar so just change the rows, i.e. layout[1]
            layout[1].cells[0] = columns;
            grid.setStructure(layout);
        }

        this.dataModel.processRows = function(items, request)
        {
            console.log("processRows called");
            columns = [];
            this.findAdditionalFields(items, columns);
            // do the default behavior now
            return dojox.grid.data.DojoData.prototype.processRows.apply(this, arguments);
        }

        dojo.connect(this.jsonStore, "onSet", null, function(item, attr)
        {
            console.log("onSet called");
            // check to see if we have a new property, might need to redo the columns
            for (var i = 0; i < columns.length; i++)
            {
                if (columns[i].field == attr)
                {
                    return;
                }
            }
            this.dataModel.findAdditionalFields([item], columns);
        });


        var gridProps =
        {
            model: this.dataModel,
            structure: layout
        };
        var grid = new dojox.grid.Grid(gridProps, dojo.byId("griddiv"));
        grid.setStructure(layout);
        grid.refresh();
    }

 Couple of things to note here. You'll need a empty div with id = "griddiv" and it only handles non-nested data.

Improvements welcome

I only dabble in Javascript, so leave a comment on how to improve this if you like. Standard disclaimers to the code apply.

 

 

 

 


  • Currently 4.0/5
  • 1
  • 2
  • 3
  • 4
  • 5
4.0 rating out of 2 votes


About Pratik Patel

Pratik Patel wrote the first book on 'enterprise Java' in 1996, "Java Database Programming with JDBC." He has also spoken at various conferences such as the Net Database Summit, WWW7 and the Atlanta Java User's Group (AJUG).

Pratik's specialty is in large-scale Java applications for mission-critical use. He has designed and built enterprise applications in the retail, health care, financial services, and telecoms sectors. Pratik holds a master's in Biomedical Engineering from UNC, has worked in places such as New York, London, and Hong Kong, and currently lives in Atlanta, GA.