8

We use the ASP.NET MVC's HTML helpers for generating forms, therefore names for form fields are also generated by those HTML helpers.

Whenever I load a partial view via AJAX into my current page (e.g. into a modal dialog), I run into problems if the model for this partial view contains a field that is named the same as some other field in the original view's model (because ASP.NET MVC generates the same IDs).

Is there any way to tell a partial view to render its fields with a specific prefix (in such a way, that later model binding understands those prefixed names)?

Currently we renamed fields in partial view models to "PartialDateOfBirth" to not interfere with the original page's model "DateOfBirth", but that sucks and doesn't work if you load the same partial view multiple times via AJAX into the page...

Any best practice solution for the problem?

D.R.
  • 20,268
  • 21
  • 102
  • 205
  • ModelBinder look for name attribute, not id. You should explain better the issue. Are you posting multiple forms? Post some code as well! – Fals Sep 18 '13 at 12:16
  • You're right, I replaced all "ID" with "name" in my post. I'm firing a single AJAX request which returns a new partial view based upon a model with properties named equally to some other properties in the original view's model. – D.R. Sep 18 '13 at 12:30
  • 1
    Yeah, you said the same as in the question! But, what are you doing with this data? How's you controller? The name is a issue if you are posting a list. What yours controller expects? If you can't provide any code I really cant give you any tip to solve this! – Fals Sep 18 '13 at 12:48
  • I think the answer can be found here: http://stackoverflow.com/questions/1488890/asp-net-mvc-partial-views-input-name-prefixes – Kris McGinnes Oct 15 '13 at 15:07
  • @KrisMcGinnes: This works only if you are still in the same request. Loading the page with AJAX, I would need to define the prefix via request parameter?! – D.R. Oct 15 '13 at 15:48
  • You should be able to create a custom ViewResult that does the same thing. You can use the partial's view name as the prefix. – Kris McGinnes Oct 16 '13 at 13:37

2 Answers2

3

Here's what I would do:

Save this as HtmlPrefixScopeExtensions.cs in your project

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

    internal class HtmlFieldPrefixScope : IDisposable
    {
        internal readonly TemplateInfo TemplateInfo;
        internal readonly string PreviousHtmlFieldPrefix;

        public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
        {
            TemplateInfo = templateInfo;
            PreviousHtmlFieldPrefix = TemplateInfo.HtmlFieldPrefix;
            TemplateInfo.HtmlFieldPrefix = htmlFieldPrefix;
        }

        public void Dispose()
        {
            TemplateInfo.HtmlFieldPrefix = PreviousHtmlFieldPrefix;
        }
    }
}

Then change your view from for example:

<div class="content">
    <div>
        @Html.EditorFor(model => model.Name)
    </div>
    <div>
        @Html.EditorFor(model => model.Population)
    </div>
</div>

To:

@using (Html.BeginPrefixScope("Country"))
{
    <div class="content">
        <div>
            @Html.EditorFor(model => model.Name)
        </div>
        <div>
            @Html.EditorFor(model => model.Population)
        </div>
    </div>
}

Last but not least, don't forget to either include a using statement in the view matching the location of HtmlPrefixScopeExtensions.cs, for example:

@using YourNamespace.Helpers

or add the correct namespace to Views/Web.config (this is by far the recommended option, you only do it once!):

<namespaces>
    <add namespace="System.Web.Helpers" />
    ...... 
   <add namespace="YourNamespace.Helpers" /> 
</namespaces>

Now: the name of fields will be for example "Country.Name"

You must then have matching name in your post e.g.:

[HttpPost]
public ActionResult SaveCountry(Country country)
{
    // save logic
    return View();
}

Credits: I stripped down Steve Sanderson's wonderful BeginCollectionItem class

joargp
  • 440
  • 3
  • 9
0

Create your Own Helper methods to pass a prefix with the ID , it is not a big job.

sino
  • 754
  • 1
  • 7
  • 22
  • It kinda is a big job to replace all ASP.NET MVC HTML helpers with our own implementations. Apart from the "little" caveats like updating or re-inventing the wheel. I don't think that this is an enterprise-ready solution to our problem. Thanks for your answer though. – D.R. Sep 18 '13 at 20:49
  • I did it myself, you just need to create helpers that you need , beside that you can just use the original helper but with encapsulating it with your method that will change the ID to have prefix. – sino Sep 19 '13 at 13:01
  • Have you open-sourced your wrapper / do you consider open-sourcing it? – D.R. Sep 19 '13 at 13:30