Mohamad
Mohamad

Reputation: 35349

How do I factor out the callbacks functionality from this ajax function?

I created a reusable ajax pattern in jQuery. It works well, but it's starting to become messy as I add more actions to it.

Look at the success callback. Every time I add a new action, the conditional logic gets messier: if actionType == foo, then bar etc...

$('.action-panel').delegate('a', 'click', function () {
    var link = $(this),
        actionTypeId = link.data('action-type-id'),

    // Do stuff, like getting the url from the link, etc...
    // Throttle multiple clicks

        $.ajax({ //[snip]

            beforeSend: function () {
                link.toggleClass('on');
            },
            error: function () {
                link.toggleClass('on');
            },
            success: function (response) {
                if (response.success) {
                    if (actionTypeId === 4) {
                        // do stuff for action 4
                    }
                    else if (actionTypeId === 2) {
                        // do stuff related to action 2
                    }
                    else if (actionTypeId === 3) {
                        // do stuff related to action 3
                    }
                    // More action types, etc...
                }
                else {
                    link.toggleClass('on');
                }
            // decide to show tooltip or not
            });
        // do some extra stuff like re-enable the link (throtled earlier)

I should factor out the ajax function by itself. But I can't figure out a way to separate the callback conditionals into their own blocks/functions, and pass back the result.

Any ideas? Please bare in mind I'm new to JavaScript and jQuery.

Upvotes: 1

Views: 127

Answers (3)

Mark Schultheiss
Mark Schultheiss

Reputation: 34168

I like to use a switch for this.

switch (actionTypeId) {
case 4:
    $('.fav-count').text(response.newcount);
    $('.fav-count').toggleClass('on');
    break;
case 2:
    link.siblings('.liked').removeClass('on');
    link.siblings('.count').text(response.newcount);
    break;
case 3:
    link.siblings('.disliked').removeClass('on');
    link.siblings('.count').text(response.newcount);
    break;
default:
    break;
}

Note that the first item found true will be executed as long as you have a break in there.

Alternate way: Note the response.success and the NEED for breaks then.

switch (true) {
    case !response.success:
        link.toggleClass('on'); 
        break;
    case actionTypeId===4:
        $('.fav-count').text(response.newcount);
        $('.fav-count').toggleClass('on');
        break;
    case actionTypeId===2:
        link.siblings('.liked').removeClass('on');
        link.siblings('.count').text(response.newcount);
        break;
    case actionTypeId===3:
        link.siblings('.disliked').removeClass('on');
        link.siblings('.count').text(response.newcount);
        break;
    default:
        break;
    }

Upvotes: 1

Andreas Louv
Andreas Louv

Reputation: 47099

Maybe you could put all the callbacks in a seperate Object:

var success_callbacks = {};
success_callbacks["2"] = function(response) {
    link.siblings('.liked').removeClass('on');
    link.siblings('.count').text(response.newcount);
};
success_callbacks["3"] = function(response) {
    link.siblings('.disliked').removeClass('on');
    link.siblings('.count').text(response.newcount);
};
success_callbacks["4"] = function(response) {
    $('.fav-count').text(response.newcount);
    $('.fav-count').toggleClass('on');
};

And then call them in your success handler

$('.action-panel').delegate('a', 'click', function () {
    var link = $(this),
        actionTypeId = link.data('action-type-id'),

    // Do stuff, like getting the url from the link, etc...
    // Throttle multiple clicks

    // BEGIN AJAX
    $.ajax({
        context: this,
        dataType: 'json',
        url: url,

        beforeSend: function () {
            link.toggleClass('on');
        },
        error: function () {
            link.toggleClass('on');
        },
        success: function (response) {
            if (response.success) {
                success_callbacks[action-type-id](response);
            }
            else {
                link.toggleClass('on');
            }
        // decide to show tooltip or not
        });
    // do some extra stuff like re-enable the link (throtled earlier)

Upvotes: 1

Pablo Fernandez
Pablo Fernandez

Reputation: 105220

Have an "action" map like this, saving the action ID and the function to execute:

var actions = {

  '4' : function () {
    $('.fav-count').text(response.newcount);
    $('.fav-count').toggleClass('on');
  },

  '2' : function() {
    link.siblings('.liked').removeClass('on');
    link.siblings('.count').text(response.newcount);
  }
}

Then on the success callback you just do:

if (response.success) {
   actions[actionTypeId]();
}

Note you'll probably have to change a bit things since link wont be visible from the callback but you can do something like actions[actionTypeId](this); and then have the callbacks receive the link as a parameter.

Upvotes: 5

Related Questions