Home > Programming > YUI Components with DWR – DWR DataSource

YUI Components with DWR – DWR DataSource

I’m working on project which uses YUI and DWR. The hardest part is intergrating these two. I googled on how people integrated YUI and DWR, found this and this. But these solutions will only work with earlier versions of YUI. I’m using YUI 2.7. So i ended up writing my own DWRDataSource. Might be useful for guys who want to integrate DWR and YUI 2.7.

Drawbacks :

  • This version unlike XHRDataSource does not support queuing and aborting the requests, as DWR has no support for aborting the requests.
  • No support to call java methods which has multiple arguments. Eg: You cannot invoke UserService.getUser(name, email).
YAHOO.namespace("javachap.util");
javachap = YAHOO.javachap;

var DS = YAHOO.util.DataSourceBase,
	lang = YAHOO.lang;

javachap.util.DWRDataSource = function(oLiveData, oConfigs) {
    this.dataType = DS.TYPE_XHR;
    oLiveData = oLiveData || "";

    javachap.util.DWRDataSource.superclass.constructor.call(this, oLiveData, oConfigs);
};

//DWRDataSource extends DataSourceBase
YAHOO.lang.extend(javachap.util.DWRDataSource, DS, {
	/**
	 * Overriding method passes query to Connection Manager. The returned
	 * response is then forwarded to the handleResponse function.
	 *
	 * @method makeConnection
	 * @param oRequest {Object} Request object.
	 * @param oCallback {Object} Callback object literal.
	 * @param oCaller {Object} (deprecated) Use oCallback.scope.
	 * @return {Number} Transaction ID.
	 */
	makeConnection : function(oRequest, oCallback, oCaller) {
	    var oRawResponse = null;
	    var tId = DS._nTransactionId++;
	    this.fireEvent("requestEvent", {tId:tId,request:oRequest,callback:oCallback,caller:oCaller});

	    // Set up the callback object and
	    var oSelf = this;

	    /**
	     * Define DWR success handler
	     *
	     * @method _dwrSuccess
	     * @param oResponse {Object} DWR Response
	     * @private
	     */
	    var _dwrSuccess = function(oResponse) {
	        // If response ID does not match last made request ID,
	        // silently fail and wait for the next response
	        if(oResponse && (this.connXhrMode == "ignoreStaleResponses") &&
	                (oResponse.tId != oQueue.conn.tId)) {
	            YAHOO.log("Ignored stale response", "warn", this.toString());
	            return null;
	        }
	        // Error if no response
	        else if(!oResponse) {
	        	oSelf.fireEvent("dataErrorEvent", {request:oRequest,
	                    callback:oCallback, caller:oCaller,
	                    message:DS.ERROR_DATANULL});
	            YAHOO.log(DS.ERROR_DATANULL, "error", this.toString());

	            // Send error response back to the caller with the error flag on
	            DS.issueCallback(oCallback, [oRequest, {error:true}], true, oCaller);

	            return null;
	        }
	        // Forward to handler
	        else {
	            //oSelf.responseType = DS.TYPE_JSARRAY;
	            // Try to sniff data type if it has not been defined
	            if(oSelf.responseType === DS.TYPE_UNKNOWN) {
	                if(YAHOO.lang.isArray(oResponse)) { // array
	                	oSelf.responseType = DS.TYPE_JSARRAY;
	                }
	                 // xml
	                else if(oResponse && oResponse.nodeType && oResponse.nodeType == 9) {
	                	oSelf.responseType = DS.TYPE_XML;
	                }
	                else if(oResponse && oRawResponse.nodeName && (oResponse.nodeName.toLowerCase() == "table")) { // table
	                	oSelf.responseType = DS.TYPE_HTMLTABLE;
	                }
	                else if(YAHOO.lang.isObject(oResponse)) { // json
	                	oSelf.responseType = DS.TYPE_JSON;
	                }
	                else if(YAHOO.lang.isString(oResponse)) { // text
	                	oSelf.responseType = DS.TYPE_TEXT;
	                }
	            }
	            oSelf.handleResponse(oRequest, oResponse, oCallback, oCaller, tId);
	        }
	    };

	    /**
	     * Define DWR failure handler
	     *
	     * @method _dwrFailure
	     * @param oResponse {Object} Exception object
	     * @private
	     */
	    var _dwrFailure = function(oResponse) {
	        this.fireEvent("dataErrorEvent", {request:oRequest,
	                callback:oCallback, caller:oCaller,
	                message:DS.ERROR_DATAINVALID});
	        YAHOO.log(DS.ERROR_DATAINVALID + ": " +
	                oResponse.statusText, "error", this.toString());

	        // Send failure response back to the caller with the error flag on
	        oResponse = oResponse || {};
	        oResponse.error = true;
	        DS.issueCallback(oCallback, [oRequest,oResponse], true, oCaller);

	        return null;
	    };

	    /**
	     * Define DWR call meta data
	     *
	     * @property _dwrCallMetaData
	     * @private
	     */
	     var _dwrCallMetaData = {
	    	callback:_dwrSuccess,
	        exceptionHandler:_dwrFailure,
	        scope: this
	    };

	    // Get ready to send the request URL
	    var dwrServiceMethod = this.liveData;
	    dwrServiceMethod.call(this, oRequest, _dwrCallMetaData)

	    return tId;
	}
});
YAHOO.lang.augmentObject(javachap.util.DWRDataSource, DS);

And configure YUI AutoComplete to use the DWRDatasource. Here Userservice.getUsers is the javascript function that you want to invoke to fetch the data from the server.

// Use an DWRDataSource
var oDS = new javachap.util.DWRDataSource(UserService.getUsers);

// Instantiate the AutoComplete
var oAC = new YAHOO.widget.AutoComplete(
    'userName', 'userNameContainer', oDS);
// we dont need '?query=sQuery', just return the sQuery instead.
oAC.generateRequest = function(sQuery) {
    return  sQuery;
};
Share and Enjoy:
  • Digg
  • DZone
  • del.icio.us
  • Yahoo! Buzz
  • Facebook
  • Google Bookmarks
  • Reddit
  • Live
  • Twitter
Categories: Programming Tags: , ,
  1. DLo
    January 12th, 2010 at 22:03 | #1

    Excellent YUI extension! Works fine on YUI 2.8.0.

    I have an addition for you, though…

    This implementation requires that your exposed DWR interface have exactly 1 parameter. If you’re using your DataSource for an AutoComplete, that’s a reasonable assumption. However, for something like a DataTable, you could conceivably have a no-parameter DWR interface that just spits out a JSON array. In this case, you’re basically calling:
    dwrServiceMethod(null, dwrCallMetaData).

    DWR gets confused by this. Because your exposed Java method is a zero-argument method, DWR expects to find its metadata in the first arguments in its generated javascript function. However, the first argument is null because of the way you’re calling it! The result is DWR can’t find a callback to call, nothing happens, and your DWRDataSource just sits there idly twidling its thumbs after the makeConnection call because DWR never calls it back. To fix this, replace lines 121-123 with something like:

    // Get ready to send the request URL
    var dwrServiceMethod = this.liveData;

    // If we never specified a request, call the no-parameter version of the exposed DWR interface.
    // Otherwise, assume the exposed DWR interface takes 1 parameter and pass it our request object.
    if (oRequest == null) {
    dwrServiceMethod.call(this, _dwrCallMetaData);
    } else {
    dwrServiceMethod.call(this, oRequest, _dwrCallMetaData);
    }

    Even more complicated, if you want to create a DWRDataSource that supports multiple-argument DWR interfaces, you could put your multiple arguments into your oRequest object and add code that unpacks your oRequest variable into multiple arguments in your dwrServiceMethod.call(…) line. The implementation of this is left as an exercise for the reader : )

    Thank you for this code snippet!

  1. July 17th, 2009 at 18:06 | #1

Spam protection by WP Captcha-Free