0

I'm new to MVC (which you'll soon be able to tell from my code). My issue is binding is not working as I'd hoped because there is a for loop inside a for loop, and I don't know how to make it work.

I have one page that displays an OVERALL object, all the ASSETs associated with OVERALL, then all the PORTs associated with each ASSET. The user can edit some fields in it as well. ie It's Index and Edit all in one VIEW.

I populate my model called OVERALL in my httpget Index controller successfully. I display the data on screen via my view and it works.

But when I hit my 'validate' button which goes to my httpost Index controller, my pList only contains the 5 entries related to the first entry in the aList, instead of all 20 entries (5 PORTS per ASSET and there is 4 ASSETS in OVERALL). oList and aList have the correct values though.

My controller:

[HttpPost]
 public ActionResult Index(OVERALL oList, IList<ASSET> aList, IList<PORT> pList)

I assume it's because the bind is not working because there is a for loop inside a for loop in my view which is confusing the name/id's for the binding, but I don't know how to fix it.

Should I be specifying an input name for each item in the Port list?

Should I rewrite this completely as I'm doing it wrong. My ultimate goal being to pass all the data from my OVERALL object (including the connected collections) to my httppost index controller?

Here's some of my view:

@model Models.OVERALL

<div>
    <hr />
    <dl class="dl-horizontal">
        @Html.HiddenFor(model => model.OVERALLID)
        <dt>
            @Html.DisplayNameFor(model => model.EMAIL_SEND_DATE)
        </dt>
        <dd>
            @Html.HiddenFor(model => model.EMAIL_SEND_DATE)
            @Html.DisplayFor(model => model.EMAIL_SEND_DATE)
        </dd>
        <dt>
            @Html.DisplayNameFor(model => model.SENDER_ID)
        </dt>
        <dd>
            @Html.HiddenFor(model => model.SENDER_ID)
            @Html.DisplayFor(model => model.SENDER_ID)
        </dd>
        @Html.HiddenFor(model => model.ASSET)
        <dd>
            <table class="table">
                @for (int i = 0; i < Model.ASSET.Count(); i++)
                {
                    @Html.HiddenFor(x => x.ASSET.ToList()[i].OVERALLID)
                    <tr>
                        <td>
                            @Html.HiddenFor(x => x.ASSET.ToList()[i].ASSETID)
                            @Html.DisplayFor(x => x.ASSET.ToList()[i].ASSETID)
                        </td>
                        <td>
                            @Html.HiddenFor(x => x.ASSET.ToList()[i].ASSET_CLASS)
                            @Html.DisplayFor(x => x.ASSET.ToList()[i].ASSET_CLASS)
                        </td>
                        <td>
                            @Html.EditorFor(x => x.ASSET.ToList()[i].NEW_FUNDS_TO_BE_INVESTED)
                        </td>
                    </tr>
                    @Html.HiddenFor(x => x.ASSET.ToList()[i].PORT)
                    for (int j = 0; j < Model.ASSET.ToList()[i].PORT.Count(); j++)
                    {
                        <tr>
                            @Html.HiddenFor(y => y.ASSET.ToList()[i].PORT.ToList()[j].ASSETID)
                            <td>
                                @Html.HiddenFor(y => y.ASSET.ToList()[i].PORT.ToList()[j].PORTID)
                                @Html.DisplayFor(y => y.ASSET.ToList()[i].PORT.ToList()[j].PORTID)
                            </td>
                            <td>
                                @Html.HiddenFor(y => y.ASSET.ToList()[i].PORT.ToList()[j].PORTFOLIO)
                                @Html.DisplayFor(y => y.ASSET.ToList()[i].PORT.ToList()[j].PORTFOLIO)
                            </td>
                            <td>
                                @Html.EditorFor(y => y.ASSET.ToList()[i].PORT.ToList()[j].NEW_TARGET)
                            </td>
                        </tr>
                    }
                }
            </table>
        </dd>
    </dl>
</div>

Here's my classes (built automatically using EF database first): each OVERALL has many ASSET and each ASSET has many PORT.

public partial class OVERALL
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public OVERALL()
    {
        this.ASSET = new HashSet<ASSET>();
    }

    public decimal OVERALLID { get; set; }
    public DateTime? EMAIL_SEND_DATE { get; set; }
    public string SENDER_ID { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<ASSET> ASSET { get; set; }
}

 public partial class ASSET
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public ASSET()
    {
        PORT = new HashSet<PORT>();
    }

    public decimal ASSETID { get; set; }
    public string ASSET_CLASS { get; set; }
    public decimal? NEW_FUNDS_TO_BE_INVESTED { get; set; }
    public decimal OVERALLID { get; set; }

    public virtual OVERALL OVERALL { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PORT> PORT { get; set; }
}   

 public partial class PORT
{
    public decimal PORTID { get; set; }
    public string PORTFOLIO { get; set; }
    public Nullable<decimal> NEW_TARGET { get; set; }
    public decimal ASSETID { get; set; }

    public virtual ASSET ASSET { get; set; }
}   
fkn_ace
  • 1
  • 1
  • Please note that the model-view-controller tag is for questions about the pattern. There is a specific tag for the ASP.NET-MVC implementation. –  Nov 11 '16 at 07:19
  • You need to remove `.ToList()` from all your methods. If the properties are not already `IList`, then you need to make then `IList` or use EditorTemplates. And your post method just needs to be `public ActionResult Index(OVERALL oList)` In any case, your editing data so use view models, not data models –  Nov 11 '16 at 07:22
  • You also need to remove `@Html.HiddenFor(model => model.ASSET)` and `@Html.HiddenFor(x => x.ASSET.ToList()[i].PORT)` from your view - look at the html they generate to understand why that would also cause binding to fail –  Nov 11 '16 at 07:23
  • Recommend you also read [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) (and compare it with the html your generating) –  Nov 11 '16 at 07:49
  • Hi @StephenMuecke, thanks for the responses. To start, I'll use view models instead of data models. As you can see I want to display and edit data from OVERALL, ASSET and PORT on the same screen. Should my viewmodel look something like this: `public class OverallViewModel { public decimal OVERALLID { get; set; } public DateTime? EMAIL_SEND_DATE { get; set; } public string SENDER_ID { get; set; } public List Assets { get; set;} public List Ports { get; set;} }` – fkn_ace Nov 14 '16 at 02:38
  • No. `OverallViewModel` would contain a property `List Assets` and `AssetViewModel` would contain a property `List Ports` –  Nov 14 '16 at 02:42
  • Hi @StephenMuecke thanks for your help with this one. I went and read more about MVC, did some tutorials and re-did my solution using view models set up properly and everything works. Thanks for your time and patience. – fkn_ace Nov 29 '16 at 23:43

0 Answers0