EditorFor() for a List of Complex Type (MVC)
Asked Answered
S

4

19

I'm trying to create an EditorFor() for a List of a Complex Type. Specifically the "Options" below should get displayed in a one multitext input where each option(string) is in a new line. However, I can only display one option in a textbox and not all options....

My View Model and Class:

public class ItemViewModel
{
    public int itemId { get; set; }

    [UIHint("Option")]
    public List<Option> Options { get; set; }
}
public class Option
{
    public string Text { get; set; }
}

My Editor Templates:

EditorTemplates\Item.cshtml

@model ItemViewModel
@Html.EditorFor(model => model.Options)

EditorTemplates\Option.cshtml

//Not sure how to dispay the options here
<textarea rows="4" cols="50">
Display Options
</textarea>

If I update my EditorTemplates to:

EditorTemplates\Item.cshtml

@model ItemViewModel
@Html.EditorFor(model => model.Options[0])

EditorTemplates\Option.cshtml

@Html.TextBoxFor(x => x.OptionText)

It will display the first option in a textbox. But, again what I'm trying to achieve is to display all options in a multitext input.

Any ideas?

Spurt answered 29/11, 2013 at 4:27 Comment(0)
F
17

You nearly have it.

In this EditorTemplates\Option.cshtml add the following:

@model IEnumerable<Option>
@foreach(var option in Model)
{
   @Html.TextBoxFor(m => option.Text)
}

Then call it in your view like this:

@Html.EditorFor(model => model.Options)

If you are not populating your options on the initial get, you will need to add this in your ItemViewModel class:

public class ItemViewModel
{
    public ItemViewModel()
    {
        Options = new List<Option>();
    }
    public int itemId { get; set; }

    [UIHint("Option")]
    public List<Option> Options { get; set; }
}

This constructor initializes the collection:

public ItemViewModel()
{
    Options = new List<Options>();
}
Figge answered 29/11, 2013 at 7:34 Comment(11)
I get "Object reference not set to an instance of an object." because Model is null.Spurt
You need to put your model reference in the view at the top i.e. @model ItemViewModelFigge
I'm not sure I understand...My option.cshtml view has model IEnumerable<Option> at the top. And Item.cshtml has model.ItemViewModel at the top.Spurt
You need to initialize the collection too, if you are not sending any out on the initial load. Please see my updated qutestion above. :DFigge
You do need to send the model back to the view like this in your controller: public ActionResult Index() { ItemViewModel model = new ItemViewModel(); model.itemId = 1; model.Options = new List<Option>() { new Option { Text = "one" }, new Option { Text = "two" } }; return View(model); }Figge
Still working on it :( I do bind that data using AJAX with Kendo UI Wrappers and it looks like there is a limitation on their end. Not sure what else to think.Spurt
not working for me - gives me an error as soon as I try to add @model IEnumerable<Option>Mild
@Mild Sorry this was back in 2013Figge
It throws NULL reference at (var option in Model). i know it's empty but I need to create items for this list so I need only display inputs for it. How to do it?Synsepalous
@Synsepalous I'd use DisplayTemplates instead for just displaying data i.e. DisplayTemplates\Option.cshtml then @Html.DisplayFor(model => model.Options)Figge
@Synsepalous Did you fix the issue? I have this problem right now.Lashondalashonde
N
23

Just create a view in Shared/EditorTemplates/Option.cshtml

@model Option

@Html.TextBoxFor(m => m.Text)

And call

@Html.EditorFor(model => model.Options)

EditorFor iterates over collection for you.

Nadia answered 12/2, 2016 at 19:17 Comment(0)
F
17

You nearly have it.

In this EditorTemplates\Option.cshtml add the following:

@model IEnumerable<Option>
@foreach(var option in Model)
{
   @Html.TextBoxFor(m => option.Text)
}

Then call it in your view like this:

@Html.EditorFor(model => model.Options)

If you are not populating your options on the initial get, you will need to add this in your ItemViewModel class:

public class ItemViewModel
{
    public ItemViewModel()
    {
        Options = new List<Option>();
    }
    public int itemId { get; set; }

    [UIHint("Option")]
    public List<Option> Options { get; set; }
}

This constructor initializes the collection:

public ItemViewModel()
{
    Options = new List<Options>();
}
Figge answered 29/11, 2013 at 7:34 Comment(11)
I get "Object reference not set to an instance of an object." because Model is null.Spurt
You need to put your model reference in the view at the top i.e. @model ItemViewModelFigge
I'm not sure I understand...My option.cshtml view has model IEnumerable<Option> at the top. And Item.cshtml has model.ItemViewModel at the top.Spurt
You need to initialize the collection too, if you are not sending any out on the initial load. Please see my updated qutestion above. :DFigge
You do need to send the model back to the view like this in your controller: public ActionResult Index() { ItemViewModel model = new ItemViewModel(); model.itemId = 1; model.Options = new List<Option>() { new Option { Text = "one" }, new Option { Text = "two" } }; return View(model); }Figge
Still working on it :( I do bind that data using AJAX with Kendo UI Wrappers and it looks like there is a limitation on their end. Not sure what else to think.Spurt
not working for me - gives me an error as soon as I try to add @model IEnumerable<Option>Mild
@Mild Sorry this was back in 2013Figge
It throws NULL reference at (var option in Model). i know it's empty but I need to create items for this list so I need only display inputs for it. How to do it?Synsepalous
@Synsepalous I'd use DisplayTemplates instead for just displaying data i.e. DisplayTemplates\Option.cshtml then @Html.DisplayFor(model => model.Options)Figge
@Synsepalous Did you fix the issue? I have this problem right now.Lashondalashonde
S
0

I bumped into the same issue and I have different solution but a bit similar with hutchonoid.

So the first part is same, modify the Option.cshtml like following:

@model IEnumerable<Option>
@foreach(var option in Model)
{
   @Html.TextBoxFor(m => option.Text)
}

And in Item.cshtml, I call the Option.cshtml using Html.Partial, like following:

@Html.Partial("Option", model:Model.Options)

And in my case, I don't have to modify the ItemViewModel class. Hopefully this can be alternative answer for this problem. Cheers!

Southbound answered 6/3, 2017 at 14:40 Comment(0)
P
-3

Using @hutchonoid's answer, you should call the template in view:

@Html.EditorFor(model => Model.Options)

instead of

@Html.EditorFor(model => model.Options)

and please be noted, the Option.cshtml template is in Views\Item\EditorTemplates\Option.cshtml or View\Shared\EditorTemplates\Option.cshtml

Paprika answered 29/4, 2015 at 9:26 Comment(1)
No, you don't want to use the Model property, you want to give MVC an expression from which it will be able to determine the path of the properties to bind the view model.Reclamation

© 2022 - 2024 — McMap. All rights reserved.