0

I would like to save users steps and have each row in my MVC index view be a form.

I am using the HTML.Begin form inside the foreach to build the individual forms. The page renders without errors and the form submits without problems, but I can not bind to a model inside the controller - thus all the submitted data is lost.

I have validated that the form values are there to begin with when the form is submitted: item.Completed=true&item.Completed=false&item.Comment=HELLO+WORLD+&item.FinalizeStepId=1&item.StepId=1, but the controller does not accept them and the FinalizeStepViewModel object is created with null values.

So how do I get the form to pass back the data correctly?

This might be my second question ever on Stackoverflow, so let me know what additional information I might need to add.

Thanks.

=== Model =====

public class FinalizeStepViewModel
    {
    public int FinalizeStepId { get; set; }

    // foreign key from Step table
    public int StepId { get; set; }

    // name of taks from Step table 
    public string StepDesc { get; set; }

    [DisplayName("Review Data")]
    public string ReviewFormulaValue { get; set; }

    [Required]
    public bool Completed { get; set; }

    [DisplayName("Fiscal Year")]
    public int FiscalYear { get; set; }

    // Period for the adjustment
    [Required]
    public int Period { get; set; }

    [Required]
    public string UserID { get; set; }

    [Required]
    [DisplayName("Created By")]
    public string CreatedBy { get; set; }

    [Required]
    [DisplayName("Created At")]
    public DateTime CreatedAt { get; set; }

    public string Comment { get; set; }

==== View ========== @model IEnumerable

@{ ViewBag.Title = "Index";

// is everything completed, if yes => enabled
string alldone = "enabled";

}

<h2>Finalize Checklist</h2>


<table class="table">
    <tr>
        <th>
            Completed
        </th>
        <th>
            Finalized Task
        </th>
        <th>
            Review Data
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Comment)
        </th>
        <th></th>
        <th></th>
        @*<th>
                @Html.DisplayNameFor(model => model.FiscalYear)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Period)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.CreatedBy)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.CreatedAt)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.UserID)
            </th>*@
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        //<form action="/FinalizeSteps/Checklist/" method="post">
        //@using (Html.BeginForm("Login", "Account", FormMethod.Post))
        //// <form action="/Account/Login" action="post">

        using (Html.BeginForm("EditFromChecklist", "FinalizeSteps", FormMethod.Post, new { finalizeStepPassed = Model }))
        {
            <tr>
                <td>
                    <div class="form-group" style="text-align: center; vertical-align: text-top;">
                        <div class="checkbox">
                            @Html.EditorFor(modelItem => item.Completed)
                            @if (item.Completed == false) { alldone = "disabled"; }
                        </div>
                    </div>
                </td>
                <td>
                    <h4>@Html.DisplayFor(modelItem => item.StepDesc)</h4>
                </td>
                <td style="text-align: center;">
                    @Html.DisplayFor(modelItem => item.ReviewFormulaValue)

                </td>
                <td>
                    <div class="form-group" style="width: 300px;">
                        @Html.EditorFor(modelItem => item.Comment, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(modelItem => item.Comment, "", new { @class = "text-danger" })
                    </div>

                </td>
                <td>
                    <div class="form-group">
                        @Html.EditorFor(modelItem => item.FinalizeStepId, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(modelItem => item.FinalizeStepId, "", new { @class = "text-danger" })
                    </div>

                </td>
                <td>
                    <div class="form-group">
                        @Html.EditorFor(modelItem => item.StepId, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(modelItem => item.FinalizeStepId, "", new { @class = "text-danger" })
                    </div>

                </td>
                @*<td>
                        @Html.DisplayFor(modelItem => item.FiscalYear)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Period)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.CreatedBy)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.CreatedAt)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.UserID)
                    </td>*@
                <td>
                    <div class="form-group">
                        <input type="submit" value="Save" class="btn btn-default" />
                    </div>
                    @Html.ActionLink("Save", "EditFromChecklist", new { FinalizeStepId = item.FinalizeStepId, StepId = item.StepId, Completed = item.Completed, Comment = item.Comment })

                    @*@Html.ActionLink("Edit", "Edit", new { id = item.FinalizeStepId }) |
                        @Html.ActionLink("Details", "Details", new { id = item.FinalizeStepId }) |
                        @Html.ActionLink("Delete", "Delete", new { id = item.FinalizeStepId })*@
                </td>
            </tr>
        }
    }

</table>

=== Controller Method ====

    [HttpPost]       
    public ActionResult EditFromChecklist([Bind(Include = "FinalizeStepId,StepId,Completed,Comment")] FinalizeStepViewModel finalizeStepPassed)
     {

        // Do we have a FinalizeStepId?
        if (finalizeStepPassed.FinalizeStepId != 0)
        {
            // Yes, this is an edit

...

NJA
  • 47
  • 2
  • 9

2 Answers2

0

You should bind to a IList instead of IEnumerable, and instead of

@foreach (var item in Model)
{
    @Html.EditorFor(modelItem => item.Completed)
}

Use this syntax

@for( int i=0; i < Model.Count; i++ )
{
    @Html.EditorFor(modelItem => Model[i].Completed)
}

Here is an earlier topic that also discussed this: How to pass IEnumerable list to controller in MVC including checkbox state?

Community
  • 1
  • 1
John
  • 354
  • 2
  • 5
  • I saw that post, but couldn't put it to together with my problem. Your comment comment helped. Maybe next time I will try that. But deadlines loom and Sam's answer gets me going right now. Thank you. – NJA Jul 30 '15 at 19:47
0

Change your EditFromChecklist action's parameter from finalizeStepPassed to item.

Or you could use a partial view to submit your data.

_FinalizeStepPartial.cshtml

@model FinalizeStepViewModel

using (Html.BeginForm("EditFromChecklist", "FinalizeSteps"))
{
    @Html.EditorFor(model => model.Completed)
    // rest of your form
}

and in the main view inside of loop call the partial

@foreach (var item in Model)
{
    @Html.Partial("_FinalizeStepPartial",item)
} 
Sam FarajpourGhamari
  • 13,921
  • 4
  • 49
  • 55
  • Changed finalizedStepPassed to item and a couple of small tweaks and poof, it is working. I knew it had to be right in front of me. Thanks much. – NJA Jul 30 '15 at 19:42