1

I think I have read every post on SO about this, but still don't know why the following custom Editor Template, strongly typed to a model, is not displaying at all. It is definitely executing the Recipient.cshtml Template Editor because I put a breakpoint on the TextboxFor line and that line is hit twice, once for each Recipient Name that is set in the Controller, but when it's done, the page display is blank for the model items (submit button on main page still displays). If I uncomment the RenderPartial line, and comment out EditorFor, then the recipients display just fine, but of course the IDs are not properly enumerated so I can't post. As far as I understand I have to use the Editor Template in order for the IDs to properly enumerate and allow for the Recipients model to post.

Can anyone see what I might be doing wrong or suggest an alternative way to render this list with the correct IDs?

Thanks!

Models:

[DataContract(Name = "recipient")]
public class Recipient
{
    [Display(Name = "Email")]
    public string eMail { get; set; }

    [Display()]
    public string Name { get; set; }
}

Controller:

[HttpGet]
public ActionResult CreateRecipients()
{
    var recp = new List<Recipient>();
    recp.Add(new Recipient());
    recp[0].Name = "VTest";
    recp[0].eMail = "vgtest@test.com";
    recp.Add(new Recipient());
    recp[1].Name = "GTest";
    recp[1].eMail = "vgtest2@test.com";

    return this.View(recp);
}

EditorTemplate:

@model Recipient
    <div class="row">
        <div class="col-md-4">
            <div class="row">
                <div class="col-xs-12 custom-label-left-condensed">
                    @Html.LabelFor(model => Model.Name)
                </div>
            </div>
            <div class="row">
                <div class="col-xs-12">
                    @Html.TextBoxFor(model => Model.Name)
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="row">
                <div class="col-xs-12 custom-label-left-condensed">
                    @Html.LabelFor(model => Model.eMail)
                </div>
            </div>
            <div class="row">
                <div class="col-xs-12">
                    @Html.EditorFor(model => Model.eMail, new { htmlAttributes = new { @class = "emailField" } })
                </div>
            </div>
        </div>
    </div>

View:

@model List<Recipient>

<div class="panel panel-default">
    <div class="panel-heading hidden-xs">
        <h4>@ViewBag.Title</h4>
    </div>

    @using (Html.BeginForm())
    {
        <div class="container-fluid panel-body">
            <div id="myData">
                @if (Model != null)
                {
                    for (int i = 0; i < Model.Count(); i++)
                    {
                        Html.EditorFor(m => Model[i], "Recipient", "Recipient[" + i + "]" );
                        //Html.RenderPartial("EditorTemplates/Recipient", Model[i]);
                    }
                }
            </div>
            <div class="row">
                <div class="col-xs-4 col-md-3 text-right">
                    <input id="cmdSubmit" type="submit" value="Create" class="btn btn-default btn-sm" />
                </div>
            </div>
        </div>
    }
</div>
VG1
  • 185
  • 9
  • Is it `Recipient` or `Recipients`? You use both in your code, but those are two totally different class names. – Chris Pratt Oct 03 '16 at 16:46
  • Under Models I defined Recipient, singular, and then the plural as Recipients : List. The view uses the plural and a Model for loop, and inside the for loop, I call the EditorTemplate which is singular. – VG1 Oct 03 '16 at 16:50
  • I see. That's actually not a great idea, though. Not only does it make your code more difficult to read, but it also creates a point of failure. How often are you going to autocomplete with the wrong one in Visual Studio? I would imagine quite often. Also, it's actually pretty important in a strongly typed language like C# to know what *kind* of collection you're dealing with. `Recipients` could be any of `List`, `ICollection`, `IEnumerable`, `Recipient[]`, etc. Having to dig into the class to figure that out is a code smell. – Chris Pratt Oct 03 '16 at 16:57
  • If you created `Recipients` merely so you could bind an editor template to it, you should be aware that the default behavior of `EditorFor`, when passed a collection of something is to render the editor template of that something for each item in the collection. So, for example, `@Html.EditorFor(m => m.Recipients)`, where `Model.Recipients` is `List` is functionally equivalent to iterating over `Recipients` and calling `Html.EditorFor` for each item. – Chris Pratt Oct 03 '16 at 17:02
  • I understand the objection to the name, although I believe that is a red herring. Nevertheless, I updated my code to use List instead - Recipients (plural) no longer exists. After making that change, I get the same problem. The breakpoint clearly shows the data in the Editor Template, but the page still renders blank. – VG1 Oct 03 '16 at 17:13
  • As for EditorFor, I want the Editor Template to be singular so that I can later add JS code to dynamically add a new one by loading that template and appending it to the myData div. All of that works fine & dandy if I use RenderPartial instead of EditorFor. But then I don't have unique IDs so I can't post the data back to the controller. So I have to use EditorFor and a template to get unique IDs right? – VG1 Oct 03 '16 at 17:15
  • In the main view its just `@Html.EditorFor(m => m)` - The `EditorFor()` method accepts `IEnumerable` and no loop (or `if` block) is required. And using JS to dynamically add a new item based on your template will not work (and it has nothing to do with the `id` attributes - its the `name` attribute and the indexers that matter). Refer [this answer](http://stackoverflow.com/questions/39834406/strongly-typed-editor-template-not-displaying) for dynamically adding and deleting collection items. And I am assuming the template is `/Views/Shared/EditorTemplates.Recipient.cshtml` –  Oct 03 '16 at 21:50
  • Stephen, I'm not sure I understand you. You say using JS to dynamically add a new item will not work, but if I use that exact same template as a partial view instead, that part does work. I understand that EditorFor can do the looping for me, but that's optional right? I've seen other examples where people put the EditorFor inside the loop. The main thing I'm trying to figure out with this post is why the template is not displaying despite seeing it execute with breakpoints. Lastly, the "this answer" link you left is a link to this current thread. – VG1 Oct 04 '16 at 12:13
  • No it will not work unless your adding elements with the correct `name` attribute. In order to bind to a collection, the name attributes of the controls your generating must contain the correct indexers. Sorry about the link - its [this one](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308). And you should never need to use an `EditorTemplate` inside a loop. And in anycase the 3rd parameter (`"Recipient[" + i + "]"`) is `AdditionalViewData` which you never access in the template, so it makes no sense. –  Oct 04 '16 at 23:48
  • I removed the third parameter, I've tried the EditorTemplate inside a loop, outside the loop, and it still won't render. At this point I don't care about adding another record with JS, I just want the existing data to display. Can anyone tell me why this doesn't display at all? Thanks – VG1 Oct 12 '16 at 12:59

1 Answers1

0

use

List<recp> recps = new List<Recipients>();
recp orecp = new recp();

orecp.Name = "VTest";
orecp.eMail = "vgtest@test.com";
recps.add(orecp);

orecp = new recp();
orecp.Name = "GTest";
orecp.eMail = "vgtest2@test.com";
recps.add(orecp);

return this.View(recps);
Emil
  • 281
  • 1
  • 2
  • 11
  • Thanks Emil, I have updated my controller, but that made no difference. The Recipients are definitely populated. When I am debugging and hit the breakpoint at "@Html.TextBoxFor(model => Model.Name)" the name shows up just fine for both records. Yet nothing is rendered to the page. – VG1 Oct 03 '16 at 16:39