1

I've seen a few very similar posts on here regarding iterating through a list of models and creating a form within each iteration, but nothing has led me to successfully POST back a populated model.

My goal is to present an inline form for each iteration of the model and allow users to make changes and save the edits for that specific model when the associated form gets submitted. I'm still fairly new to ASP.NET MVC so if there is a better way to go about this, please feel free to offer suggestions.

Thanks in advance for any help with this!

View

@model List<POSGuys.Option>

@{
    var options = Model.OrderBy(i => i.OptionEndOfLife).ToList();
}

@for (int i = 0; i < options.Count(); i++)
{
    using (Html.BeginForm("Save", "Option", FormMethod.Post ))
    {
        <tr style="@(options[i].OptionEndOfLife ? "color:#777" : "")">
            @Html.HiddenFor(model => options[i].OptionID)
            <td>@options[i].ItemNumber</td>
            <td width="100"><img @Html.Raw(POSGuys.Controllers.Shims.Resize("/content/images/catalog/" + options[i].image, 200, 200, rescale: 2)) /></td>
            <td>@Html.EditorFor(model => options[i].OptionName)</td>
            <td>@Html.EditorFor(model => options[i].PGPrice)</td>
            <td>@Html.EditorFor(model => options[i].OptionsMSRP)</td>
            <td>@Html.EditorFor(model => options[i].Cost)</td>
            <td>@Html.EditorFor(model => options[i].Description)</td>
            <td>@Html.EditorFor(model => options[i].Rank)</td>
            <td>@Html.EditorFor(model => options[i].Standard)</td>
            <td><input type="submit" value="Save" class="btn btn-warning" /></td>
        </tr>
    }
}

Controller

[HttpPost]
public ActionResult Save(Option option)
{
    var opt = StoreDatabase.Options.Find(option.OptionID);

    if (opt != null)
    {
        StoreDatabase.Entry(opt).CurrentValues.SetValues(option);
        StoreDatabase.SaveChanges();
    }

    return RedirectToAction("EditList", option.ProductID);
}
6
  • 1
    You creating inputs with <name="[0].OptionName" etc which will not bind to Option. But why are you generating multiple forms - you can only submit one at a time. Have one form and put the for loop inside it and change the method parameter to List<Option> Commented Jul 20, 2016 at 23:18
  • I suppose I wanted a form for each iteration so that I'm only posting back the data that I want to update and not the whole list. There will only ever be one iteration getting updated at a time, but I want to allow the user to quickly edit any field in any iteration of the model. Commented Jul 20, 2016 at 23:24
  • 1
    There is no point generating all that extra html for inputs when you only want to submit one item. Just render a details view for each item with an associated link to an edit page (or a modal form if you want to edit it on the same page). But if you want to allow the user to edit any field in any iteration, then you need one form, not many Commented Jul 20, 2016 at 23:27
  • Dang, I definitely feel like I'm fighting the framework, but I wanted to avoid a separate edit page or even a modal popup. Or rather, my boss wants it as quick and seamless as possible. What do you think about implementing some sort of AJAX solution that grabs the fields dynamically on submit via javascript and posts it back? Commented Jul 20, 2016 at 23:31
  • 1
    That will give you all sorts of other issues such as handling validation, returning the view if invalid etc that you will need to solve. But again, what is the point of this. A user sees inputs for each item in the collection, edits a field in the first one, then another in the 3rd one and presses a submit button - it may not even be the submit button associated with what they have edited, but at best, only one change will be submitted (the poor user has just lost all the changes and will be none the wiser Commented Jul 20, 2016 at 23:35

2 Answers 2

5

You just need to make sure that your code is generating the input field's with name values same as the property names of the Option class and model binding will work.

@for (int i = 0; i < options.Count(); i++)
{
    using (Html.BeginForm("Save", "Option", FormMethod.Post))
    {

        @Html.EditorFor(model => options[i].OptionName,null,"OptionName")
        @Html.EditorFor(model => options[i].PGPrice,null, "PGPrice")
        <input type="submit" />
        <br />  
    }
}

Now when you submit the form, the Default model binder will be able to map the form field values to the properties of the Option class object.

Sign up to request clarification or add additional context in comments.

2 Comments

That's the missing piece, it's working now, Thank you!
I've faced similar problem , but I used ASP-FOR to map the property but it gives empty value. what would be the solution?
1

Much easier solution - create partial view. If you have your main view as List your partial should be just Model and everything will work like it should.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.