ASP.NET MVC 2 - ViewModel Prefix
Asked Answered
T

4

12

I want to use RenderPartial twice in my view with different models associated. The problem is that some properties are present in both models (nickname, password). They have no prefix, so even the id's or names are equal in the output. Now, if I have model errors for nickname or password, both fields get highlighted.

Main View:

<div>
    <% Html.RenderPartial("Register", Model.RegisterModel); %>
</div>
<div>
    <% Html.RenderPartial("Login", Model.LoginModel); %>
</div>

Login PartialView:

<% using (Html.BeginForm("Login", "Member")) { %>
<fieldset>
    <legend>Login</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>    
    <input type="submit" value="Login" />
</fieldset>
<% } %>

Register PartialView:

<% using (Html.BeginForm("Register", "Member")) { %>
<fieldset>
    <legend>Register</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Email) %>
        <%= Html.TextBoxFor(x => x.Email) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.PasswordRepeat) %>
        <%= Html.PasswordFor(x => x.PasswordRepeat) %>
    </p>
    <input type="submit" value="Register" />
</fieldset>
<% } %>

How can I change this?

Tomy answered 18/3, 2010 at 21:18 Comment(0)
T
8

Instead of using Html.RenderPartial you could use editor templates which will handle prefixes.

So in your main view:

<div>
    <%-- See below what does the second argument mean --%>
    <%= Html.EditorFor(x => x.RegisterModel, "RegisterModel") %>
</div>
<div>
    <%= Html.EditorFor(x => x.LoginModel, "LoginModel") %>
</div>

And then create a folder Views/Shared/EditorTemplates/RegisterModel.ascx (The name of this file is used in the EditorFor helper method). Also notice that this partial should be strongly typed to the type of the RegisterModel property:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Ns.Models.RegisterModel>" %>

<% using (Html.BeginForm("Register", "Member")) { %>
<fieldset>
    <legend>Register</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Email) %>
        <%= Html.TextBoxFor(x => x.Email) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.PasswordRepeat) %>
        <%= Html.PasswordFor(x => x.PasswordRepeat) %>
    </p>
    <input type="submit" value="Register" />
</fieldset>
<% } %>

You could define a different partial for the login model in Views/Shared/EditorTemplates/LoginModel.ascx

Trigonous answered 19/3, 2010 at 7:45 Comment(0)
U
12

If you can't do an EditorTemplate for some reason, you can do this in your View:

var dataDict = new ViewDataDictionary();
dataDict.TemplateInfo.HtmlFieldPrefix = "myPrefixHere";
Html.RenderPartial("myPartialViewName", myPartialViewModel, dataDict);

Lo and behold, all inputs in your PartialView will be prefixed.

Kudos to R0MANARMY for pointing this out.

Unpack answered 21/3, 2011 at 15:45 Comment(3)
and as a one liner: Html.RenderPartial("myPartialViewName", myPartialViewModel, new ViewDataDictionary(){ TemplateInfo = new TemplateInfo(){ HtmlFieldPrefix = "myPrefixHere"}})Masinissa
If I'm using RenderAction and that action in turn returns PartialView, neither PartialView nor RenderAction have a ViewDataDictionary overload that I can see. I was hoping it'd be an overload on return PartialView(. Any suggestions?Leery
NM, found out I can set it from inside the Partial, so I pass it into the ViewModel: @{ ViewData.TemplateInfo.HtmlFieldPrefix = Model.Id; } https://mcmap.net/q/102784/-asp-net-mvc3-add-a-htmlfieldprefix-when-calling-controller-partialviewLeery
T
8

Instead of using Html.RenderPartial you could use editor templates which will handle prefixes.

So in your main view:

<div>
    <%-- See below what does the second argument mean --%>
    <%= Html.EditorFor(x => x.RegisterModel, "RegisterModel") %>
</div>
<div>
    <%= Html.EditorFor(x => x.LoginModel, "LoginModel") %>
</div>

And then create a folder Views/Shared/EditorTemplates/RegisterModel.ascx (The name of this file is used in the EditorFor helper method). Also notice that this partial should be strongly typed to the type of the RegisterModel property:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Ns.Models.RegisterModel>" %>

<% using (Html.BeginForm("Register", "Member")) { %>
<fieldset>
    <legend>Register</legend>
    <p>
        <%= Html.LabelFor(x => x.Nickname) %>
        <%= Html.TextBoxFor(x => x.Nickname) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Email) %>
        <%= Html.TextBoxFor(x => x.Email) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.Password) %>
        <%= Html.PasswordFor(x => x.Password) %>
    </p>
    <p>
        <%= Html.LabelFor(x => x.PasswordRepeat) %>
        <%= Html.PasswordFor(x => x.PasswordRepeat) %>
    </p>
    <input type="submit" value="Register" />
</fieldset>
<% } %>

You could define a different partial for the login model in Views/Shared/EditorTemplates/LoginModel.ascx

Trigonous answered 19/3, 2010 at 7:45 Comment(0)
T
0

Looks like there's an overload for TextBoxFor that allows you to specify extra HTML attributes. It isn't an ideal solution, but it should let you change the id (and possibly name?) of the rendered textboxes. Of course changing the name would probably screw things up when you try to post the form.

Titanic answered 19/3, 2010 at 6:6 Comment(0)
E
0

First of all, you could use Html.TextBox("input form name", ...) and set the name to whatever you wish. There's a bigger issue how would you provide a prefix on Html.RenderPartial() level? You are already providing a model instance. So without changing their view models, there's just one more possibility: to write your own overloads for RenderPartial() that would take the prefix and pass it on to others.

Check this one out. Someone's written a whole bunch of overloads that support setting prefixes. TextBoxFor rendering to HTML with prefix on the ID attribute

If any is missing you can see the pattern how to extend these with additional ones you may need.

Evulsion answered 19/3, 2010 at 6:49 Comment(1)
You don't need to write your own overload for RenderPartial, there's already an overload that let's you redefine what the ViewData collection is. You can just add your prefix in there and have your model look for it. See: msdn.microsoft.com/en-us/library/dd470827.aspxTitanic

© 2022 - 2024 — McMap. All rights reserved.