Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does Html.EditorFor(...) know the index and item of a loop?

Suppose you have a model like so:

class Foo
{
    public int A {get; set;}
    public int B {get; set;}
}

class SomeModel
{
    public List<Foo> Foos { get; set; }

}

In a razor view on the ASP.NET mvc framework, you can do the following:

@model SomeModel

@for(int i = 0; i < Model.Foos.Count; ++i)
{
   Html.EditorFor(x => x.Foos[i]);
}

And the razor engine will happily spit out the correct html containing the index, and will call the editor template with the correct indexed instance.

The EditorFor method is a static extension method with the signature

public static MvcHtmlString EditorFor<TModel, TValue>(
this HtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression
)

From the signature, it is clear that it is simply taking an expression, and the only context is coming from the HtmlHelper instance.

I have done very limited Expression tree processing, but from what I have seen, I can't see any way that this static method could know the information that it is somehow magically getting.

How can the EditorFor method figure out the index for generating html names and get the correct instance to pass to the editor template?

like image 401
Nathan Avatar asked Feb 02 '13 02:02

Nathan


People also ask

What are the advantages of the HTML EditorFor () method?

The advantages of EditorFor is that your code is not tied to an <input type="text" . So if you decide to change something to the aspect of how your textboxes are rendered like wrapping them in a div you could simply write a custom editor template ( ~/Views/Shared/EditorTemplates/string.

What is HTML EditorFor?

The Html. Editor() or Html. EditorFor() extension methods generate HTML elements based on the data type of the model object's property. The following table list the data types and releted HTML elements: DataType.

How do I add an EditorFor style?

EditorFor does not allow for styling as there are no parameters for additional attributes. The reason for this is because the EditorFor doesn't always generate a single element as it can be overridden. To style a specific type of element you need to use the specific editor you want to use.


Video Answer


1 Answers

You are passing it an expression, not the value of x.Foos[i]. MVC then evaluates that expression and figures out that you gave it a collection with an index. You would get the same result if you removed your entire loop and did:

Html.EditorFor(x => x.Foos)

MVC will then automatically render the editor template for all elements of the collection and generate proper names.

You can read more about how MVC handles display/editor templates here: Link

EDIT : To see this in action, here's a random piece of code I scribbled:

List<string> list = new List<string>() { "A", "B", "C" };
var tester = new ExpressionTester<List<string>>(list);
var item = tester.Foo(p => p[0]);

You'll also need this class:

public class ExpressionTester<TModel>
{
    private TModel _list;
    public ExpressionTester(TModel list)
    {
        _list = list;
    }

    public TValue Foo<TValue>(Expression<Func<TModel, TValue>> expression)
    {
        var func = expression.Compile();
        return func.Invoke(_list);
    }
}

Stick a breakpoint in Foo() and look at the parameter expression in debug. You'll find under Body -> Arguments the index you passed with the expression. Under Body -> Method you'll see that it is in fact a generic list.

like image 167
Artless Avatar answered Oct 12 '22 12:10

Artless