简体   繁体   中英

MVC.NET the ViewModel from Create POST is always null

In my MVC.NET project I used scaffolding templates. Initially ther were binded to one DTO model. Now I decided I wanted to link it to a ViewModel, because I have two multiselects I need to use to pass values. This is how my ViewModel looks:

public class CreateQuestionModel
{
   public Question Question { get; set; }
   public List<int> PoliticianIds { get; set; }
   public List<int> TopicIds { get; set; }
}

My Create POST method that is getting a ViewModel from the View:

[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "Regular")]
public ActionResult Create(CreateQuestionModel question)
{
  if (ModelState.IsValid)
  {
    int id = WebSecurity.CurrentUserId;
    manager.CreateQuestion(question.Question, id, question.PoliticianIds, question.TopicIds);
    return RedirectToAction("Index");
  }

  return View(question);
}

And my Create.cshtml looks like this:

@model PoliticiOnline.Models.CreateQuestionModel
@{
ViewBag.Title = "Stel een vraag!";
}
<head>
<link rel="stylesheet" href="~/Content/Questions.css" type="text/css" />
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
<script src="@Url.Content("~/Scripts/Extra/Chosen/chosen.jquery.min.js")" type="text/javascript"></script>
<link rel="stylesheet" href="@Url.Content("~/Scripts/Extra/Chosen/chosen.min.css")" type="text/css">   
<script src="@Url.Content("~/Scripts/Extra/select2-3.4.6/select2.min.js")" type="text/javascript"></script>
<link rel="stylesheet" href="@Url.Content("~/Scripts/Extra/select2-3.4.6/select2.css")" type="text/css">
</head>

<h2>Stel een vraag!</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
    <legend>Vraag</legend>
    <div class="general-question">
        <div class="editor-label">
            @Html.LabelFor(model => model.Question.GeneralQuestion, "Algemene Vraag")
        </div>
        <div class="editor-field">
            @Html.TextBox("Question.GeneralQuestion", new { @class = "general-question-edit" })
            @Html.ValidationMessageFor(model => model.Question.GeneralQuestion)
        </div>
    </div>

    <div id="geadresseerde-politici">
        @Html.LabelFor(model => model.PoliticianIds, "Geadresseerde Politicians:")
        @Html.ListBox("PoliticianIds", (MultiSelectList)ViewBag.Politicians, new { @id = "polDrop" })
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.Question.Explanation, "Extra Uitleg")
    </div>
    <div class="editor-field">
        @Html.TextArea("Question.Explanation", new { @class = "explanation-textarea-edit" })
        @Html.ValidationMessageFor(model => model.Question.Explanation)
    </div>

    <div>
        @Html.LabelFor(model => model.TopicIds, "Kies je thema's (maximum 2):")
        @Html.ListBox("TopicIds", (MultiSelectList)ViewBag.Topics, new { @id = "select2select", @style = "width: 500px"})
    </div>

    <p>
        <input type="submit" value="Indienen!" />
    </p>
</fieldset>
}

<div>
@Html.ActionLink("Back to List", "Index")
</div>


<script type="text/javascript">
function format(topic) {
    if (topic.css == 'optionGroup') {
        return "<b>" + topic.text + "</b>";
    } else {
        return "<i>&nbsp;&nbsp;&nbsp;" + topic.text + "<i>";
    }
}

$("#select2select").select2({
    placeholder: "Selecteer een thema...",
    maximumSelectionSize: 2,
    formatResult: format,
    escapeMarkup: function(m) {
        return m;
    }
});
</script>

The <script> section at the bottom doesn't really matter but I pasted it anyway, I'm using the jQuery plugin select2 for the ListBox.

This is a way of binding the textboxes and such to ViewModel properties, I found this on Stackoverflow. I also tried the classic way using @Html.EditorFor and @HtmlListBoxFor but the ViewModel's properties are always null.

What am I doing wrong/ what am I overlooking?

EDIT: I put a constructor in the ViewModel, now the ViewModel (CreateQuestionModel) is not null anymore, but the values are still default values (not the ones from the form). My ViewModel now looks like:

public class CreateQuestionModel
{
public Question Question { get; set; }
public List<int> PoliticianIds { get; set; }
public List<int> TopicIds { get; set; }

public CreateQuestionModel()
{
  Question = new Question();
  PoliticianIds = new List<int>();
  TopicIds = new List<int>();
}
}

SOLUTION Commenter Yoeri provided the solution, you can see it below in my answer on this question!

My dumb error that caused all the properties in the ViewModel to be default values on POSTing to the Controller . I did not declare the {get; set;} {get; set;} for each property.

ERROR

public class ApplicationViewModel
{
    public Application App;        
    public SelectList SelectSimple;
    public ApplicationViewModel() 
    {
        // Create/Init App & SelectSimple
    }
}

CORRECT

public class ApplicationViewModel
{
    public Application App { get; set; }
    public SelectList SelectSimple { get; set; }
    public ApplicationViewModel() 
    {
        // Create/Init App & SelectSimple
    }

}

COMMENT

It bears repeating that the Controller needs an [HttpGet] that passes non-null ViewModel to the View; and Controller needs an [HttpPost] to receive the ViewModel on the submit by the user.

Okay guys, I just found out what I was doing wrong. I made an extremely stupid mistake, can't believe I've been struggling for 2 days with this now.

The signature of my Create POST method was:

public ActionResult Create(CreateQuestionModel question)
{
    ...
}

It should be:

public ActionResult Create(CreateQuestionModel createQuestionModel)
{
    ...
}

I just had to change the parameter form CreateQuestionModel question to CreateQuestionModel createQuestionModel , it was as simple as that, now everything works.

UPDATE Thanks to Yoeri I now understand why it was giving problems in the first place:

Initially I named the parameter CreateQuestionModel question , this didn't work because I have a model class named Question . So basically the parameter name has to be either the name of the model you are using in the Create View, or any other name as long as it's not a name of another model class!

Thanks Yoeri!

尝试,

@using(Html.BeginForm("Create", "*controller-name*",FormMethod.Post))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM