Passing knockout.js observablearray object to MVC Controller Action?

16,465

Try sending it as a JSON request by specifying the correct request Content-Type header:

updateAccessLevels = function () {
    $.ajax({
        url: '/DataService/UpdateAccessLevels', 
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        data: ko.toJSON(viewModel.AccessLevels),
        success: function(status) {
            alert(status);
        }
    });
};
Share:
16,465

Related videos on Youtube

ccorrin
Author by

ccorrin

Updated on September 15, 2022

Comments

  • ccorrin
    ccorrin almost 2 years

    Im using knockout with MVC. Im trying to pass an observable array of objects from knockout back to my MVC controller action for saving to the database. If I pass the Array from knockout over to my controller action via ko.toJSON(viewModel.ArrayName) it comes back as null in my controller parameter. If I try to pass it to MVC via ko.toJS(viewModel.ArrayName) it has the correct number of items but the data is null for some reason. Any help on how to do this would be greeatly appreciated. Thanks!

    My JQuery Data Retrieval Method:

    var dataService = {};
    var viewModel;
    
    $(document).ready(function () {
        dataService.getAccessLevelList();
    })
    
    dataService.getAccessLevelList = function () {
        $.post('/DataService/GetAccessLevelList', null, function (data) {
            viewModel = ko.mapping.fromJS(data); 
            ko.applyBindings(viewModel);
        });
    }
    

    This is the problem method:

    updateAccessLevels = function () {
        $.post('/DataService/UpdateAccessLevels', { accessLevels: ko.toJSON(viewModel.AccessLevels) }, function (status) {
            alert(status);
        });
    }
    

    My MVC Controller Data Retrieval action:

        [HttpPost]
        public ActionResult GetAccessLevelList()
        {
            FacilityAccessViewModel viewModel = new FacilityAccessViewModel();
            viewModel.AccessLevels = unitOfWork.AccessLevelRepository.Get().ToList();
            return Json(viewModel);
        }
    

    The parameter is coming back NULL or with NULL data when trying to pass it in from Knockout on this controller method.

        [HttpPost]
        public ActionResult UpdateAccessLevels(List<AccessLevel> accessLevels)
        {
            try
            {
                foreach (AccessLevel record in accessLevels)
                {
                    unitOfWork.AccessLevelRepository.Update(record);
                }
    
                unitOfWork.Save();
                return Json("SUCCESS");
            }
            catch (Exception ex)
            {
                return Json(ex.ToString());
            }
        }
    

    Below is the JSON data shown via fiddler thats being posted to my MVC controller action when i pass in { accessLevels: ko.toJSON(viewModel.AccessLevels) } the controller parameter is coming in null using this

    [{"Access":[],"Id":1,"AccessLevelDesc":"TEST222"},{"Access":[],"Id":2,"AccessLevelDesc":"TEST222"}]
    

    Below is the JS data shown via fiddler thats being posted to my MVC controller action when i pass in { accessLevels: ko.toJS(viewModel.AccessLevels) }, in this case the list has two members as expected, but the data is all null in the properties

    accessLevels[0][Id] 1
    accessLevels[0][AccessLevelDesc]    TEST222
    accessLevels[1][Id] 2
    accessLevels[1][AccessLevelDesc]    TEST222
    

    If I pass in a single object to my controller it works just fine, but I cant seem to figure out the proper way to post an array of objects to my controller from an obervablearray back to a POCO entity.

    • Brian Ball
      Brian Ball over 11 years
      What is the shape of the JSON that is being posted? Either use the debugger to get this or use Fiddler to capture it, then update your post with this information. Thanks!
  • ccorrin
    ccorrin over 11 years
    This worked perfectly. Thank you. So trying to understand this, why did it come through as null without manually specifying the content type?
  • Darin Dimitrov
    Darin Dimitrov over 11 years
    Because you are sending JSON string and haven't specified the content type. The default model binder has strictly no clue how to bind it. You could have passed { accessLevels: viewModel.AccessLevels } without calling any ko.toJSON but this would have worked only with primitive types inside the array. With more complex types it's better to use a JSON request.
  • ccorrin
    ccorrin over 11 years
    That makes sense, as when I send in one item rather than an array it worked fine. Thank you Darin.
  • ViqMontana
    ViqMontana almost 6 years
    This catches me out every time, I always forget to include the contentType: 'application/json; charset=utf-8',!