0

I have modeled (no pun intended) my AJAX call on the answer here from logan filley, which seems sensible and likely to work. This is the jquery I have in the View:

$("#btnSaveConfig").click(function () {

    var saveConfigModel = {
        unit: $('#unitsselect').val(),
        scheduleProduceUsage: $('#ckbx_produceusage').checked,
        scheduleDeliveryPerformance: $('#ckbx_deliveryperformance').checked,
        scheduleFillRate: $('#ckbx_fillratebycustomer_location').checked,
        schedulePriceCompliance: $('#ckbx_pricecompliance').checked,
        // TODO: Finish this by storing add'l emails in an array along with the three on the page; 
        recipients: $('#email1').val(),
        generationDayOfMonth: $('#dayofmonthselect').val(),
        generationOrdinal: $('#ordinalselect').val(),
        generationDayOfWeek: $('#dayofweekselect').val(),
        generationWeekOrMonth: $('#weekormonthselect').val(),
        daterangeFromProduceUsage: $('#produsagefrom').val(),
        daterangeToProduceUsage: $('#produsageto').val(),
        daterangeFromDeliveryPerformance: $('#delperffrom').val(),
        daterangeToDeliveryPerformance: $('#delperfto').val(),
        daterangeFromFillRate: $('#fillratefrom').val(),
        daterangeToFillRate: $('#fillrateto').val(),
        daterangeFromPriceCompliance: $('#pricecompliancefrom').val(),
        daterangeToPriceCompliance: $('#pricecomplianceto').val()
    }

    $.ajax({
        type:"POST",
        url:'@Url.Action("PostUnitConfig", "SaveConfig")', 
        async:true,
        contentType: 'application/json',
        dataType:"json",
        data: JSON.stringify(saveConfigModel)
    });
}); // $("#btnSaveConfig").click()

...and this is my Model:

public class SaveConfigModel
{
    public UnitConfigVals unitConfigVals { get; set; }

    public class UnitConfigVals
    {
        public string unit { get; set; }
        public bool scheduleProduceUsage { get; set; }
        public bool scheduleDeliveryPerformance { get; set; }
        public bool scheduleFillRate { get; set; }
        public bool schedulePriceCompliance { get; set; }
        public List<string> recipients { get; set; }
        public int generationDayOfMonth { get; set; }
        public string generationOrdinal { get; set; }
        public string generationDayOfWeek { get; set; }
        public string generationWeekOrMonth { get; set; }
        public int daterangeFromProduceUsage { get; set; }
        public int daterangeToProduceUsage { get; set; }
        public int daterangeFromDeliveryPerformance { get; set; }
        public int daterangeToDeliveryPerformance { get; set; }
        public int daterangeFromFillRate { get; set; }
        public int daterangeToFillRate { get; set; }
        public int daterangeFromPriceCompliance { get; set; }
        public int daterangeToPriceCompliance { get; set; }
    }
}

...and Controller (obviously ultra-spartan at the moment):

public class SaveConfigController : Controller
{
    public ActionResult PostUnitConfig(SaveConfigModel model) 
    {
        try
        {
            string s = model.unitConfigVals.unit;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        return Json(new { success = true });
    }
}

I am reaching the breakpoint in my Controller (on the "string s = model.unitConfigVals.unit;" line), but it throws an exception because the value of "model" is null. Why? Have I got something in my AJAX call wrong, or...?!?

UPDATE

I changed my jquery to this (changed boolean assignments and appended a semicolon):

   $("#btnSaveConfig").click(function() {

      var saveConfigModel = {
        unit: $('#unitsselect').val(),
        scheduleProduceUsage: $('#ckbx_produceusage').attr('checked'),
        scheduleDeliveryPerformance: 
        . . .
    };

    $.ajax({
        type: "POST",
        url: '@Url.Action("PostUnitConfig", "SaveConfig")',
        async: true,
        //contentType: 'application/json',
        dataType: "json",
        data: JSON.stringify({ data: saveConfigModel })
    });
});

...but the Controller is still passed a null model.

UPDATE 2

Now I changed "attr('checked')" to "is('checked')" but no difference...

UPDATE 3

"model" is null here in the Controller:

public class SaveConfigController : Controller
{
    public ActionResult PostUnitConfig(SaveConfigModel model)

...when the AJAX call is like this:

$.ajax({
    type: "POST",
    url: '@Url.Action("PostUnitConfig", "SaveConfig")',
    async: true,
    dataType: "json",
    data: saveConfigModel
});

...and also when the AJAX call is like this:

$.ajax({
    type: "POST",
    url: '@Url.Action("PostUnitConfig", "SaveConfig")',
    async: true,
    data: saveConfigModel
});

...and this:

$.ajax({
    type: "POST",
    url: '@Url.Action("PostUnitConfig", "SaveConfig")',
    async: true,
    contentType: 'application/json',
    dataType: "json",
    data: JSON.stringify({ model: saveConfigModel })
});

Do I need the "async: true"? I don't use that in my (working) GET AJAX calls. Similarly, do I need "cache: false"? I do use that in those working GET AJAX calls...

UPDATE 4

Even when I provide just some bogus vals:

var saveConfigModel = {
    unit: 'Buford', //$('#unitsselect').val(),
    scheduleProduceUsage: true, //$('#ckbx_produceusage').is(':checked'),
    scheduleDeliveryPerformance: false, // $('#ckbx_deliveryperformance').is(':checked'),
    scheduleFillRate: false, //$('#ckbx_fillratebycustomer_location').is('checked'),
    schedulePriceCompliance: false, //$('#ckbx_pricecompliance').is('checked'),
    // TODO: Finish this by storing add'l emails in an array along with the three on the page; might be as easy as declaring an array like this one, and adding to it as necessary
    recipients: 'platypus@whatever.com', // $('#email1').val(),
    generationDayOfMonth: '2nd', //$('#dayofmonthselect').val(),
    generationOrdinal: 'First', //$('#ordinalselect').val(),
    generationDayOfWeek: 'Thursday', // $('#dayofweekselect').val(),
    generationWeekOrMonth: 'month', // $('#weekormonthselect').val(),
    daterangeFromProduceUsage: $('#produsagefrom').val(),
    daterangeToProduceUsage: $('#produsageto').val(),
    daterangeFromDeliveryPerformance: '1', // $('#delperffrom').val(),
    daterangeToDeliveryPerformance: '1', //$('#delperfto').val(),
    daterangeFromFillRate: '1', //$('#fillratefrom').val(),
    daterangeToFillRate: '1', //$('#fillrateto').val(),
    daterangeFromPriceCompliance: '1', //$('#pricecompliancefrom').val(),
    daterangeToPriceCompliance: '1' //$('#pricecomplianceto').val()
};

...it still winds up at the Controller null like forevermore before.

And then, grasping at straws, I even encased the boolean values in single quotes ('true' and 'false'), but that also (probably predictably) made no difference either.

UPDATE 5

For future generations, this is the AJAX that works:

$.ajax({
    type: "POST",
    url: '@Url.Action("PostUnitConfig", "SaveConfig")',
    async: true,
    contentType: 'application/json',
    dataType: "json",
    data: JSON.stringify({ model: saveConfigModel })
});
Community
  • 1
  • 1
B. Clay Shannon-B. Crow Raven
  • 8,547
  • 144
  • 472
  • 862
  • 1
    It would need to be `data: JSON.stringify({ model: saveConfigModel })` or better, just use `data: saveConfigModel` and remove the `contentType` option. But there appear to be other issues with th way your generating the data, in particular for the `bool` properties –  Apr 29 '16 at 22:03
  • 1
    But the question is why you are not generating your form controls correctly in the first place, in which case it would be simply `var saveConfigModel = $('form').serialize();` –  Apr 29 '16 at 22:06
  • @StephenMuecke: Either because I don't/didn't know how, or because these aren't "form" controls (if "form" controls need to be within a "form" delimiter, as these are just all the controls on the page). – B. Clay Shannon-B. Crow Raven Apr 29 '16 at 22:21
  • @StephenMuecke: What's wrong with how I'm getting the bool properties? – B. Clay Shannon-B. Crow Raven Apr 29 '16 at 22:29
  • 1
    Add `console.log($('#ckbx_produceusage').checked));` and check the output :). It would need to be `$('#ckbx_produceusage').is(':checked')` –  Apr 29 '16 at 22:38
  • Please czech out my updates. – B. Clay Shannon-B. Crow Raven Apr 29 '16 at 22:44
  • 1
    The parameter in your method is `model`, not `data` (read my first comment) –  Apr 29 '16 at 22:46
  • That's where I got the idea to use "data"; maybe I was taking it too literally...still null using "model"... – B. Clay Shannon-B. Crow Raven Apr 29 '16 at 22:48
  • 1
    Have just noticed that your model is wrong - your posting back values associated with `UnitConfigVals` (not `SaveConfigModel`) so its `public ActionResult PostUnitConfig(SaveConfigModel.UnitConfigVals model)`. But why do you have that as a nested class? –  Apr 29 '16 at 23:24
  • Aha! That was it. Make it an answer and I'll flag it accordingly. – B. Clay Shannon-B. Crow Raven Apr 29 '16 at 23:28

1 Answers1

1

Since the values you posting back are for your nested UnitConfigVals class (not SaveConfigModel, then you controller method should be

public ActionResult PostUnitConfig(SaveConfigModel.UnitConfigVals model)

and the ajax data option needs to be

data: JSON.stringify({ model: saveConfigModel })

Alternatively you could keep the current controller method and use

data: JSON.stringify({ model: { unitConfigVals: saveConfigModel }})

although it seems a little odd that you using a nested class here.

A few other issues with your initial code

  1. $('#ckbx_produceusage').checked will return undefined, and it needs to be $('#ckbx_produceusage').is(':checked') which will return true or false
  2. Since recipients is List<string>, it will need to be recipients: [ 'someValue', 'anotherValue', etc ]

However all this code to build you json data not really necessary, and if your view is generated correctly using the strongly typed HtmlHelper methods, then your ajax call can be as simple as

$.ajax({
    type:"POST",
    url:'@Url.Action("PostUnitConfig", "SaveConfig")',
    dataType: "json",
    data: $('form').serialize(),
    success: function(data) {
        // do something
    }
});