Search code examples
jqueryasp.net-mvc-4modelhtml.listboxfor

Models and Listboxes


Ok so i'm trying to use a viewmodel with a list box such that when i add items to the listbox and then post the form, those items are carried over through the viewmodel to the action.

ViewModel:

public virtual ICollection<Sku> Skus { get; set; }  //This is this items sku's
public virtual ICollection<Sku> AllSkus { get; set; } //This is all sku's

My Listbox looks like this:

@Html.ListBoxFor(m=>m.Skus, new MultiSelectList(Model.Skus, "Id", "Name"), new { id = "skuList", style="width: 200px; height: 100px" })

I have a table full of all skus that when i select one, it adds to the list box using jquery. (I'll post all that code below)

My receiving action (skus is null):

    [HttpPost]
    public ActionResult AddProductOffering(ProductOfferingModel model)
    {

        return View(model);
    }

The items are adding to the listbox just fine, however the model is still null after the post.

Clearly i am just updating the listbox and not the model, i do not know how to tie the two together in this way.

Any help would be much appreciated, thank you!

(Updated) Full .cshtml file:

@using Web.ControlPanel.Helpers
@model Web.ControlPanel.ViewModels.Offering.ProductOfferingModel

@using (Html.BeginForm())
{

<h2>Product Offering</h2>
<br />

@Html.LabelFor(m => m.Name)
@Html.EditorFor(m => m.Name)

<br />
<br />

<label>Offerings Skus</label><br/>

@Html.ListBoxFor(m=>m.Skus, new MultiSelectList(Model.Skus, "Id", "Name"), new { id = "skuList", style="width: 200px; height: 100px" })

<br/><br/>

<button class="button" type="submit" value="Save">Save</button>

<br/><br/><br/>

<h3>All Skus</h3>

<p>
    Search: @Html.TextBox("skuFilter")
    <input type="submit" value="Search Skus" name="search" />
</p>

<table class="onepx" style="width: 80%">
    <tr>
        <td colspan="4" style="text-align: right;">
            @Html.Pager("List", Model.SkuPager, 3, (string)ViewBag.SkuFilter)
        </td>
    </tr>
    <thead>
        <tr style="font-weight: bold;">
            <td>Product</td>
            <td>Sku</td>
            <td>List Price</td>
            <td>MSRP</td>
            <td>Action</td>
        </tr>
    </thead>
    <tbody>

        @if (Model.Skus != null)
        {
            foreach (var sku in Model.AllSkus)
            {

                <tr>
                    <td>
                        @Html.DisplayFor(m => sku.Product.Name)
                    </td>
                    <td>
                        <label id="skuName@(sku.Id)">@sku.Name</label>
                    </td>
                    <td>[email protected](m => sku.ListPrice)
                    </td>
                    <td>[email protected](m => sku.Msrp)
                    </td>
                    <td>
                        <a href="#" class="AddSku" id="addSku@(sku.Id)">Add To Offering</a>
                    </td>
                </tr>

            }
        }
    </tbody>
    <tfoot>
    <tr>
        <td colspan="4" style="text-align: right;">
            @Html.Pager("List", Model.SkuPager, 3, (string)ViewBag.SkuFilter)
        </td>
    </tr>
</tfoot>
</table>
}

@section Scripts {
<script>
    $(document).ready(function() {

        //Array of skus
        var skus = new Array();

        $('.AddSku').click(function(e) {
            e.preventDefault();
            var id = e.target.id.replace("addSku", "");

            var exists = false;

            for (var i = 0; i < skus.length; i++) {
                if (skus[i] == id) {
                    exists = true;
                }
            }

            if (!exists) {
                var name = $("#skuName" + id).text();
                $('#skuList').append('<option value=' + id + '>' + name + '</option>');
                skus.push(id);
            }

        });

    });
</script>

}

Solution

  • MVC can't technically bind to an interface of types (or objects) - ICollection - change your ICollection<T> to List<T>. Then you need to look at how the List is being rendered in your ListBox (select). It should be rendered in array notation, i.e. something like Sku[0] ... Sku[n]. Your jQuery needs to append to the select in the same array notation. Read Phil Haack's Model Binding to a List article for more info.