Forcing EditorFor to prefix input items on view with Class Name?
Asked Answered
S

2

7

I have an EditorFor:

<%: Html.EditorFor(model => model.Client, "ClientTemplate", new { editing = false })%>

This will bind coming down to the view fine (as expected) but will not bind bind back when the model gets posted. This is due to the form id's not being prefixed with "Client."

Usually in this situation i just pass in model and then bind the inputs to model.Client.PropertyName in the Template but this is not an option in this case as the template is used on two different viewmodels (that have client on).

Any suggestions on getting this to bind properly?

Many thanks, Kohan.


Addendum

It seems this was a misunderstanding on my part, the issue as i now understand it is that fluentHtml does not work inside EditorFor Templates. (The same goes for this fix, which as it turns out was not needed as EditorFor will prefix for me automatically if i replace the fluentHtml with normal mvc html helpers)

Shufu answered 5/1, 2011 at 16:43 Comment(0)
B
11

Try something like:

<% Html.BeginHtmlFieldPrefixScope("Client") {
  Html.EditorFor(model => model.Client, "ClientTemplate", new { editing = false });
<% } %>

Every field you make with EditorFor, LabelFor and the likes will be prefixed.

EDIT: Here's the extension method I'm using, sorry!

public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
{
  return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}

...and the class...

private class HtmlFieldPrefixScope : IDisposable
{
    private readonly TemplateInfo templateInfo;
    private readonly string previousHtmlFieldPrefix;

    public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
    {
        this.templateInfo = templateInfo;

        previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
        templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
    }

    public void Dispose()
    {
        templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
    }
}

See the link mentioned by Kohan in the comments below.

Beak answered 5/1, 2011 at 16:51 Comment(4)
Are you referring to the custom extension method as mentioned on this question? #2759667Shufu
@Kohan: Exactly, didn't knew where the code came from! Thanks!Bosley
Also there's a mistake in your example it should be: <% using (Html.BeginHtmlFieldPrefixScope("Client")) { %> Html.EditorFor(model => model.Client, "ClientTemplate", new { editing = false }); <% } %> But many thanks anyway, i should hopefully get there now.Shufu
Sorry, seems this was all for naught. EditorFor's do this automatically, but it was the fluentHtml in my template that was messing it up.Shufu
A
6

MVC3 HTML Name Clashing

Cutting and pasting that does not work in MVC3. To get the extension to work, I had to create a class file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace incMvcSite.Classes {
    public static class HtmlPrefixScopeExtensions {
        public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix) {
            return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
        }

        private class HtmlFieldPrefixScope : IDisposable {
            private readonly TemplateInfo templateInfo;
            private readonly string previousHtmlFieldPrefix;

            public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix) {
                this.templateInfo = templateInfo;

                previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
                templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
            }

            public void Dispose() {
                templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
            }
        }
    }
}

In the Razor (.cshtml) file, I added the following:

@using incMvcSite.Classes
@using(Html.BeginHtmlFieldPrefixScope("Permission")) {
    <fieldset>
        <legend>Permission</legend>

        // The Html.EditorFor's would go here...
    </fieldset>
}

Notice the using to bring me extension class into scope. That allows the second using line to work.

Now the problem is that when posting back, the object is not updated. In my controller, I used a second parameter to specify my prefix:

TryUpdateModel(modelUser.Permission, "Permission");

This added the prefix to all field in the HTML, and the TryUpdateModel loaded the object with prefixed control names. Now you can properly namespace your controls for embedded edit lists, and for partial views of models with the same property names.

Ardenardency answered 30/7, 2011 at 21:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.