Maybe that’s not exactly the solution i need, but this is what i want to do:
i have a company registration form, and each company needs an administrative user. an administrative user may manage multiple companies, so in the company registration form, you can choose an existing user from a dropdown.
the company view model looks something like this:
public class CompanyViewModel {
[Required]
public string Name { get; set; }
// other properties...
public UserViewModel Administrator { get; set; }
public IEnumerable<UserViewModel> AvailableUsers { get; set; }
}
and the user view model looks like this:
public class UserViewModel {
[Required]
public string UserName { get; set; }
[Required]
public string Password { get; set; }
// other properties...
}
in the company registration view:
<div><input type="radiobutton" name="chooseuser" id="existing"/>Choose an Existing User:</div.
<div>@Html.DropDownListFor(m => m.Administrator.Id, Model.AvailableUsers.Select(u => new SelectListItem { Text = string.Format("{0} - {1} {2}", u.UserName, u.FirstName, u.LastName), Value = u.Id.ToString() }), "<Choose existing user>", new { id = "existingusers" })
</div>
<div><input type="radiobutton" name="chooseuser" id="createnew"/>Create a new User:</div>
<div><label>Username:</label> @Html.EditorFor(m => m.Administrator.UserName)</div>
Through javascript, based on radio button selection, the dropdown list is disabled and the new user form shown, or the new user form is hidden and the dropdown list is enabled.
The problem is in the controller Save action after you press save, ModelState.IsValid is false if an existing user is chosen and no data is filled in on the form. If the user chooses to enter a new user, validation succeeds.
What is the best way to handle this?
One option is to load all data for all users into data structures in javascript, and when the value changes on the existing user dropdown, the hidden “create new” form fields can be populated. But this seems lame since passwords would be sitting the html in plain text. i can get fancier and use ajax for a “create new” form and populate a user id on the original form once the new user is saved, but i’d like to keep it all in one form if possible.
Seems liked i’d ideally be able to load the existing user data from the db and populate the model state in the controller Save action, but writing this code manually (even using reflection) seems sloppy. It would be nice if there was a built in method to do this.
Any ideas?
Thanks.
That’s a typical scenario which perfectly illustrates the limitations of declarative validation (a.k.a Data Annotations). In order to handle it you could write a custom validation attribute which will be applied to the
CompanyViewModelinstead of individual properties and will allow you to perform the validation logic based on which radio button the user choose (btw you will need a property on your view model which will represent the radio button selection). The problem with model validators is that you might have some hard time handling the error highlighting.That’s one of the reasons why I use FluentValidation.NET instead of Data Annotations. This allows me to have the validation logic away from the model and done in an imperative way. It also allows me to have conditional validators which apply based on the values of some properties on the view model (in this case this would be the radio button selection).