How do I post this model in MVC 4 (null model)

89 views Asked by At

My problem is quite common but I can't seem to figure out on my own why when I POST my model that it's null. My FormCollection seems to suggest it doesn't understand the whole model which it is POSTING. See code below:

My model - CaseForm.cs

namespace Models.CaseForm
{
    public class CaseForm
    {
        public CaseForm()
        {
            this.Person = new Person();
            this.Case = new Case();
            this.Cases = new List<Case>();
        }

        public string strMessage;
        public bool isValidModel;

        public Person Person = new Person();
        public Case Case = new Case();
        public List<Case> Cases = new List<Case>();
    }
}

My view = NewCase.cshtml

@model Models.CaseForm.CaseForm

@using (Html.BeginForm())
{
    @Html.Raw(Model.strMessage)
    <br />

    @*@Html.HiddenFor(m => m.Case.CaseId)
        @Html.HiddenFor(m => m.Case.CaseNotes)
        @Html.HiddenFor(m => m.Case.CaseRef)
        @Html.HiddenFor(m => m.Case.FirstAppointmentMade)
        @Html.HiddenFor(m => m.Case.IsClosedRecord)
        @Html.HiddenFor(m => m.Case.IsFirstContact)
        @Html.HiddenFor(m => m.Case.PersonId)
        @Html.HiddenFor(m => m.Case.ReasanForContact)
        @Html.HiddenFor(m => m.Case.WasAdvisedByEmail)*@

    <legend>
        <fieldset>
            <h4>New Case for @Html.Raw(Model.Person.Firstname + " " + Model.Person.Firstname)</h4>
        </fieldset>
    </legend>

    <table>
        <tr>
            <td>@Html.LabelFor(m => m.Person.PersonRef)</td>
            <td>@Html.DisplayFor(m => m.Person.PersonRef)</td>
        </tr>
        <tr>
            <td>@Html.LabelFor(m => m.Person.LesasPerson.ActionTakenPending, "Action Taken Pending")</td>
            <td>@Html.DisplayFor(m => m.Person.LesasPerson.ActionTakenPending)</td>
        </tr>
        <tr>
            <td>@Html.LabelFor(m => m.Person.LesasPerson.DateArrivedInUk, "Date Arrived In UK")</td>
            <td>@Html.DisplayFor(m => m.Person.LesasPerson.DateArrivedInUk)</td>
        </tr>
        <tr>
            <td>@Html.LabelFor(m => m.Person.LesasPerson.ImmigrationStatus, "Immigration Status")</td>
            @{
    string ImmigrationStatus = Model.Person.LesasPerson.ImmigrationStatus == null ? "No status set for this person" : Model.Person.LesasPerson.ImmigrationStatus;
            }

            <td>@Html.Raw(ImmigrationStatus)</td>
        </tr>
    </table>
    <br />

    <div id="divCase" style="border-style: solid; border-width: thin; padding: 5px;">

        <table>
            <tr>
                <td><b>If Case ref is not known then leave blank for now.</b></td>
            </tr>
            <tr>
                <td>
                    @Html.LabelFor(m => m.Case.CaseRef, "Case Reference code")
                </td>
                <td>
                    @Html.TextBoxFor(m => m.Case.CaseRef)
                </td>
            </tr>
            <tr>
                <td>
                    @Html.LabelFor(m => m.Case.FirstAppointmentMade, "First Appointment Made")
                </td>
                <td>
                    @Html.TextBoxFor(m => m.Case.FirstAppointmentMade)
                </td>
            </tr>
            <tr>
                <td>
                    @Html.LabelFor(m => m.Case.IsFirstContact, "Is First Contact")
                </td>
                <td>
                    @Html.CheckBoxFor(m => m.Case.IsFirstContact)
                </td>
            </tr>
            <tr>
                <td>
                    @Html.LabelFor(m => m.Case.ReasanForContact, "Reason For Contact")
                </td>
                <td>
                    @{
    List<SelectListItem> Reasons = new List<SelectListItem>();
    Reasons.Add(new SelectListItem() { Text = "One Off Advice", Value = "One Off Advice", Selected = false });
    Reasons.Add(new SelectListItem() { Text = "Housing", Value = "Housing", Selected = true });
    Reasons.Add(new SelectListItem() { Text = "Immigration", Value = "Immigration", Selected = false });
    Reasons.Add(new SelectListItem() { Text = "Social Advice", Value = "Social Advice", Selected = false });
    Reasons.Add(new SelectListItem() { Text = "Legal", Value = "Legal", Selected = false });

    Reasons = Reasons.OrderBy(r => r.Text).ToList();
                    }
                    @Html.DropDownListFor(m => m.Case.ReasanForContact, Reasons)
                </td>
            </tr>
            <tr>
                <td>
                    @Html.LabelFor(m => m.Case.WasAdvisedByEmail, "Was Advised By Email")
                </td>
                <td>
                    @Html.CheckBoxFor(m => m.Case.WasAdvisedByEmail)
                </td>
            </tr>
        </table>
        <hr />
        <div id="divCaseNote" style="padding:10px;">
            @for (int i = 0; i < Model.Case.CaseNotes.Count; i++)
            {
                int status = i + 1;
                <table>
                    <tr>
                        <td>@Html.Label("This is note: " + status.ToString())</td>
                    </tr>
                    <tr>
                        <td>@Html.LabelFor(m => m.Case.CaseNotes[i].CaseStatus, "Write title or status for note")</td>
                        <td>@Html.TextBoxFor(m => m.Case.CaseNotes[i].CaseStatus)</td>
                        <td>@Html.ValidationMessageFor(m => m.Case.CaseNotes[i].CaseStatus)</td>
                    </tr>
                    <tr>
                        <td>@Html.LabelFor(m => m.Case.CaseNotes[i].CaseNote, "Case Note")</td>
                        <td>@Html.TextAreaFor(m => m.Case.CaseNotes[i].CaseNote)</td>
                        <td>@Html.ValidationMessageFor(m => m.Case.CaseNotes[i].CaseNote)</td>

                        @*@Html.HiddenFor(m => m.Case.CaseNotes[i].CaseDate)
                            @Html.HiddenFor(m => m.Case.CaseNotes[i].CaseId)
                            @Html.HiddenFor(m => m.Case.CaseNotes[i].CaseNote)
                            @Html.HiddenFor(m => m.Case.CaseNotes[i].CaseNoteId)
                            @Html.HiddenFor(m => m.Case.CaseNotes[i].CaseStatus)*@
                    </tr>
                </table>
            }
        </div>
        <input type="submit" value="Add Note For Case" name="btnSubmit" />
        <input type="submit" value="Remove Note For Case" name="btnSubmit" />
    </div>

    <br />
    <input type="submit" value="Save Case To Database" name="btnSubmit" />
    <br />
    <b>@Html.ActionLink("Go back to people grid", "PeopleDashboard")</b>
}

ActionResult NewCase (POST)

[HttpPost]
        public ActionResult NewCase(string btnSubmit, FormCollection form, CaseForm Model)
        {
            RepositoryLesas RepositoryLesas = new RepositoryLesas();
            switch (btnSubmit)
            {
                case "Add Note For Case":
                    #region AddClaimStatus
                    Model.Case.CaseNotes.Add(new CaseNotes());
                    // SET to false as Model is not ready for DB
                    Model.isValidModel = false;
                    // SET message for the user
                    Model.strMessage = "Type new note information in the fields below";

                    return View("~/Views/Case/NewCase.cshtml", Model);
                    #endregion
                case "Remove Note For Case":
                    #region RemoveClaimStatus
                    // Can't remove IF only 1 
                    Model.isValidModel = false;
                    if (Model.Case.CaseNotes.Count == 0 || Model.Case.CaseNotes.Count == 1)
                    {
                        Model.strMessage = "Must be at least one case note before saving case";
                    }
                    else
                    {
                        Model.Case.CaseNotes.RemoveAt(Model.Case.CaseNotes.Count - 1);
                        Model.strMessage = "One case note removed.";
                    }
                    return View("~/Views/Case/NewCase.cshtml", Model);
                    #endregion
                //case "Save Case To Database":
                    //#region submit
                    //if (!Model.isValidModel)
                    //{
                    //    RepositoryLesas.InsertClaim(Model);
                    //    // Do one final check before going to success screen
                    //    Model.strMessage = "Claim data inserted into the database.";
                    //    Model.Person = RepositoryLesas.GetPerson(Model.Person.PersonID);
                    //    // Use to persist data through redirect - Model data will be lost otherwise
                    //    TempData["Model"] = Model;
                    //    return RedirectToAction("Success", new { URL = SuccessClaimUrl });
                    //}
                    //else
                    //{
                    //    Model.strMessage = "Claim data could not be inserted into the database. Missing key fields.";
                    //    return View("~/Views/Claim/AddClaim.cshtml", Model);
                    //}
                    //#endregion
            }
            return View("~/Views/Case/NewCase.cshtml", Model);
        }

My FormCollection

enter image description here

In my form collection, it only interprets the case object, it should show:

  • strMessage
  • isValidModel
  • Case obj
  • Cases collection
  • Person obj

Why is this model not posting correctly?

1

There are 1 answers

1
AudioBubble On BEST ANSWER

You need getter and setter on your properties. The DefaultModelBinder creates a new instance of CaseForm but can set the values of its properties that have been posted back because they dont have setters.

public class CaseForm
{
  public string strMessage { get; set; }
  public bool isValidModel { get; set; }
  ....
  public List<Case> Cases { get; set; }
}

Note you do not need the parameter FormCollection form

Note also your are rendering hidden inputs for some properties

 @Html.HiddenFor(m => m.Case.CaseRef)

and then creating a textbox for the same property

@Html.TextBoxFor(m => m.Case.CaseRef)

You need to remove the HiddenFor because it will only bind the first value on post back (the value in the hidden input) and ignore the second (the value in the textbox)