Alan B
Alan B

Reputation: 2289

Passing collection to the controller from view

I have a model bind to view. I would like to add a checkbox which allows user to change select and submit the selected items for another process. User also can change the value of NumberOfCopies if needed.

I am passing the ManufacturingJobEditModel to the controller. I can see all the items in the PrintErrors collection in the controller. However, I have 2 problems here

  1. ManufacturingJob always NULL in ManufacturingJobEditModel in the controller
  2. Only IsSelected and NumberOfCopies have values. The rest of the properties show NULL values.

Is that anything that I am missing here?

Model

public class ManufacturingJobProductEditModel
{
    public ManufacturingJob ManufacturingJob{ get; set;}
    public IList<PrintError> PrintErrors { get; set; }
}

public class PrintError
{
    public bool IsSelected { get; set; }
    public int ProductId { get; set; }
    public string ISBN { get; set; }
    public string ProductName { get; set; }
    public int Sequence { get; set; }
    public int NumberofCopies { get; set; }
}

MainView

<table>
    <tr>
        <td class="display-label valign-top">Products</td>
        <td class="display-field white-space-reset"
            colspan="3">
            <table class="formDisplayTable">
                <colgroup>
                    <col class="width05" />
                    <col class="width10" />
                    <col class="width10" />
                    <col class="width35" />
                    <col class="width05" />
                    <col class="width20" />
                </colgroup>
                <thead>
                    <tr>
                        <th></th>
                        <th>ISBN</th>
                        <th>Product ID</th>
                        <th>ProductName</th>
                        <th>Sequence Number</th>
                        <th>No of Copies</th>
                    </tr>
                </thead>
                <tbody>@foreach (var product in Model.ManufacturingJob.ManufacturingJobProducts.OrderBy(c => c.Sequence))
                        {
                            Html.RenderPartial("_PrintErrorDetails", product);
                        }</tbody>
            </table>
        </td>
    </tr>
</table>

_PrintErrorDetails.cshtml

@model Bolinda.Matrix.Data.Domain.ManufacturingJobProduct
@{Html.RegisterFormContextForValidation();} 

<tr class="valign-top">
    @using (Html.BeginCollectionItem("PrintErrors"))
    {
        <td>
            <div class="editor-field">@Html.CheckBox("IsSelected")</div>
        </td>
        <td>
            <div class="table-display-field">@Html.Display("ISBN")</div>
        </td>
        <td>
            <div class="table-display-field">@Html.Display("ManufacturingProduct.Product.ProductId")</div>
        </td>
        <td>
            <div class="table-display-field">@Html.Display("ManufacturingProduct.Product.Name")</div>
        </td>
        <td>
            <div class="table-display-field">@Html.Display("Sequence")</div>
        </td>
        <td>
            <div class="table-editor-field">@Html.Editor("NumberOfCopies")</div>
        </td>
    }
</tr>

Controller

[HttpPost]
public ActionResult PrintError(ManufacturingJobProductEditModel editModel)
{
    var id = editModel.ManufacturingJob.ManufacturingJobId;
    ManufacturingJob manufacturingJob = _unitOfWork.ManufacturingJob
                                            .GetWhere(j => j.ManufacturingJobId == id, null, "ManufacturingJobProducts")
                                            .FirstOrDefault();
    if (manufacturingJob == null)
    {
        return new HttpNotFoundResult(String.Format("Manufacturing Job with id {0} was not found.", id));
    }

  //  _service.RequeueErrorCorrection(manufacturingJob, printErrorCorrection, autoCdErrorCorrection, manualCdErrorCorrectionSequenceNumbers);
    return RedirectToAction("Details", new { id = manufacturingJob.ManufacturingJobId });
}

Upvotes: 1

Views: 80

Answers (2)

Kamal Negi
Kamal Negi

Reputation: 1

This is because you are not rendering html input controls for the rest of the model properties other than "IsSelected" and "NumberOfCopies".

"@Html. Display" just render data without any html input control. You can check using page view source.

To render these control you can use below html helper methods. @Html. TextBox, @Html. DropDown, @Html. TextArea and others.

To submit all properties that you required for further processing, you must need to render html input control corresponding to that property. Only then you can able to submit those properties.

Please let me know if problem still persist.

Upvotes: 0

user3559349
user3559349

Reputation:

ManufacturingJob always NULL in ManufacturingJobEditModel in the controller

The view you have shown does not generate any form controls for any properties so no values are posted back and bound to your model. From the code in your POST method, you appear to only need the ManufacturingJobId property so you need to include

@Html.HiddenFor(m => m.ManufacturingJob.ManufacturingJobId)

Only IsSelected and NumberOfCopies have values. The rest of the properties show NULL values

Again, you have not included form controls for any properties other than the IsSelected and NumberOfCopies of each PrintError object in the collection. If you want the other properties to be bound, use

<td>
    <div class="table-display-field">@Html.Display("ISBN")</div>
    @Html.HiddenFor(m => m.ISBN)
</td>

or

<td>
    <div class="table-display-field">@Html.TextboxFor(m => m.ISBN, new { @readonly = "readonly" })</div>
</td>

Side note: Since you are not dynamically adding or deleting PrintError items in the view, there is no need to use the extra overhead of BeginCollectionItem(). Either use a for loop or a custom EditorTemplate for type of PrintError and in the main view use @Html.EditorFor(m => m.PrintErrors) (refer this answer for an example of using an EditorTemplate). I would also recommend that you populate your models PrintError collection on the server before you pass it to the view (including the .Order() clause) rather that trying to 'fake' it as you are doing.

Upvotes: 1

Related Questions