0

I have an MVC form set up like this:

@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "createForm"}))
{
    @Html.Partial("_Action", Model)
    <div class="form-group">
        <button type="button" id="createButton" class="btn btn-primary">@Resources.Global.CreateActionButton</button>
    </div>
}

Here's the code of the partial:

@model EWI_JOPWeb.Models.ActionsViewModel
@Html.AntiForgeryToken()

<div class="form-group">
    @Html.HiddenFor(m => m.Action.Id)
</div>
<div class="form-group">
    @Html.LabelFor(m => m.Action.Number)
    @Html.TextBoxFor(m => m.Action.Number, new { @class = "form-control", type = "number", placeholder = "Vul hier een nummer in" })
</div>

<div class="form-group">
    @Html.LabelFor(m => m.Action.Title)
    @Html.TextBoxFor(m => m.Action.Title, new { @class = "form-control", placeholder = "Vul hier tekst in" })
</div>

<div class="form-group">
    @Html.LabelFor(m => m.Action.DepartmentNumber)
    @Html.DropDownListFor(m => m.Action.DepartmentNumber, Model.DepartmentSelectItems, new { @class = "form-control selectpicker noBoxShadow", title = "Selecteer opties...", data_selected_text_format = "count > 0", multiple = "multiple" })
</div>

<!-- Other similar controls -->

Following code is used to submit to a controller:

$("#createButton").click(function() {
    $.ajax({
        url: '@Url.Action("CreateAction", "Home")?spHostUrl=' + getSPHostUrlFromQueryString(window.location.search),
        dataType: "json",
        data: { viewModel: $("#createForm").serialize() },
        cache: false,
        type: "POST",
        success: function (response) {
            //show successMessage
        },
        error: function (jqXhr, textStatus, errorThrown ) {
            //show errorMessage
        }
    });
});

And of course the controller/viewmodel code:

[HttpPost]
[SharePointContextFilter]
public ActionResult CreateAction(ActionsViewModel viewModel)
{
    //process 'viewModel'
}

public class ActionsViewModel
{
    public IEnumerable<DepartmentViewModel> Departments { get; set; }
    public Action Action { get; set; }


    public IEnumerable<SelectListItem> TypeSelectItems => new[]
    {
        new SelectListItem { Value = "Beheersactie", Text = @"Beheersactie", Selected = true },
        new SelectListItem { Value = "Beleidsactie", Text = @"Beleidsactie", Selected = false }
    };

    public IEnumerable<SelectListItem> DepartmentSelectItems { get; set; }
    public IEnumerable<SelectListItem> PolicyDocumentSelectItems { get; set; }
    public IEnumerable<SelectListItem> BudgetArticleSelectItems { get; set; }
    public IEnumerable<SelectListItem> MonitoringSelectItems { get; set; }
}

The result of $("#createForm").serialize() is similar to:

__RequestVerificationToken=D71hJi2rti_r2nyqi5KLg1iYnUHIMoVizjoR5ru2fsVa4CAhRTr-3dqi9bzdWZGlE2fNZReSIzySm_B2gtmbubPWaIchekaTmOdyerwahD01&Action.Id=&Action.Number=23&Action.Title=test&Action.DepartmentNumber=f4663eb2-e9b1-4aea-a7e9-b1b49eb100a7

But when the debugger hits the controller method, viewModel remains null.

I have searched and tried solutions from following other questions:

But none of these solutions have worked for me.

Now I changed my code and added variables for the selected items and such:

public string SelectedType { get; set; }
public List<string> SelectedDepartment { get; set; }
public List<string> SelectedPolicyDocuments { get; set; }
public List<string> SelectedBudgetArticles { get; set; }
public List<string> SelectedMonitorings { get; set; }

And in my markup I adjusted this to:

@Html.DropDownListFor(m => m.SelectedMonitorings,
                      new MultiSelectList(Model.MonitoringSelectItems, "Id", "Title", Model.SelectedMonitorings),
                      new { @class = "form-control selectpicker noBoxShadow",
                      title = "Selecteer opties...",
                      data_selected_text_format = "count > 0",
                      multiple = "multiple" })

The viewmodel is not null anymore but on the other hand, the selected values are not coming through. If I select one or more items from the MultiSelect, the SelectedXXX list has always 1 item with no value.

Does anyone have any idea what is the correct way to reconstruct the ViewModel from a jQuery AJAX call to the Controller method? I am kind of list because there are several ways and combinations to achieve this.

Community
  • 1
  • 1
Abbas
  • 14,186
  • 6
  • 41
  • 72
  • 2
    Note: You do not have to serialise the form to the named `viewModel` parameter. MVC will map the values to the model with just `data: $("#createForm").serialize() ` – iCollect.it Ltd Dec 09 '16 at 16:55
  • Also dropdown lists are very buggy in MVC. The only variations we use now is the @Html.DropDownList("FieldName") version with the lookups in a ViewBag entry of the same name. – iCollect.it Ltd Dec 09 '16 at 16:57
  • @GoneCoding when I don't serialize it to the name, the SelectedXXX lists are filled but the Action in my ViewModel remains *null*. – Abbas Dec 09 '16 at 17:06
  • Are you newing your Action property in the constructor of Viewmodel? It will usually only map to properties and not create child objects. Same goes for any incoming lists. – iCollect.it Ltd Dec 09 '16 at 17:09
  • What do you mean *newing*? So you mean when I post, no new `Action` object is created to put in the ViewModel? – Abbas Dec 09 '16 at 17:14
  • Correct. In your viewmodel constructor (which I can't see) you need to create any incoming lists or child objects that are not simple value properties. I should have said `new`ing as in `Action = new Action()` :) – iCollect.it Ltd Dec 09 '16 at 17:18
  • I added `public ActionsViewModel() { Action = new Action(); }` to my ViewModel class but it remains *null*... Only if I create a ViewModel with all 'flat' properties, they get filled again. – Abbas Dec 09 '16 at 17:41
  • Its just `data: $("#createForm").serialize(),` –  Dec 09 '16 at 21:21
  • @Stephen Muecke as I stated in the comments: when I use that, the ViewModel won't be *null* anymore but the *Action* property still is. – Abbas Dec 09 '16 at 21:39
  • The `Action` property will NOT be `null` based on the code you have shown. If it is, then its due to code you have not shown (and as a side note, use `ListBoxFor(m => m.Action.DepartmentNumber, ...)`, not `DropDownListFor() with the `multiple` attribute - there are reasons that usage will fail) –  Dec 09 '16 at 21:55

0 Answers0