Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I keep MVC JQuery Ajax POSTs DRY?

I'm using Ajax to POST updates to the server:

$("#my-check-box").change(function () {

         var value = $(this).attr("checked");
         var url = '<%: Url.Routes().MyAction() %>';
         $.ajaxSetup({ cache: false });
         $.post(url, { **myActionParameterName**: value }, function (data) {

             if (data.result != "success") {
                 alert(data.error);
             }

         });


     });

I don't want to write the parameter name on the client side (in case it changes) but is there a way to avoid doing this?

like image 498
Lee Smith Avatar asked Jun 13 '11 14:06

Lee Smith


3 Answers

Simple answer: no. At the end of the day, your AJAX needs to know what to call the parameter one way or another.

What you're talking about is abstraction, and not the "Don't Repeat Yourself" strategy. DRY means "Don't repeat your logic more than once," not "Don't reference variables." If that were the case, you wouldn't be able to make any sort of reference to variables or parameters because you're technically repeating the name of the variable.

You're going to have to reference something, and that something will be referenced more than once, once client side and once server side. You can abstract it into something else, sure, but at the end of the day, it's probably easiest to just reference your action parameter and don't worry about it.

Refactoring would involve a simple Find/Replace anyway, which wouldn't change under any sort of abstraction.

Now, if you're referencing that JSON object more than once or constructing it oddly multiple times in your JavaScript, that's when DRY comes into play and you should create a method where you can pass in the data to construct it.

like image 56
Adam Terlson Avatar answered Nov 03 '22 02:11

Adam Terlson


Here is what I do: I Cannot take all the credit as I found parts from an example.

    var varType;
    var varUrl;
    var varData;
    var varContentType;
    var varDataType;
    var varProcessData;          
    //Generic function to call ASMX/WCF  Service        
    function CallService() 
    {
            $.ajax({
                type        : varType, //GET or POST or PUT or DELETE verb
                url         : varUrl, // Location of the service
                data        : varData, //Data sent to server
                contentType : varContentType, // content type sent to server
                dataType    : varDataType, //Expected data format from server
                processdata : varProcessData, //True or False
                success     : function(msg) {//On Successfull service call
                ServiceSucceeded(msg);                    
                },
                error: ServiceFailed// When Service call fails
            });
    }

Then have a function for the success

function ServiceSucceeded(result) {//When service call is successful
 ....
}

Then a function for failures

 function ServiceFailed(result) {
 ...
 }

Then finally an example of calling the ajax function:

 function GetWCFJSON() {
        varType = "POST";
        varUrl = "service/WCFService.svc/GetMyData";
        varData = '{"States": "' + $('#ddlStates').val() + '"}';
        varContentType = "application/json; charset=utf-8";
        varDataType = "json";
        varProcessData = true;
        CallService();
    }
like image 43
Tom Stickel Avatar answered Nov 03 '22 02:11

Tom Stickel


I would recommend using jQuery.extend() functionality to simplify you calls and create a javascript api. Check out check out this video from MVC Conf

I use a stndard ajax call like this

//A standard ajax api call that takes in a set of options
//This uses the jQuery extend method to merge the supplied options with a set of defaults
(function ($) {
    $.apiCall = function (options) {
        var config = $.extend({
            type: 'GET',
            data: {},
            contentType: 'application/x-www-form-urlencoded',
            success: function () { },
            error: function () { }
        }, options);

        $.ajax({
            type: config.type,
            url: config.url,
            contentType: config.contentType,
            data: config.data,
            success: function (result) {
                config.success(result);
            },
            error: function (result) {
                config.error(result);
                flashError('An error occured during the operation');
                //Okay, so this last bit is kindof a problem. Your nice, sharable api should not be referencing something
                //  on the master page. So you could pass it all the way down. But that means you have to have this defined
                //  lots of places. Or you could create another js object to wrap this. There are several ways to do this and
                //  how you do it is up to you.
            }
        });
    }
})(jQuery);

I then extend it with a api per entity

//User api object
//Uses the prototype method to make sure all objects of this type have required functions
var patientsApi = function () { }

userApi.prototype.getUsers = function (options,Id) {
    var config = $.extend({
        success: function () { },
        error: function () { }
    }, options);

    $.apiCall({
        url: '/Users/GetUser',
        data:{ID:Id},
        success: function (result) { config.success(result); }
    });
}

You can then call from the page like this

        var api = new userApi();
        var UserId= $("#UserId").val();

        api.getUsers({
            success: function (result) {          
            //Do some stuff
        }
     },userId);
like image 1
Richard Forrest Avatar answered Nov 03 '22 01:11

Richard Forrest