1

My Javascript Code

$('[step="4"]').click(function () {
//shortened for brevety
var _model = new Object();
_model.ItemDesc.value = 'Descript';
//^ throws an error but gets fixed if removing the .value
_model.ItemQty.num = 1;
_model.ItemQty.unit = 'pcs'

    $.ajax({
        type: "POST",
        url: 'CreateItemCallAsync',
        data: _model,
        success: function (msg) {
            status = JSON.stringify(msg);
            alert('Item created successfully!');
            location.reload();
        },
        error: function (msg) {
            status = JSON.stringify(msg);
            alert('Failed to create item.');
            location.reload();
        }
    });
});

C# Controller Code

[HttpPost]
public async Task<JsonResult> CreateItemCallAsync(CreateItemModel item)
{
   //breakpoint here 
   var test = item.ItemDesc;
   var qty = item.ItemQty.num; //getting nulls here
   var unit = item.ItemQty.unit; //getting nulls here
}

C# CreateItemModel

public class CreateItemModel
{
   public string ItemName { get; set; }
   public string ItemDesc { get; set; }
   public ExpandoObject ItemQty { get; set; }
}

JavaScript Object

[
  {
     ItemName : 'Item1',
     ItemDesc : 'Descript'
     ItemQty : { num : 5 , unit: 'pcs'}
  },
  {
     ItemName : 'Item2',
     ItemDesc : 'Descript'
     ItemQty : { num : 1 , unit: 'box'}
  }
]

From the code above. I have a JavaScript object passed to my C# controller with a CreateItemModel parameter that has a field of ItemQty as an ExpandoObject. However, after passing to my C# controller. the ItemQty.num and ItemQty.unit are null.

With further investigating, before passing the JavaScript object to C# controller. the Objects are successfully populated.

I need ItemQty as an ExpandoObject because the fields/properites under ItemQty is always changing/dynamic

Questions:

  1. (Bit of off topic) why _model.ItemDesc.value = 'Descript' errors? On the other hand _model.ItemDesc = 'Descript' runs without error.
  2. Why am I getting nulls in ItemQty properties?
Hexxed
  • 683
  • 1
  • 10
  • 28
  • Could you show use your receive `JSON` data? – D-Shih Nov 14 '18 at 07:55
  • Add your `CreateItemModel` to the question –  Nov 14 '18 at 07:56
  • 1
    in the ajax request change the data: _model to data: { item: JSON.stringify(_model) } as your api end point is expecting the item object – Hassaan Nov 14 '18 at 07:57
  • For point 1 - `ItemDesc` is typeof `string` - it does not have a property named `value` –  Nov 14 '18 at 08:06
  • For point 2. The `DefaultModelBinder` matches the name/value pairs in the request to property names (which do not exist in your model). You need to either create a model to receive the values, or you need to create a custom ModelBinder to read the values from the request and initialize and set you `ExpandoObject` property –  Nov 14 '18 at 08:08
  • @StephenMuecke thats the problem the. `ItemQty` will not always contain `{ num : 1, unit : 'pcs' }` it can change – Hexxed Nov 14 '18 at 08:10
  • Then you need to create you own custom ModelBinder. (or another option would be to make the property a `IDictionary`) –  Nov 14 '18 at 08:13
  • @StephenMuecke `IDictionary` on `ItemQty` still returns a `null` in Controller side. – Hexxed Nov 14 '18 at 08:22
  • 1
    You need to modify the data you are sending if you want to use a Dictionary (using the default `contentType` as you are doing, then it would be `var _model = { ItemDesc.value: 'Descript', ItemQty[0].Key: 'num', ItemQty[0].Value: 1, ItemQty[1].Key: 'unit', ItemQty[1].Value: 'pcs' };` –  Nov 14 '18 at 08:26

1 Answers1

1

(Bit of off topic) why _model.ItemDesc.value = 'Descript' errors? On the other hand _model.ItemDesc = 'Descript' runs without error.

Because there isn't a property ItemDesc,ItemQty,ItemQty in original javascript Object.

You can try to create an anonymous JSON object for your javascript code.

var _model = {     
    ItemDesc: {
        value : "Descript"
    }, 
    ItemQty :{
        num : 1,
        unit :'pcs'
    }
};

instead of

var _model = new Object();
_model.ItemDesc.value = 'Descript';
_model.ItemQty.num = 1;
_model.ItemQty.unit = 'pcs'

your c# model might look like because your currently ItemDesc is an object instead of a string value.

Why am I getting nulls in ItemQty properties?

Because default ModelBindiner can't find ExpandoObject with your JSON key ItemQty object.

public class ItemDesc
{
    public string value { get; set; }
}

public class ItemQty
{
    public int num { get; set; }
    public string unit { get; set; }
}

public class CreateItemModel
{
    public ItemDesc ItemDescContext { get; set; }
    public ItemQty ItemQtyContext { get; set; }
}
D-Shih
  • 44,943
  • 6
  • 31
  • 51