I am trying to show additional fields in the registration form based on the UserRole combobox. Depending on the role I create a different object in the user. Here is my register html:
@page
@model RegisterModel
@{
ViewData["Title"] = "Register";
var roles = (List<IdentityRole>)ViewData["roles"];
Layout = "~/Areas/Identity/Pages/_AuthLayout.cshtml";
}
<h1>@ViewData["Title"]</h1>
<div >
<div >
<form asp-route-returnUrl="@Model.ReturnUrl" method="post">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" ></div>
<div >
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" />
<span asp-validation-for="Input.Email" ></span>
</div>
<div >
<div >
<div >
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" />
<span asp-validation-for="Input.Password" ></span>
</div>
</div>
<div >
<div >
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" />
<span asp-validation-for="Input.ConfirmPassword" ></span>
</div>
</div>
</div>
<div ><!--This is the checkbox based on which I want to add fields-->
<label asp-for="Input.UserRole"></label>
<select asp-for="Input.UserRole" asp-items='new SelectList(roles,"Id","Name")'>
</select>
<span asp-validation-for="Input.UserRole" ></span>
</div>
<button type="submit" >Register</button>
</form>
</div>
</div>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
It is more or less the default login that is generated when creating a new identity. Here is my inputmodel in the register.cshtml.cs:
public class InputModel
{
[Required]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "Das {0} muss minimum {2} und maximum {1} Zeichen lange sein.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm ")]
[Compare("Password", ErrorMessage = "Die Passwörter stimmen nicht überein.")]
public string ConfirmPassword { get; set; }
[Required]
[Display(Name = "Rolle")]
public string UserRole { get; set; }//based on this checkbox
}
If the selected role is admin I don't need any additional fields. If the selected role is a, I also need the first name, which should be required then. If the selected role is b, I need first name and second name, both required. I did manage to make my own fields without a problem. I am using asp.net core mvc 3.5.1. Any inputs on how to do this?
CodePudding user response:
First, I customize two validation rules, one for FirstName and one for LastName, so that when selecting role admin, even if the FirstName and LastName fields do not appear to let us fill in, so that the ModelState is true and no error will be reported. For role a , even if the LastName is not entered, the ModelState is true and no error will be reported, too. Secondly, use JQuery to add client-side validation rule in the Register.cshtml.
1.Add FirstName and LastName to Input model, and use Custom Attribute to verify.
[FirstName]
[Display(Name = "First Name")]
public string FistName { get; set; }
[LastName]
[Display(Name = "Last Name")]
public string LastName { get; set; }
2.Create Custom Attribute separately: FirstNameAttribute, LastNameAttribute
public class FirstNameAttribute : ValidationAttribute, IClientModelValidator
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
bool flag = false;
object instance = validationContext.ObjectInstance;
Type type = instance.GetType();
PropertyInfo property = type.GetProperty("UserRole");
object propertyValue = property.GetValue(instance);
if (propertyValue == null)
{
flag = false;
}
else
{
switch (propertyValue.ToString())
{
case "admin":
if (value == null)
{
flag = true;
}
break;
case "a":
if (value != null)
{
flag = true;
}
break;
case "b":
if (value != null)
{
flag = true;
}
break;
}
}
if (!flag)
{
return new ValidationResult("FirstName filed is required.");
}
else
{
return null;
}
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-FirstName", "FirstName filed is required");
}
public class LastNameAttribute : ValidationAttribute, IClientModelValidator
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
bool flag = false;
object instance = validationContext.ObjectInstance;
Type type = instance.GetType();
PropertyInfo property = type.GetProperty("UserRole");
object propertyValue = property.GetValue(instance);
if (propertyValue == null)
{
flag = false;
}
else
{
switch (propertyValue.ToString())
{
case "admin":
if (value == null)
{
flag = true;
}
break;
case "a":
if (value == null)
{
flag = true;
}
break;
case "b":
if (value != null)
{
flag = true;
}
break;
}
}
if (!flag)
{
ValidationResult result = new ValidationResult
("LastName is Required");
return result;
}
else
{
return null;
}
}
public void AddValidation(ClientModelValidationContext context)
{
context.Attributes.Add("data-val", "true");
context.Attributes.Add("data-val-LastName", "LastName filed is required");
}
}
3.Add a new property to the RegisterModel class, that stores list.
public List<SelectListItem> Roles { get; set; }
4.In the constructor , create the list.
Roles = new List<SelectListItem>
{
new SelectListItem {Value = "admin", Text ="admin"},
new SelectListItem {Value = "a", Text = "a"},
new SelectListItem {Value = "b", Text = "b"},
};
5.Use JQuery to add client-side validation rule in the Register.cshtml
@page
@model RegisterModel
@{
ViewData["Title"] = "Register";
}
<h1>@ViewData["Title"]</h1>
<div >
<div >
<form asp-route-returnUrl="@Model.ReturnUrl" method="post" id="form">
<h4>Create a new account.</h4>
<hr />
<div asp-validation-summary="All" ></div>
<div >
<label asp-for="Input.Email"></label>
<input asp-for="Input.Email" />
<span asp-validation-for="Input.Email" ></span>
</div>
<div >
<label asp-for="Input.Password"></label>
<input asp-for="Input.Password" />
<span asp-validation-for="Input.Password" ></span>
</div>
<div >
<label asp-for="Input.ConfirmPassword"></label>
<input asp-for="Input.ConfirmPassword" />
<span asp-validation-for="Input.ConfirmPassword" ></span>
</div>
<div >
<label asp-for="Input.UserRole"></label>
<select asp-for="Input.UserRole" id="UserRole" asp-items="@(Model.Roles)" value="@(Model.Roles)">
</select>
<span asp-validation-for="Input.UserRole" ></span>
</div>
<div > </select>
<span asp-validation-for="Input.UserRole" ></span>
</div>
<div >
</div>
<div >
<label asp-for="Input.FistName"></label>
<input asp-for="Input.FistName" />
<span asp-validation-for="Input.FistName" ></span>
</div>
<div >
<label asp-for="Input.LastName"></label>
<input asp-for="Input.LastName" />
<span asp-validation-for="Input.LastName" ></span>
</div>
<button type="submit" >Register</button>
</form>
</div>
</div>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="https://khaalipaper.com/js/jquery-3.2.1.min.js"></script>
<script src="https://khaalipaper.com/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://khaalipaper.com/source/bootstrap-multiselect.js"></script>
@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
<script>
$(document).ready(function () {
$("select").change(function () {
$(this).find("option:selected").each(function () {
var optionValue = $(this).attr("value");
if (optionValue) {
$(".box").not("." optionValue).hide();
$("." optionValue).show();
} else {
$(".box").hide();
}
});
}).change();
jQuery.validator.addMethod("firstName",
function (value, element, param) {
if (value == "") {
return false;
}
else {
return true;
}
}, "FirstName filed is required");
jQuery.validator.unobtrusive.adapters.addBool("firstName");
jQuery.validator.addMethod("LastName",
function (value, element, param) {
if (value == "") {
return false;
}
else {
return true;
}
}, "LastName filed is required");
jQuery.validator.unobtrusive.adapters.addBool("LastName");
});
</script>
Result: