0

In a C# MVC WebApp, I have a CallDetailViewModel that contains a list of CallerViewModels and it has a List of PhoneNumberViewModels. I'm trying to link them all together properly.

Not shown here, but I am also trying to both load existing values and add new/remove values, so I don't know what's being sent to the controller ahead of time.

I've tried following this 2012 guide that has a very similar problem I found online, but no luck yet: Code Project Article
I also tried moving the List of PhoneNumberViewModels to the CallDetailViewModel, and while I was able to pass the phone numbers to my controller I didn't have a clear way to link them to the appropriate CallerViewModel.

I want to be able to add and remove PhoneNumbers from Callers and Callers from the CallDetail.
I've removed my buttons and AJAX regarding those for now, as it's not my main problem.

Here are my simplified ViewModels and Views:

ViewModels

CallDetailViewModel.cs

namespace PROJECT_NAME.ViewModels
{
    public class CallDetailsViewModel
    {
        public Guid Id { get; set; }

        public string EnteredByEmail { get; set; }

        public List<CallerViewModel> CallerViewModels { get; set; }
    }
}

CallerViewModel.cs

namespace PROJECT_NAME.ViewModels
{
    public class CallerViewModel
    {
        public Guid Id { get; set; }

        public string FirstName { get; set; }

        public List<PhoneNumberViewModel> PhoneNumberViewModels { get; set; }
    }
}

PhoneNumberViewModel.cs

namespace PROJECT_NAME.ViewModels
{
    public class PhoneNumberViewModel
    {
        public Guid Id { get; set; }

        public string Number { get; set; }
    }
}

Views

CallDetail.cshtml

@using PROJECT_NAME.ViewModels
@model CallDetailsViewModel

<div class="container">
    @using (Html.BeginForm("SubmitCallDetails", "Home", FormMethod.Post))
    {
        @Html.AntiForgeryToken()
        @Html.HiddenFor(m => m.Id)
        <div class="well">
            @* Call Details *@
            <div class="row">
                <fieldset">
                    <legend>Call Details</legend>
                </fieldset>
                <div class="form-group">
                    @Html.LabelFor(m => m.EnteredByEmail, new {@class = "control-label"})
                    @Html.TextBoxFor(m => m.EnteredByEmail, new {@class = "form-control"})
                </div>
            </div>
            @* Caller Details *@
            <div class="row">
                <fieldset>
                    <legend>Callers</legend>
                </fieldset>
            </div>
            @* Render each existing caller. Each caller gets it's own well to create a visual seperation between them. *@
            @if (Model.CallerViewModels.Count == 0)
            {
                <div class="well">
                    @{ Html.RenderPartial("_PartialCallerInfo", new CallerViewModel());}
                </div>
            }
            @foreach (var callerViewModel in Model.CallerViewModels)
            {
                <div class="well">
                    @{ Html.RenderPartial("_PartialCallerInfo", callerViewModel); }
                </div>
            }
        </div>
        <div class="row">
            <div class="form-group">
                <button class="btn btn-danger" type="reset">Reset</button>
            </div>
            <div class="form-group">
                <button class="btn btn-primary" type="submit">Submit</button>
            </div>
        </div>
    }
</div>

_PartialCallerInfo.cshtml

@using PROJECT_NAME.ViewModels
@model CallerViewModel

@using (Html.BeginCollectionItem("CallerViewModels"))
{
    <div class="row">
        @Html.HiddenFor(m => m.Id)
        <div class="form-group">
            @Html.LabelFor(m => m.FirstName, new { @class = "control-label" })
            @Html.TextBoxFor(m => m.FirstName, new { @class = "form-control"})
        </div>
    </div>
    @if (Model.PhoneNumberViewModels.Count == 0)
    {
        @{ Html.RenderPartial("_PartialCallerPhoneNumber", new PhoneNumberViewModel());}
    }
    @foreach (var phoneNumberViewModel in Model.PhoneNumberViewModels)
    {
        @{ Html.RenderPartial("_PartialCallerPhoneNumber", phoneNumberViewModel); }
    }
}

_PartialCallerPhoneNumber.cshtml

@using PROJECT_NAME.ViewModels
@model PhoneNumberViewModel

@using (Html.BeginCollectionItem("PhoneNumberViewModels"))
{
    <div class="row">
        @Html.HiddenFor(m => m.Id)
        <div class="form-group">
            @Html.LabelFor(m => m.Number, new { @class = "control-label" })
            @Html.TextBoxFor(m => m.Number, new { @class = "form-control"})
        </div>
    </div>
}
Ryan Taite
  • 789
  • 12
  • 37
  • The `BeginCollectionItem()` method does not support nested collections. An alternative is to use the `HtmlHelper` methods described in [this article](http://www.joe-stevens.com/2011/06/06/editing-and-binding-nested-lists-with-asp-net-mvc-2/). Or if you want a pure client side solution, refer [this DotNetFiddle](https://dotnetfiddle.net/I8q07y) –  Dec 20 '17 at 21:10
  • Sorry for such a long delay in my reply, I've been trying to implement in my code the examples you linked to. I ran into obstacles with both implementations, unfortunately. In the article, where he makes a "small amendment to the HtmlPrefixScopeExtensions BeginCollection method", I start to get errors stating method ambiguity (and I was having some editor templates not appearing correctly as well like how it showed in the previous steps), and the pure client version I honestly don't remember what wall I hit there before switching to the article. – Ryan Taite Dec 21 '17 at 21:10
  • I really appreciate the help, but with my Xmas vacation coming I won't be able to return to this for a little over a week at the earliest. If I'm able to come back to this and get to a solution I'll let you know. Thanks again! – Ryan Taite Dec 21 '17 at 21:12

0 Answers0