Lets say you want to build an application where you add friends and hobbies to your profile using Ajax. The approach I would take is to include the markup for the friend and hobby forms as part of the profile page markup to make the UI more responsive when the overlays are shown. By doing this you could end up with duplicate element names and ids which can break UI behaviour or if the elements are in a form will not bind correctly when you submit it.
Models:
Here is the view model for the profile page, note that I added the friend and hobby edit models as properties, this is not required but my view is that it important to make it clear that the view for the profile page depends on the friend and hobby models.
public class ProfileViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
public FriendModel FriendModel { get; set; }
public HobbyModel HobbyModel { get; set; }
}
public class HobbyModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class FriendModel
{
public int Id { get; set; }
public string Name { get; set; }
public string EmailAddress { get; set; }
}
Views with no bind prefix
When you render the partial views with no prefix the Name elements will have the same name and id, creating duplicate elements in the markup.
<div id="friendOverlay" class="overlay">
@Html.Partial("_AddFriend", Model.FriendModel)
</div>
<div id="hobbyOverlay" class="overlay">
@Html.Partial("_AddHobby", Model.FriendModel)
</div>
Html rendered with no bind prefix
Note the id and name attributes are the same for both input elements.
FriendModel:
<div class="editor-field">
<input class="text-box single-line" id="Name" name="Name" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
</div>
HobbyModel:
<div class="editor-field">
<input class="text-box single-line" id="Name" name="Name" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Name" data-valmsg-replace="true"></span>
</div>
Views with bind prefix
Note the HtmlFieldPrefix is a property on the TemplateInfo property of the ViewDataDictionary that is passed to the Partial method.
The code is not the most elegant, you could create a html helper to improve this.
<div id="friendOverlay" class="overlay">
@Html.Partial("_AddFriend", Model.FriendModel, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "friend" } })
</div>
<div id="hobbyOverlay" class="overlay">
@Html.Partial("_AddHobby", Model.HobbyModel, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "hobby" } })
</div>
Html rendered with bind prefix
Note the id and name attributes of the input elements are now prepended with the prefix specified.
FriendModel:
<div class="editor-field">
<input class="text-box single-line" id="friend_Name" name="friend.Name" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="friend.Name" data-valmsg-replace="true"></span>
</div>
HobbyModel:
<div class="editor-field">
<input class="text-box single-line" id="hobby_Name" name="hobby.Name" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="hobby.Name" data-valmsg-replace="true"></span>
</div>
Binding the form to the model:
The final change we need to make is to tell the model binder to use the relevant prefix when binding the forms data to the model on post back. We do this by simply adding the BindAttribute to the property of the action we are posting to.
public ActionResult AddFriend([Bind(Prefix = "friend")] FriendModel model)
{
// code to process the model
// code to return result
}
public ActionResult AddHobby([Bind(Prefix = "hobby")]HobbyModel model)
{
// code to process the model
// code to return result
}