Fusioncube

The online journey of a technophile, by Steve Brownlee

Sencha ExtJS: Expand/Collapse GroupView with Checkbox

  • Filed under: ExtJS
Monday
Dec 20,2010

Pretty straightforward example of expanding and collapsing all grouped rows by clicking on the Checkbox item.

See this code in action

// Sample JSON data for teammates, their department
// and compensation rate
var Teammates = [{
    tmID: 1, Teammate:'Steve', Department:'Safety', Compensation_Rate:'30', Date_Change:'01/01/1999'},{
    tmID: 2, Teammate:'Steve', Department:'IT', Compensation_Rate:'55', Date_Change:'05/07/2002'},{
    tmID: 3, Teammate:'John', Department:'Sales', Compensation_Rate:'50', Date_Change:'03/05/2000'},{
    tmID: 4, Teammate:'John', Department:'Executive', Compensation_Rate:'53', Date_Change:'05/10/2000'},{
    tmID: 5, Teammate:'Matthew', Department:'Welding', Compensation_Rate:'55', Date_Change:'12/17/2002'
}];

// Create a Checkbox that will toggle between
// expanding and collapsing the grid items
ExpandCollapseAll = new Ext.form.Checkbox({
    renderTo: Ext.getBody(),
    boxLabel: 'Expand Results',
    listeners: {
        check: function(ctrl, val) {
            if (val) {
                RateGrid.view.expandAllGroups();
            } else {
                RateGrid.view.collapseAllGroups();
            }
        }
    }
});

// A GridPanel using a GroupingView to display the data
// grouped by the teammate name
RateGrid = new Ext.grid.GridPanel({
   renderTo: Ext.getBody(),
   width:    400,
   style: 'margin: 10px 10px 10px 10px',
   height:   300,
   store:    new Ext.data.GroupingStore({
               data:   Teammates,
               reader: new Ext.data.JsonReader({ id: 'tmID' },
                  Ext.data.Record.create([
                     {name: 'tmID', type: 'string'},
                     {name: 'Teammate', type: 'string'},
                     {name: 'Department', type: 'string'},
                     {name: 'Compensation_Rate', type: 'string'},
                     {name: 'Date_Change', type: 'string'}
                  ])),
               groupField: 'Teammate',
               sortInfo: {field:'Date_Change', direction: 'ASC'}
   }),
   cm:       new Ext.grid.ColumnModel([
               {
                  id: 'Teammate',
                  dataIndex: 'Teammate',
                  hidden: true
               },{
                  id: 'Department',
                  header: 'Department',
                  dataIndex: 'Department',
                  width: 150
               },{
                  id: 'Compensation',
                  header: 'Rate',
                  dataIndex: 'Compensation_Rate',
                  width: 100
               },{
                  id: 'DateChange',
                  header: 'Date',
                  dataIndex: 'Date_Change',
                  width: 100
               }
   ]),
   autoScroll:  true,
   autoExpandColumn: 'Department',
   view:        new Ext.grid.GroupingView({
                  showGroupName: false,
                  hideGroupedColumn: true,
                  startCollapsed: true,
                  groupTextTpl:  '{text}'
   })
});

Getting rid of eval() for JSON parsing

Tuesday
Dec 7,2010

I wanted to finally get rid of any usage of the JavaScript eval() function when parsing JSON returned from my components.

I went to JSON.org and noticed that there’s an updated json2.js file that should replace my old json.js file as well as two separate parsing engine files on the GitHub site:

  • json_parse.js
  • json_parse_state.js

Once again, I customized.  I removed the existing JSON.parse() method from json2.js and replaced it with the function on json_parse_state.js, so all I need to do is

<script type="text/javascript" src="js/JSON.js"></script>

and the JSON.parse() method will now use the state engine code instead of eval().

Download custom JSON.js.

Tuesday
Dec 7,2010

I’ve been using the AjaxCFC library for years. It’s my preferred way of integrating Javascript and ColdFusion via AJAX. I’ve even modified it from its original form so that my implementation was strictly for integration with jQuery, only returns JSON strings (ignoring WDDX and simple string), and can work with ColdSpring.

Now that I’m a heavy user of the Sencha ExtJS framework, I thought it would be useful to port the jQuery.ajaxCFC.js file over to an Ext.AjaxCFC.js file that extended the native Ext.data.Connection class and utilized the Ext.Ajax object.

Took me about half the day, but I finally got a working Ext.AjaxCFC.request() method that uses the same syntax as the $.AjaxCFC() method. For those familiar with the inner workings and code of the jQuery AjaxCFC class, this will look very familiar.

So now I can make AJAX calls using native ExtJS classes, access ColdSpring beans in my application’s bean factory, or connect directly to any CFC

Ext.AjaxCFC.js

Ext.AjaxCFCConnection = Ext.extend(Ext.data.Connection, {
   data        : null,
   queryFormat : 'array',
   factory     : (typeof(__ajaxConfig) == 'undefined') ? null : __ajaxConfig.beanFactory,
   timeout     : (typeof(__ajaxConfig) == 'undefined') ? 30000 : __ajaxConfig.defaultTimeout,
   url         : __ajaxConfig.url,
   bean        : null,

   request : function(arguments) {
      var params = (typeof(arguments.data) == 'undefined') ? {} : arguments.data;
      arguments.params = {};
      arguments.params['C0-ID']         = (Math.floor(Math.random() * 10001) + "_" + new Date().getTime()).toString(),
      arguments.params['method']        = 'init';
      arguments.params['component']     = arguments.component;
      arguments.params['bean']          = (typeof(arguments.bean) == 'undefined') ? this.bean : arguments.bean;
      arguments.params['factory']       = this.factory;
      arguments.params['C0-METHODNAME'] = arguments.method;
      arguments.params['queryFormat']   = (typeof(arguments.queryFormat) == 'undefined') ? this.queryFormat : arguments.queryFormat;
      arguments.params['C0-PARAM0']     = params;

      arguments.url = this.url + '?method=' + arguments.params['method'];
      arguments.method = 'POST';
      arguments.failure = arguments.error;
      arguments.timeout = this.timeout;

      var ____success = arguments.success;

      arguments.success = function(data) {
         data = data.responseText.replace(/^\s*|\s*$/g, '');

         if (data.substring(0,9) == '__json__:') {
            data = Ext.util.JSON.decode(data.slice(9));
         }
         ____success(data, this);
      };

      if ( params ) {
         if (typeof params != 'string') {
            arguments.params['C0-PARAM0'] = Ext.util.JSON.encode(params);
         }
      }

      Ext.Ajax.request(arguments);
   }
});

Ext.AjaxCFC = new Ext.AjaxCFCConnection();

Usage

// Include Ext.AjaxCFC code
<script type="text/javascript" src="js/Ext.AjaxCFC.js"></script>

// Default configuration properties for the ajaxCFC library
__ajaxConfig = {
   'url':'/myApp/ajaxCFC/ajax.cfc',
   'defaultTimeout':30000,
   'beanFactory':'application.beanFactory'
};

// AjaxCFC call using Ext.data.Connection class
Ext.AjaxCFC.request({
   bean: 'AColdSpringBean',
   method: 'aMethod',
   data: {
      'id': 416198,
      'first_name': 'Steve',
      'last_name': 'Brownlee'
   },
   success: function(details, s){
      DataStore.loadData(details);
   },
   error: function(results){
      Ext.MessageBox.alert('Search Failed', 'An unexpected error occurred. Please try again.');
   }
});

Fixing the Worst Hack of my Career

Tuesday
Jul 20,2010

Several years ago, I designed and developed an application whose scope was far greater than the business folks imagined. Therefore, the timeline was far more compressed than I would have liked.

I cut a lot of corners in that project in order to get it out in time, but there was only one hack that has haunted me since I reluctantly pushed it into production: I returned a large HTML string from an AJAX call and inserted it directly into the DOM.

It was far easier, at the time, to simply loop through the highly complex query structures in my class and build the HTML structure there rather than build a JSON string and use a JavaScript parsing class to build the HTML on the browser.

Well, in a little twist of fate, there was an update scheduled for this application; and this time I had some extra time as the release date got pushed back a couple of weeks. Using that to my advantage, I finally was able to fine-tune that entire mechanism, including:

  • Passing a vastly more compressed JSON string back to the interaction layer.
  • Using a new HTMLRender class in JavaScript to parse the JSON, and then build and insert the HTML into the DOM.
  • Reduced the number of hits on the database by retrieving all information in one, massive query instead of dozens of smaller ones.
  • Increased the usage of Sencha ExtJS in the layout to make it more attractive.
  • All in all, this particular section of the application now executes about 70% faster, is less resource intensive on the database, and is easier to use.

    It’s a big monkey off my back. Not to mention that I always enjoy going back to code from previous projects and seeing how I can improve upon it since I’m always learning new tricks.

  • About Steve

    I am a technologist, and have been ever since 1980 when I got my very first TRS-80 and programmed it to do my math homework. I love to share the gift of technology with others and show them the wonderful things it can do for them, and how they should not fear it, but embrace it.

    Latest Tweets

    • Ok... stayed up way too late trying out website designs for my wife's new nonprofit. The kids will be getting me u... — http://t.co/QrKh5iBI
    • Am I the only one who likes Google’s new privacy policy? http://t.co/qwcym5wH
    • All that time wasted learning the .NET framework - Fusioncube - http://t.co/krANoWmg
    • @marcesher libraries like Less only do what you tell them. You can make a mixin to do that, but it doesn't assume anything (which is good)
    • Circus about to start. Girls are so excited they can't stand it!!!! (with Sabrina and Tessa at @BrdgstoneArena) [pic] — http://t.co/PXwi5emj

    Subscribe

    Entries (RSS)
    Comments (RSS)