Friday, November 28, 2014

Concatinating values and return as single value column in MS SQL Server

For 1 to many relationship between 2 tables, you may want to return this result:

Person Name Gadgets
Amy LG, Samsung, Sony
Bea Blackberry, iPhone

select p.name as "Person Name", STUFF((                                         
 SELECT ',' gadget_name
 FROM gadget g              
 WHERE p.person_id = g.person_id               
 FOR XML PATH('')), 1, 1, '') as "Gadgets"
from person

Concatenation is done by the FOR XML PATH; whereas the STUFF is to simply remove the first comma (",").


Thursday, November 27, 2014

Globally disable sorting of Ext JS Grid when empty

This is specifically beneficial for stores that use remoteSort, as it will only conserve hitting the server when its empty, which potentially may trigger complex processing (such as search form validation or execute the sql query itself) even though it knows that it will return empty. You can disable this globally by overriding the Store's sort function like this, wherein you add a checking before calling the parent method (which will do its default behaviour):
Ext.define('Ext.overrides.data.Store', {
    override: 'Ext.data.Store',
    sort: function() {
        if (this.count() > 0) { //prevents from submitting a request, for remote sort
            this.callParent(arguments);
        }
    }    
});
This effectively prevents sorting across all your Grids that use a Store. No need to individually configure your Grid. Lastly, in relation to empty Stores and hitting the server, if you are using the Paging Toolbar, and your paging remotely, the Refresh button in that Toolbar by default will hit the server as well, hence do the same checking by overriding the doRefresh function:
Ext.define('Ext.overrides.toolbar.Paging', {
    override: 'Ext.toolbar.Paging',
    doRefresh: function() {
     var store = this.getStore();
        if (store && store.count() > 0) { //prevents from submitting a request, for remote refresh
            this.callParent(arguments);
        }
    }
});

Tuesday, November 25, 2014

Global exception handling Ajax calls in Ext JS

If your Ext JS web app primarily communicates with the backend via Ajax, then you need to handle server side exceptions for each of those Ajax calls. In my experience, doing this across all pages (it's not a single page application) is not an ideal solution, as it violates two (2) things:

  1. duplicates code 
  2. maintainance nightmare
The ideal solution is to have a global exception handler, where: 
  1. single location for all exception handling, 
  2. it acts as a catch-all
The solution I have here aims to globally:
  1. detect and inform user of Ajax operation timeout 
  2. handle Java session timeout when an Ajax call is executed on expired user session
  3. catch all Java exceptions from the backend
This is the code, put it in your common.js (or a similar file which you import in all your pages):
Ext.util.Observable.observe(Ext.data.Connection, {
    requestexception: function(conn, response, options) {
        if (response && response.request) {
            if (response.request.timedout) {
                Ext.Msg.show({
                    title: 'Operation Timeout',
                    msg: 'The operation did not complete due to a timeout.',
                    buttons: Ext.Msg.OK,
                    closable: false
                });

            } else {
                //then its a validation error or generic backend error 
                //this is my custom method, that parses the json response
                //and shows either: 
                //1. validation errors (ie. To Date must be before From Date)
                //2. runtime exceptions (generic system exceptions)
                showErrors(Ext.JSON.decode(response.responseText));
            }
        }
    },
    requestcomplete: function(conn, response, options, eOpts) {
        //using Spring Security, if user session expires,
        //it simply returns the login page
        if (response.responseText.indexOf('User') > -1 
            && response.responseText.indexOf('Password') > -1 
            && response.responseText.indexOf('Login') > -1) {
            window.location.href = 'login.htm';
        }
    }
});

This code registers a listener for the 2 events of the Ext.data.Connection:

  1. requestexception - non HTTP 200
  2. requestcomplete - HTTP 200
Ext.data.Connection is the underlying class used by the Ext JS classes such as Ext.data.Store, Ext.data.Model, Ext.Ajax, etc. Hence by registering this, any calls such as store.load() or model.save() which encounters backend error (non HTTP 200) or Ajax operation timeout or Java session timeout, will benefit from this global exception handling. 

Go Live Date

I created this blog with the intention of transferring what I've learned and gradually building up a knowledge base for Java, Ext JS primarily among other things.