4

I have a datatables form that's backed by a server-side Ajax data source (which uses a struts action in the backend to process the request, fetch the data and send a JSON response). The server-side operation needs to run in authenticated mode, i.e. there needs to be an active session.

What is the best way to handle session timeout errors in Datatables? At present it just shows a JSON formatting error, which is not the best option for the user. I do not want to go and change the datatables code for obvious reasons (compatibility, future maintainability etc). Is there a neat way of handling errors?

I was thinking along the lines of embedding error message in the JSON response but where is the best place to intercept it in the front-end flow?

EDIT: I presume the best place for doing such post processing would be in fnServerData, am I correct?

Ashkan Aryan
  • 3,504
  • 4
  • 30
  • 44

5 Answers5

3

Below technique worked for me ... I know it was too late to respond but hoping the code will help someone

1) Check if session is timed out in the controller (MVC) and return the status code which should be handled at the client side

if (!Request.IsAuthenticated)
{
    return new HttpStatusCodeResult((HttpStatusCode)302, "Authentication timeout");
}

2) At the client side use jQuery global ajax Error, which catches the errors from all the ajax calls. Check for the status code and redirect to your login page

$(document).ajaxError(function (event, jqxhr, settings, thrownError) {
   if (jqxhr.status === 302) {
      document.location.href = '/account/login';
   }
});

3) [Optional] Disable the warnings from data tables and check the errors in the console

/*disable datatable warnings*/
$.fn.dataTable.ext.errMode = 'none';

/*display warnings in the console*/
$tblDashboard.on('error.dt', function (e, settings, techNote, message) {
      console.log('An error has been reported by DataTables: ', message);
});
3

I would fire back a JSON response containing some sort of error code. To process it, you need to define fnServerData as you have surmised. However, I would strongly consider the use case before using the error callback for this reason:

Error is simply any problem fetching the resource, and uses status codes. Let's say the session is terminated on the server. User requests the data, the server sends back a 500 error. Error callback says, "Well, that sucked. Let's redirect to a login page." Everything works great.

However... the user makes a request. The request is taking a little bit of time for whatever reason (large data set, network conditions). In the meantime, the user decides to navigate to another page, interrupting the call-response loop. With no response, the error callback is tripped and the user is redirected to a login page (or whatever function is set in the error callback).

The problem is that there's no status code that I'm aware of (I'd love to know, though! I don't mind being wrong here!) for 'session has expired' in order to capture and process.

I'm not saying you "shouldn't" or "can't" use the error callback. But the function has to take into account errors other than the session expiring. You might need to get into processing differently based on status codes. If your function handles all those cases elegantly, great! In one application, we are indeed redirecting to login page, and the error callback would often trip due to a false positive, dumping the user incorrectly to the login page. For the case of "session expired" we are catching it in the success callback via a JSON message.

[updated after Dave's excellent comments: ] If you have your server return a useful server error (401, 403, 550 or whatever makes sense in your scenario) then using fnServerData with statusCode parameter in the .ajax() call (that's a mouthful!) would work just as well. I think it's the same amount of work: return JSON via a method you've already written, or return status error via methods you should already have access to. Choose which one makes sense for you.

Greg Pettit
  • 10,749
  • 5
  • 53
  • 72
  • just discovered the statusCode parameter in .ajax, which may help with that side of things. I would still use the success handler for expired sessions, and statusCode or error for other problems. – Greg Pettit Oct 05 '11 at 19:20
  • 3
    If the user navigates away from the page the Ajax request would go away and no callback will fire, no? Whether the server sends back a successy or errory HTTP code is a matter of preference and domain. IMO requests that require a session but don't have one should return a "forbidden" code, since it's the truth. – Dave Newton Oct 05 '11 at 20:32
  • You would think. I'm not sure what magic is involved, but the callback indeed fires if you navigate away in the middle of a request. A forbidden code is a good idea, though. Handling it with statusCode parameter would be easy, too. If your application doesn't need to distinguish between session expiry and other forbidden states, I'm leaning towards that as a better solution. – Greg Pettit Oct 05 '11 at 20:59
  • My fault, I use beforeUnloads as per http://stackoverflow.com/questions/1906023/jquery-ajaxerror-handler-fires-if-user-leaves-page-before-page-finishes-loading and haven't really thought about it in a long time; now I feel silly :) – Dave Newton Oct 05 '11 at 21:05
  • Thanks gentlmen, that's what I ended up doing exactly: return a well formed JSON back when session times out on the server side with an error message in it, parsing it on the fnServeData on the client side – Ashkan Aryan Oct 07 '11 at 09:32
  • @AshkanAryan - is it possible for you to give that code or what exactly we can write JS code o solve this issue. Thanks. – Rahul J. Rane Mar 21 '18 at 07:26
1

Even though it has been a long time since this question has been asked i'm going to post my solution if just in case anybody needs it.

This solution applies to version 1.10.16 of JQuery Datatables.

After a bit of digging arround I found the function that shows the alert when the session expires. Here it is:

/**
     * Log an error message
     *  @param {object} settings dataTables settings object
     *  @param {int} level log error messages, or display them to the user
     *  @param {string} msg error message
     *  @param {int} tn Technical note id to get more information about the error.
     *  @memberof DataTable#oApi
     */
    function _fnLog( settings, level, msg, tn )
    {
        msg = 'DataTables warning: '+
            (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;

        if ( tn ) {
            msg += '. For more information about this error, please see '+
            'http://datatables.net/tn/'+tn;
        }

        if ( ! level  ) {
            // Backwards compatibility pre 1.10
            var ext = DataTable.ext;
            var type = ext.sErrMode || ext.errMode;

            if ( settings ) {
                _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
            }

            if ( type == 'alert' ) {
                alert( msg );
            }
            else if ( type == 'throw' ) {
                throw new Error(msg);
            }
            else if ( typeof type == 'function' ) {
                type( settings, tn, msg );
            }
        }
        else if ( window.console && console.log ) {
            console.log( msg );
        }
    }

As you can see there is a check on the type variable to see if it's a function. If it is it gets invoked. Note that the type variable is obtained like this:

var type = ext.sErrMode || ext.errMode;

So i did this:

//Check the message and redirect
  $.fn.dataTable.ext.errMode = function (settings, tn, msg) {
    if (msg.indexOf("YourErrorCode") != -1) {
      window.location = "/login";
    }
  }

Just replace YourErrorCode with want you need and it will work. I'll admit it's not the cleanest code ever but it works.

Peter Catalin
  • 1,342
  • 1
  • 14
  • 22
0

I have done it using the answer from bill martino here: http://datatables.net/forums/discussion/4377/catch-text-returned-from-server-side-ajax-call

"fnServerData": function ( sSource, aoData, fnCallback ) {
    // get filter ID
    var filter_id = $('#storedFilter_id').val();
    // send filter ID
    aoData.push(
        { "name": "filter_id", "value": $.trim(filter_id) }
    );
    $.getJSON( sSource, aoData, function (json) {
        // check for expired session being returned, if so, send the user back to the login page
        if(json.error == 'expired'){
            document.location.href='index.cfm?fuseaction=login.form';    
        }
        else{
            fnCallback(json)
        }

     });
}

On the Ajax Source response you should return a Json string like this:

{"error": "expired"}
blackbishop
  • 30,945
  • 11
  • 55
  • 76
0

1.Using this code in your getting ajax error page. or also used footer file.this code working for at session timeout after redirect to login page not getting ajax error.

$(document).ajaxError(function(event, jqxhr, settings, exception) {

if (exception == 'Unauthorized') {
    // Prompt user if they'd like to be redirected to the login page
    window.location = '<?=route("admin.login")?>';

    }
});
function CheckSession() {
    var session = '<%=Session["name"] != null%>';
    //session = '<%=Session["username"]%>';
    if (session == false) {
        window.location = '<?=route("admin.login")?>';
    }
}

setInterval(CheckSession(),500);

2.click on button called to function at time getting error..put the one line in function

 $.fn.dataTable.ext.errMode = 'none';

like one example

function ChangeUrl(){
        $.fn.dataTable.ext.errMode = 'none';
        product_table.fnStandingRedraw();
    }