views:

18

answers:

2

I've got a jqgrid (version 3.5.3) on my site which gets its results from an ajax call to a web service. Often the query is complicated and it takes a few seconds to load the result. While it is loading the user sees a box [Loading...].

In case the users realise they're searching for the wrong thing, the client has asked to add a cancel button to the grid, which would:

  1. make the grid forget about the data it's just requested
  2. retain the results already loaded from the previous search

There doesn't seem to be anything built in for this, so I'm probably looking for a bit of a hack to achieve this.

Any ideas?

+1  A: 

In general $.ajax request returns XMLHttpRequest object having abort method. So if the corresponding call of the $.ajax would be have the form

var lastXhr = $.ajax ({
    // parameters
    success:function(data,st) {
       // do something
       lastXhr = null;
    },
    error:function(xhr,st,err){
        // do something
       lastXhr = null;
    }
});

and we would have access to the lastXhr valuable then we could be able to call lastXhr.abort(). I think that a new method like abortAjaxRequest in jqGrid can be the best solution.

Without changing of the current source code of jqGrid the solution could looks like following

var lastXhr;
var stopAjaxRequest(myGrid) {
    $('#cancel').attr('disabled', true);  // disable "Cancel" button
    lastXhr = null;
    myGrid[0].endReq();
};
var grid = $("#list");
grid.jqGrid ({
    // all standard options
    loadComplete() {
        stopAjaxRequest(grid);
    },
    loadError() {
        stopAjaxRequest(grid);
    },
    loadBeforeSend (xhr) {
        l$('#cancel').attr('disabled', false); // enable "Cancel" button
        lastXhr = xhr;
    }
});

$("#cancel").click(function() {
    if (lastXhr) {
        lastXhr.abort();
    }
});

In the code I suppose, that we have a "Cancel" button with the id="cancel" outside of jqGrid. I should mention, that I don't yet tested the code above, but I hope it should work.

You should understand, of cause, that the code above aborts only the waiting of the browser on the client side and the process on the server will be continued. If your server will be implement the server side aborting, then the code above will be not needed and you will be able to call this server aborting method directly.

Oleg
Thanks for the comprehensive answer! We ended up implementing something similar, I'll probably post that when we've tidied it up
Jonny Cundall
A: 

Here's our solution, which is very similar to Oleg's, the main difference is that we keep track of a list of XHRs to make sure we clean all requests up

var handlerUrl = '';

jQuery(document).ready(function() {
    var xhrList = [];

    var beforeSendHandler = function() {

        var cancelPendingRequests = function() {
            jQuery.each(xhrList, function() { this.abort(); });
            xhrList = [];
            return false;
        };

        var hideLoadingUI = function() {
            $(this).hide();
            $("#load_list").hide();
        };

        cancelPendingRequests();

        $("#load_list").show();

// some faffing around to ensure we only show one cancel button at a time
        if (jQuery("#cancelrequest").length == 0) {
            jQuery(".ui-jqgrid-titlebar").append(jQuery("<button   id='cancelrequest'>Cancel</button>").click(cancelPendingRequests).click(hideLoadingUI));
        } else {
            jQuery("#cancelrequest").show();
        };  
    }


    jQuery("#list").jqGrid({
        datatype: function(postdata) {

            GetSearchCriteria(); //needed for the grid's filtering

            var xhr = $.ajax({
                //we override the beforeSend so we can get at the XHRs, but this means we have to implement the default behaviour, like showing the loading message ourselves
                beforeSend: beforeSendHandler,
                dataType: "xml",
                data: postdata,
                success: function(xmlDoc) {
                    //
                    jQuery("#cancelrequest").hide();
                    $("#load_list").hide();
                    jQuery("#list")[0].addXmlData(xmlDoc);
                    xhrList = [];
                }

...

Jonny Cundall