Get items from listbox in controller MVC ASP 4

2019-03-30 04:20发布

问题:

I have a page where you can create channels. Channels have genres associated with them.

CreateChannel.cshtml
<h2>Create Channel</h2>

<div class="row-fluid">
<div>
    @{
        using (Html.BeginForm("CreateNewChannel", "Channel", new { channelId = Model.Id, userId = @Session["userId"] }, FormMethod.Post))
        {
            @Html.HiddenFor(model => model.Id)
            <h5>Name</h5>
            @Html.TextBoxFor(model => model.Name, new { @class = "input-block-level pull-left", type = "text", required = "required", placeholder = "Channel Name", style = "width: 400px" })
            @Html.ValidationMessageFor(model => model.Name, null, new { @class = "txt-error error-field", style = "padding-top: 4px" })
            <div class="clearfix"></div>
            <div style="width: 400px" class="input-block-level">
                <h5 style="">Description</h5>
                <div class="input-block-level">
                    @Html.TextAreaFor(model => model.Description, 5, 60, new { @class = "input-block-level", type = "textarea", required = "required", placeholder = "Description" })
                </div>
            </div>

            @Html.Action("SelectGenre", new { channelId = -1 })

            <button class="btn">Create</button>
        }
    }
</div>

The view SelectGenre.cshtml looks like this:

<div id="genreDiv">
@Html.ListBoxFor(model => model.AvailableGenres, new MultiSelectList(Model.AvailableGenres, "Id", "Name"), new { size = "10" })

<input id="btnAddAll" type="button" value=" >> " onclick="addallItems();" />
<input id="btnAdd" type="button" value=" > " onclick="addItem();" />
<input id="btnRemove" type="button" value=" < "  onclick="removeItem();" />
<input id="btnRemoveAll"type="button" value=" << "  onclick="removeallItems();" />

@Html.ListBoxFor(model => model.ChosenGenres, new MultiSelectList(Model.ChosenGenres, "Id", "Name"), new { size = "10" })
</div>

<script type="text/javascript">
function addItem() {
    $("#AvailableGenres option:selected").appendTo("#ChosenGenres");
    $("#ChosenGenres option").attr("selected", false);
}
function addallItems() {
    $("#AvailableGenres option").appendTo("#ChosenGenres");
    $("#ChosenGenres option").attr("selected", false);
}
function removeItem() {
    $("#ChosenGenres option:selected").appendTo("#AvailableGenres");
    $("#AvailableGenres option").attr("selected", false);
}
function removeallItems() {
    $("#ChosenGenres option").appendTo("#AvailableGenres");
    $("#AvailableGenres option").attr("selected", false);
}
</script>

The controller looks like this:

public class ChannelController : Controller
{
    public SelectGenreModel GetGenreModel(int channelId)
    {
        List<GuiGenre> chosenGenres;
        List<GuiGenre> availableGenres;
        using (RentItServiceClient proxy = new RentItServiceClient())
        {
            chosenGenres =     GuiClassConverter.ConvertGenres(proxy.GetGenresForChannel(channelId));
            availableGenres = GuiClassConverter.ConvertGenres(proxy.GetAllGenres()).Except(chosenGenres).ToList();
        }
        SelectGenreModel model = new SelectGenreModel
        {
            AvailableGenres = availableGenres,
            ChosenGenres = chosenGenres,
            ChannelId = channelId,
        };
        return model;
    }

    public PartialViewResult SelectGenre(int channelId)
    {
        return PartialView(GetGenreModel(channelId));
    }
}

public ActionResult CreateNewChannel(GuiChannel channel, int? userId, SelectGenreModel     model)
    {
        if (userId.HasValue)
        {
            channel.OwnerId = userId.Value;
            int channelId;
            using (RentItServiceClient proxy = new RentItServiceClient())
            {
                channelId = proxy.CreateChannel(channel.Name, userId.Value, channel.Description, new string[0]);
            }
            return RedirectToAction("SelectChannel", new { channelId = channelId, userId = userId });
        }
        return RedirectToAction("Index", "Home");
    }

The SelectGenreModel looks like this:

public class SelectGenreModel
{
public List<GuiGenre> AvailableGenres { get; set; }
public List<GuiGenre> ChosenGenres { get; set; }
public int ChannelId { get; set; }
}

When i submit the form, both lists in the SelectGenreModel is null.

How can i pass these lists to the view?

回答1:

The reason why it is not deserializing is because the form data posted back does not match the format that MVC is expecting for array mapping.

To approach what you are trying to accomplish, I would recommend creating another model to represent the form posted data. In this case:

public class SelectedGenrePostModel
{
    public int ChannelId { get; set; }
    public List<int> ChosenGenres { get; set; }
}

And in your view, have javascript hook into the submit event to automatically select all of the options in ChosenGenres so they are properly posted back according to what your UI is doing.

<script type="text/javascript">
    $(function () {
        // this event fires when the browser is about to submit a form
        $('#GenreForm').submit(function () {
            // modifies the 'selected' options on the list 
            // before finally being submitted by the browser
            $('#ChosenGenres option').prop('selected', true);
        });
    });
</script>

Then, if you absolutely need the SelectGenreModel, you repopulate using your service call and the data posted back via SelectedGenrePostModel.

public ActionResult CreateNewChannel(GuiChannel channel, int? userId, SelectGenrePostModel model)
{
    if (userId.HasValue)
    {
        // do work here
        return RedirectToAction("SelectChannel", new { channelId = channelId, userId = userId });
    }
    return RedirectToAction("Index", "Home");
}