J. Lavoie J. Lavoie - 8 months ago 29
ASP.NET (C#) Question

Pass an ajax value into a controller list ASP.NET/AJAX

Ok so I basically have an ajax call retrieving values from html select multiple tag ... Thing is I'm not able to pass these values into my controller (I'm getting a null reference in my controller)

Check

types: $('select#opt2').val()
in the ajax call.
avion: $('select#opt1').val()
isn't a multiple values so it works fine. When I
alert($('select#opt2').val())
I get values like: GC,VSG,AA7... (They are separated by ",")

Here's my code:

AJAX

$('select#opt2').change(function () {
$.ajax({
url: '@Url.Action("RetournerPostes", "Home", new { area = "Avion" })',
data: { avion: $('select#opt1').val(), types: $('select#opt2').val() },
type: 'POST',
dataType: 'JSON',
//Rest of code


CONTROLLER
This is where I get the null reference for variable "types"

[HttpPost]
public async Task<ActionResult> RetournerPostes(string avion,List<string> types)
{
//Rest of action


Tell me if you need any more information. Thanks!

EDIT

Added fiddle: https://jsfiddle.net/f73jxo5v/

Win Win
Answer Source

If you bind comma separated value (CSV) a lot, the easiest and maintainable way is to create a custom model binder called CommaSeparatedModelBinder.

It is not common to capture select's change event, and make an Ajax call whenever user selects an option. But it is up to you.

enter image description here

enter image description here

[HttpGet]
public ActionResult RetournerPostes()
{
    return View();
}

[HttpPost]
public ActionResult RetournerPostes(string avion, 
    [ModelBinder(typeof(CommaSeparatedModelBinder))] int[] types)
{
    return View();
}

View

@using (Html.BeginForm())
{
    <select id="opt1">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
    </select>

    <select id="opt2" multiple>
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
    </select>
    <input type="submit" value="Submit"/>
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script type="text/javascript">
    $('select#opt2').change(function () {
        var data = JSON.stringify({ avion: $('select#opt1').val(), types: $('select#opt2').val() });
        console.log(data);
        $.ajax({
            url: '@Url.Action("RetournerPostes", "Home")',
            data: data,
            type: 'POST',
            contentType: "application/json",
            dataType: 'JSON',
            success: function(msg) {
                console.log(msg);
            }
        });
    });
</script>

CommaSeparatedModelBinder

public class CommaSeparatedModelBinder : DefaultModelBinder
{
    private static readonly MethodInfo ToArrayMethod = typeof(Enumerable).GetMethod("ToArray");

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        return BindCsv(bindingContext.ModelType, bindingContext.ModelName, bindingContext)
                ?? base.BindModel(controllerContext, bindingContext);
    }

    protected override object GetPropertyValue(ControllerContext controllerContext, ModelBindingContext bindingContext, System.ComponentModel.PropertyDescriptor propertyDescriptor, IModelBinder propertyBinder)
    {
        return BindCsv(propertyDescriptor.PropertyType, propertyDescriptor.Name, bindingContext)
                ?? base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
    }

    private object BindCsv(Type type, string name, ModelBindingContext bindingContext)
    {
        if (type.GetInterface(typeof(IEnumerable).Name) != null)
        {
            var actualValue = bindingContext.ValueProvider.GetValue(name);

            if (actualValue != null)
            {
                var valueType = type.GetElementType() ?? type.GetGenericArguments().FirstOrDefault();

                if (valueType != null && valueType.GetInterface(typeof(IConvertible).Name) != null)
                {
                    var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(valueType));

                    foreach (var splitValue in actualValue.AttemptedValue.Split(new[] { ',' }))
                    {
                        if (!String.IsNullOrWhiteSpace(splitValue))
                            list.Add(Convert.ChangeType(splitValue, valueType));
                    }

                    if (type.IsArray)
                        return ToArrayMethod.MakeGenericMethod(valueType).Invoke(this, new[] { list });

                    return list;
                }
            }
        }

        return null;
    }
}

Original Source: CommaSeparatedModelBinder.cs

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download