-1

I want to pass a List of VoedingBindingModel to my controller by using an Editor Template, however I only receive the first entry of the List in the Controller, never all the entries.

The Controller:

public ActionResult Create()
    {
        ViewBag.fk_customVoedingId = new SelectList(customvoeding.GetAllCustomvoeding(), "customVoedingId", "customVoedingNaam");
        ViewBag.fk_standaardVoedingId = new SelectList(standaardvoeding.GetAllStandaardvoeding(), "standaardVoedingId", "standaardVoedingNaam");

        return View();
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "Id,Datum,Tijd,VoedingCollection")]AgendaBindingModel agendaBindingModel)
    { 
        //Do something
    }

The Model:

public class AgendaBindingModel
    {
      [Required]
       public List<VoedingBindingModel> VoedingCollection { get; set; }
       //More properties
    }

The View:

@using Website.Models
@model AgendaBindingModel

@using (Html.BeginForm())
{
@Html.AntiForgeryToken()

<div class="form-horizontal">
    <h4>agenda</h4>
    <hr />
    @Html.ValidationSummary(true, "", new { @class = "text-danger" })
    <div class="form-group">
        @Html.LabelFor(model => model.Datum, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.TextBoxFor(m => m.Datum, "{0:dd-MM-yyyy}", new { @class = "form-control-datepicker", placeholder = "DD-MM-YYYY", maxlength = "10" })

            @Html.ValidationMessageFor(model => model.Datum, "", new { @class = "text-danger" })
        </div>
    </div>

    <div class="form-group">
        @Html.LabelFor(model => model.Tijd, htmlAttributes: new { @class = "control-label col-md-2" })
        <div class="col-md-10">
            @Html.EditorFor(model => model.Tijd, "{0:hh:mm}", new { htmlAttributes = new { @class = "form-control-timepicker", placeholder = "hh:mm", maxlength = "5" } })
            @Html.ValidationMessageFor(model => model.Tijd, "", new { @class = "text-danger" })
        </div>
    </div>
    <div id="CreateVoedingDiv0">
        @Html.EditorFor(x => x.VoedingCollection[0])
    </div>
    <div id="CreateVoedingDiv1"hidden>
        @Html.EditorFor(x => x.VoedingCollection[1])
    </div>
    <div id="CreateVoedingDiv2"hidden>
        @Html.EditorFor(x => x.VoedingCollection[2])
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input value="Add" class="btn btn-default" onclick="ShowVoeding()" /> <input value="Remove" class="btn btn-default" onclick="HideVoeding()" />
        </div>
    </div>

    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
</div>
}

<div>
@Html.ActionLink("Back to List", "Index")
</div>

<script>
var count = 1;

function ShowVoeding()
{
    if (document.getElementById("CreateVoedingDiv" + count).hidden == true)
    {
        document.getElementById("CreateVoedingDiv" + count).hidden = false;
        count++;
    }
}
function HideVoeding()
{
    count = count - 1;
    if (document.getElementById("CreateVoedingDiv" + count).hidden == false)    {
        document.getElementById("CreateVoedingDiv" + count).hidden = true;            
    }
}
</script>

Partial class:

(customvoeding and standaardvoeding do the same thing, only customvoeding returns a collection of customvoeding and standaardvoeding returns a collection of standaardvoeding.

public partial class customvoeding
{
    private static foodtrackerEntities1 db = new foodtrackerEntities1();

    public static List<customvoeding> GetAllCustomvoeding()
    {
        db.Configuration.LazyLoadingEnabled = false;
        return db.customvoeding.ToList();
    }
}
DaGrooveNL
  • 177
  • 1
  • 1
  • 10
  • Are you able to see the other 2 items in your view (rendered page) ? I see you have some invalid html in the 2 div's – Shyju Aug 01 '16 at 19:57
  • I use Javascript to show the other divs by putting the 'hidden' attribute to false: var count = 1; function ShowVoeding() { if (document.getElementById("CreateVoedingDiv" + count).hidden == true) { document.getElementById("CreateVoedingDiv" + count).hidden = false; count++; } } – DaGrooveNL Aug 01 '16 at 19:58
  • What you mean you use javascript to show. You need to share the relevant code in the question. Otherwise it is hard for others to understand – Shyju Aug 01 '16 at 19:59
  • I added it. When trying the suggestion from @Jesse Johnson, I made a new
    without hidden and it is still the same problem.
    – DaGrooveNL Aug 01 '16 at 20:34
  • Can anyone please help me out? :( – DaGrooveNL Aug 03 '16 at 12:37

4 Answers4

0

Your second and third html are broken.

<div id="CreateVoedingDiv2"hidden>

remove hidden

Pang
  • 9,564
  • 146
  • 81
  • 122
  • It does not matter if I have hidden there, the data does not get send to my Controller – DaGrooveNL Aug 01 '16 at 20:05
  • I think I am using the EditorTemplate the wrong way. The thing is, I do not know how many VoedingCollections I want to show, so I want the user to be able to add new collections on the fly. When using @Html.EditorFor(x => x.VoedingCollection) I always get 1, but I want the user to be able to add more. so I did @Html.EditorFor(x => x.VoedingCollection[0]) and @Html.EditorFor(x => x.VoedingCollection[1]), etc. – DaGrooveNL Aug 01 '16 at 20:08
  • He said I have invalid Html, while it is not invalid. – DaGrooveNL Aug 03 '16 at 19:59
0

You don't seem to be initializing the model and passing it to the view. In the action methods of your controller try adding:

var viewModel = new AgendaBindingModel();
viewModel.VoedingCollection = // TODO: Fill the list from your data source

return View(viewModel );
Jesse Johnson
  • 1,638
  • 15
  • 25
  • When I used your solution, I still get 1 back and not more. It always passes the first one, the rest gets ignored. – DaGrooveNL Aug 01 '16 at 20:18
  • The issue may be in your GetAllCustomvoeding() and/or GetAllStandaardvoeding() methods. Are you able to post the code for those methods? – Jesse Johnson Aug 01 '16 at 20:25
  • I highly doubt that, but I added them to the question. – DaGrooveNL Aug 01 '16 at 20:31
  • By doing "@Html.EditorFor(x => x.VoedingCollection[0])" I effectively create a new instance at index 0. This is also the case for index 1, 2, etc. However, I found out that if I use a template at more than one line, I will only receive the first entry of my collection. If I do not specify a template, then I will receive all the entries. But ofcourse, I want to specify a template for the markup and functions. – DaGrooveNL Aug 03 '16 at 20:02
0

Try like this. I could not test, but if you like we can advance is this way:

To show all items:

<div id="group">
@for(int i = 0; i < AgendaBindingModel.VoedingCollection.Count; i++)
{
    @Html.EditorFor(x => x.VoedingCollection[i])
}
To add new item:
<button onclick=newItem() >+</button>
</div>


<script>
function newItem(){
    var div = document.createElement('div');
    div.id = CreateNewItem;
    div.innerHTML = '@Html.EditorFor(x => x.VoedingCollection[i])';
    document.body.appendChild(div);
}
</script>
  • Yes, but the problem is not showing the items on the page, it is getting the items back to the controller. I always only get the first result. – DaGrooveNL Aug 03 '16 at 19:07
-1

I found out what was preventing me from receiving more than one result:

You can NOT use @Html.EditorFor template for more than 1 value when you specify a template. It does not matter if you use different models or different templates, it just simply does not work.

To fix it, you have to use 'Html.BeginCollectionItem' library, which can be found here.

DaGrooveNL
  • 177
  • 1
  • 1
  • 10
  • For more information, view the screenshots I took: http://imgur.com/a/EhFUL – DaGrooveNL Aug 03 '16 at 19:36
  • Of course you can use `EditorFor()` _for more than 1 value_. The correct usage is just `@Html.EditorFor(x => x.VoedingCollection)` and the method will correctly generate the html for each property of each item in the collection. –  Aug 04 '16 at 00:47
  • But its really not clear what your trying to do with your code, in particular your `hidden` elements and your `Add` button. If your trying to dynamically add/remove items to for a collection property, then you on the wrong track (in which case refer the answers [here](http://stackoverflow.com/questions/29161481/post-a-form-array-without-successful/29161796#29161796) and [here](http://stackoverflow.com/questions/28019793/submit-same-partial-view-called-multiple-times-data-to-controller/28081308#28081308) –  Aug 04 '16 at 00:47
  • When using the EditorFor _for a collection_ it locks up after te first index of the initial collection and does not submit anything else after the first collection. This is also the case when using the EditorFor for a single sub-model everytime (so not for a collection). Of course your suggested answer might work (I will try it and post back). But to me it seems _wrong_ that Razor Views, out-of-the-box, cannot handle a collection of sub-models. – DaGrooveNL Aug 04 '16 at 13:14
  • Using the 'Html.BeginCollectionItem' solved my issue. Thank you sooooo much! However, I am curious as to why Razor Views cannot do this by default, if you know why, would you care to explain it to me? – DaGrooveNL Aug 04 '16 at 15:13
  • Razor view CAN handle a collection of sub models. And you do NOT have to use `BeginCollectionItem()` (although you can). It still not even clear what you trying to do, and why in the world you have `@Html.EditorFor(x => x.VoedingCollection[0])`, `@Html.EditorFor(x => x.VoedingCollection[1])` etc with the last 2 items hidden. –  Aug 04 '16 at 22:56
  • I am making a form where a user can add items (sub-models) to the main model. I want to restrict the user so that he can not make too much of sub-models and I want to execute particular javascript on those sub-models which I find easier to implement doing it this way. I am aware that it is not perse best-practice. You also mention Razor being able to handle a collection of sub models. I know it can handle them when displaying them, but on postback to the controller, I noticed that those sub-models get lost. So I came here to ask how to solve that. – DaGrooveNL Aug 05 '16 at 12:53