Modifying the argument passed to jQuery done() callback following a successful AJAX call

StackOverflow https://stackoverflow.com/questions/23224330

Вопрос

Here's the scenario:

I need to fetch some JSON data via AJAX from the server (ASP.NET MVC application + ServiceStack services). If the user's session expires then instead of getting back JSON I get a redirect to the login page, which gets automatically executed by jQuery, so the result of the AJAX call ends up being the raw HTML of the login form. I need to handle these two cases differently:

  • if the result is JSON then use it to update the UI using the .done() promise
  • if the result is HTML then pop up a login dialog.

So I have to modify the argument passed to the done() callback. Here's what I've tried so far:

function getSomeData() 
{
    return $.ajax(
    {
        /* 
            ...set my AJAX config options... 
        */,
        error: function(xhr, status, errorText)
        {
            // handle the error
        },
        success: function(data) 
        {
            // if the AJAX call returned a login form instead of expected JSON 
            // result (because the user's session has expired) then show a 
            // login dialog and resolve the jQuery promise with 'null' instead 
            // of original 'data'

            if (isLoginFormHTML(data)) 
            {
                showModalLoginDialog(data);
                data = null;    // neither this...
                return null;    // ... nor this seem to work!
            }
        }
    });
}

function updateUI()
{
    getSomeData().done(function(jsonData)
    {
        if (jsonData)
        {
            // do something 
        }
    });
}

Unfortunately, regardless of whether I do data = null or return null in my success function, the argument passed to the done() callback contains the original data returned from the server, which may be the HTML of the login form if the session has expired.

So the question is, how do I tell jQuery to pass something else to done()?

P.S. Of course, I could perform the isLoginFormHTML() check inside the updateUI method but I'm trying to avoid that in order to keep the data-retrieval and UI-update logic separate.

Это было полезно?

Решение

You should return a promise on the values you need by using .then, one of the cool things about promises is that they chain.

function getSomeData() 
{
    return $.ajax({
        /* 
            ...set my AJAX config options... 
        */,
        error: function(xhr, status, errorText)
        {
            // handle the error
        }).then(function(data){

            if (isLoginFormHTML(data)) {
                showModalLoginDialog(data);
                throw new Error("Unauthorized");..
            }
            return data;
        }
    });
}

Which would allow you to do:

    getSomeData().done(function(jsonData){
        //yay data   
    }).fail(function(){
       //no data
    });
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top