1

In an ASP.NET MVC3 application, I'm trying to use jQuery to make an asynchronous post to an action.

The following JSON object is being passed as data...

{
    categoryId: "21"
    content: "asdf"
    reference: "asdf"
    tags: [
        {id: 1, name: "asdf", status: 1},
        {id: 2, name: "asdf", status: 1},
        {id: 3, name: "asdf", status: 1}
    ]
}

The method signature I have to receive the request is

[HttpPost]
public ActionResult Create(String reference, Int32? categoryId, String content, IEnumerable<TagDTO> tags)

with TagDTO is being defined as:

public class TagDTO
{
    public String name { get; set; }
    public Int32 id { get; set; }
    public Int32 status { get; set; }
}

I should mention that before I introduced the array of objects to the JSON object and to the signature of the action method, this was working perfectly. And the Post is still successfully reaching the action, only the data in the IEnumerable is not coming through correctly. It will give me the correct number of objects in the IEnumerable, but they are all initialized to default values. (id=0, name=null, status=0)

I'm not sure what I'm doing wrong here. I hope this makes sense. I'm hoping someone can show me the proper way to pass data to an MVC action in this manner.

Thanks


Here is the javascript function I'm using to perform my ajax call...

function saveResource() {
    var tagAssignments = [];
    for (var x = 0; x < $('.tag-assignment').length; x++) {
        var tag = $($('.tag-assignment')[x]);
        tagAssignments.push({
            name: tag.find('.tag-name').html().toString(),
            id: parseInt(tag.find('.tag-id').html()),
            status: parseInt(tag.find('.tag-status').html())
        });
    }

    $.ajax({
        url: '/Resources/Create',
        dataType: 'json',
        type: 'POST',
        success: function (data) {
            if (data.status == 'Success') {
                forwardToDefaultPage();
            } else {
                alert(data.status);
            }
        },
        data: {
            reference: $('#txt-resource-reference').val(),
            categoryId: $('#ddl-category').val(),
            content: $('#txt-resource-content').val(),
            tags: tagAssignments
        }
    });
}
3
  • Please post the code of your ajax call
    – Marc
    Commented Apr 2, 2012 at 1:14
  • I would try to put all your input arguments into one object, including the array
    – TGH
    Commented Apr 2, 2012 at 1:16
  • Is your name property in your view fully qualified i.e. tags[0].name and tags[1].name etc Perhaps posting your view code might help as well
    – dreza
    Commented Apr 2, 2012 at 1:21

2 Answers 2

3

I'd would recommend you using view models and send JSON request.

So a view model:

public class CreateViewModel
{
    public string Reference { get; set; }
    public int? CategoryId { get; set; }
    public string Content { get; set; }
    public IEnumerable<TagDTO> Tags { get; set; }
}

action:

[HttpPost]
public ActionResult Create(CreateViewModel model)
{
    ...
}

AJAX request:

// TODO: build this object dynamically as you are currently doing
// but always start with hardcoded values like this to test first
var data = {
    categoryId: '21',
    content: 'asdf',
    reference: 'asdf',
    tags: [
        { id: 1, name: 'asdf', status: 1 },
        { id: 2, name: 'asdf', status: 1 },
        { id: 3, name: 'asdf', status: 1 }
    ]
};

$.ajax({
    url: '@Url.Action("create", "resources")',
    type: 'POST',
    contentType: 'application/json',
    data: JSON.stringify({ model: data }),
    success: function(result) {
        ...
    }
});

The JSON.stringify method used here is built into modern browsers. If you need to support legacy browsers you could add the json2.js script to your page.

2
  • Just a question of semantics... If the model is being used to transfer data back and forth through AJAX requests and only addresses part of what is contained in a view, should it be called a ViewModel? Or should it just be called a Model?
    – jdavis
    Commented Apr 2, 2012 at 15:00
  • 1
    @jdavis, a controller action always takes a view model as parameter and always passes a view model to the view. Commented Apr 2, 2012 at 15:16
0

A couple of things to try.

Look at changing to your ajax call as shown below.

function saveResource() {

   var tagAssignments = [];
   for (var x = 0; x < $('.tag-assignment').length; x++) {
       var tag = $($('.tag-assignment')[x]);
       tagAssignments.push({
           name: tag.find('.tag-name').html().toString(),
           id: parseInt(tag.find('.tag-id').html()),
           status: parseInt(tag.find('.tag-status').html())
       });
   }

   $.ajax({
       url: '<%: Url.Action("Create", "Resources")',
       dataType: 'json',
       type: 'POST',
       success: function (data) {
           if (data.status == 'Success') {
               forwardToDefaultPage();
           } else {
               alert(data.status);
           }
       },
       data: {
           reference: $('#txt-resource-reference').val(),
           categoryId: $('#ddl-category').val(),
           content: $('#txt-resource-content').val(),
           tags: JSON.stringify(connect)        
       }
   });

}

and change your IEnumerable to IList in your action

   [HttpPost]
   public ActionResult Create(String reference, Int32? categoryId, String content, IEnumerable<TagDTO> tags)

Not the answer you're looking for? Browse other questions tagged or ask your own question.