views:

135

answers:

2

I'm building an ASP.NET MVC site where I want to implement jQuery AJAX calls in some places. I've read up on the subject, but still have a few questions.


Model Binding

First of all, what is the correct way to pass data through the AJAX calls and have it be model-binded into an object inside my Controller Action?

So far, I've read in some places that jQuery sends data in key-value pairs, so I don't have to do anything extra, while in other places, I've read that I have to first use a JSON deserializer and then bind the result. I've currently implemented my Controller Actions as ones that accept HTTP POST.

How does it actually work? Could you give me some sample code, please?


Multiple Pieces of Data

Next, how do I send more than one pieces of data? For example, I have an AJAX method that submits a comment. In the AJAX call, I want to send two parameters: an ID parameter (of the post the comment is made on) and a Text parameter (the text of the comment).

I think the best way to do it is to create a class that contains all of the parameters and then just send the class through the AJAX call, to be bound into an identical class inside the Controller. Am I right?


Authentication

Finally, will forms authentication be transmitted through such an AJAX call?

If a user is already signed in, will the identity be sent so that I can use it in my Controller Action as usual?

Thanks in advance.

+1  A: 

Some example code is provided below.

The good news is that when you pass a list of key-value pairs via POST to one of your actions via jquery the MVC framework will do its best to map the pairs into an instance of the specified parameter object on the target action. This makes multiple pieces of data is no problem. Regarding authentication, cookies are transmitted along with your jquery POST and that should allow you to maintain session-based forms security.

You'll love MVC / have fun!

CLIENT SIDE

// you can do this once to set defaults for later ajax transmissions
$.ajaxSetup({
    dataType: "json",
    type: "POST",
    cache: false,
    failure: failureOfAsyncCall,
    beforeSend: function() {
        $('div#ajaxProcessingMessageDiv').show();
    },
    complete: function() {
        $('div#ajaxProcessingMessageDiv').hide();
    }
});
// do something like this for each ajax transmission
$.ajax({
  data: "appId=" + $('#hAppId').val() +
                    "&functionalId=" + newVal.Dsc +
                    "&Dsc=" + newVal.Dsc2 + antiForgeryTokenData,
  url: '/App/SaveProfile', // App is my controller name here
  success: function(result) {
    // process your result - a json object in this case
  }
});

SERVER SIDE

[HttpPost]
public ActionResult SaveProfile(UpdatableAppInfo postData) {
  List<object> result = new List<object>();
  // process postData here
  return Json(result);
}
Tahbaza
+1  A: 

You can post data as follows which is very simple:

var formData = $(this).serialize()
        + "&Id=" + Id
        + "&otherVal=" + otherVal;

$.post($(this).attr("action"), formData, function(res)
{
    // do stuff with response

}, "json");

with an ActionMethod defined as

public ActionResult MyAction(int id, string otherVal)
{
    return PartialView();
}

The model binder knows to match the parameter names you pass to the variables you want to bind to.

or you can use functionality like the following to extract the data from all Select dropdowns & Checkboxes on the Form:

    // frm is $('form') that gets passed to the function
    // includeContextObjects determines if it's only the elements in the 
    // current form, or from all over the page.
    function GatherFormDataAndSubmit(frm, includeContextObjects)
    {

        var data = frm.serializeObject(); 
        data = GetSelectData(frm, data, includeContextObjects);
        data = GetCheckBoxData(frm, data, includeContextObjects);

        $.post(frm.attr("action"), data, function(res)
        {
            UpdateSuccessMessage(res);
        }, "json");
    }

    function GetSelectData(frm, data, includeContextObjects)
    {
        var objSelects;
        if (includeContextObjects)
        {
            objSelects = $("select");
        }
        else
        {
            objSelects = frm.find("select");
        }

        if (objSelects.length)
        {
            data = GetDataObjectFromSelects(objSelects, data);
        }

        return data;
    }


    function GetDataObjectFromSelects(selects, data)
    {

        var valuesArray = selects.map(function()
        {
            return $.getAttributes($(this).find(":selected"));
        });

        var obj = new Array();
        $.each(valuesArray, function(item) { obj.push($(this)[0]); });

        if (!data)
        {
            data = {};
        }
        $.each(obj, function()
        {
            for (var propertyName in $(this)[0])
            {
                data[propertyName] = $(this).attr(propertyName);
            }
        });

        return data;
    }

function GetCheckBoxData(frm, data, includeContextObjects)
{
    var objCheckBoxes;
    if (includeContextObjects)
    {
        objCheckBoxes = $("input:checked");
    }
    else
    {
        objCheckBoxes = frm.find("input:checked");
    }

    if (objCheckBoxes.length)
    {
        data = GetDataObjectFromCheckBoxes(objCheckBoxes, data);
    }

    return data;
}

function GetDataObjectFromCheckBoxes(objCheckBoxes, data)
{

    var valuesArray = objCheckBoxes.map(function()
    {
        return $.getAttributes($(this));
    });

    var obj = new Array();
    $.each(valuesArray, function(item) { obj.push($(this)[0]); });

    $.each(obj, function(i)
    {
        data["configuredFactsheets[" + i + "].configuredFactsheetId"] = $(this).attr("configuredFactsheetId");
    });

    return data;
}

Note, serializeObject() relies on this, and getAttributes relies on this

In this case, my Action Method is:

[AcceptVerbs(HttpVerbs.Post)]
public JsonResult EditConfiguredPanel(ConfiguredPanel cfp, List<ConfiguredFactsheet> configuredFactsheets) 
{

    bool success = repos.UpdateConfiguredPanel(cfp, configuredFactsheets);

    return Json(success);
}

where the List<ConfiguredFactsheet>'s ids correspond to the ids gathered with GetCheckBoxData() and the id of the ConfiguredPanel corresponds to the id gathered from the selected Select list option.

It wouldn't take too much to modify this to include Comments text and another Id value.

The Forms Authentication data will get transmitted as a cookie with every request, so yes.

DaveDev
sorry - I should have also mentioned that getAttributes() requires this plugin: http://plugins.jquery.com/project/getAttributes
DaveDev