I'm using C# with MVC(Razor View Engine)
I'm doing validation using Annotation Like this:-
Model :-
[Required]
public int VendorId { get; set; }
Razor view Engine :-
<div class="col-md-3">
<label>#Html.LabelFor(r => Model.VendorId)</label>
#Html.DropDownListFor(x => x.VendorId, new SelectList(suppliers, "Value""Text"),"-Select-", htmlAttributes: new { #class = "select-full" })
#Html.ValidationMessageFor(x => x.VendorId, null, new { style = "color: red" })
</div>
and it was showing error message
The Vendor field is required.
if I'm not selecting vendor.
Now I want to highlight (Border Color in Red) of this Dropdown Field
instead showing this message if validation failed (DataAnnotation) instead showing a message on both client & server side
You can check validate form, if form is invalid, just add:
$('#VendorId').attr('style', "border-radius: 5px; border:#FF0000 1px solid;");
Related
I am using MVC Core 1.1 with Razor and binding it to a ViewModel which has a property:
[Required(ErrorMessage = "Required")]
[Display(Name = "Surname")]
public string Surname { get; set; }
In Razor, I am using the TextBoxFor to bind this as such:
#Html.LabelFor(x => x.Surname, new { #class = "required" })
#Html.ValidationMessageFor(x => x.Surname)
#Html.TextBoxFor(x => x.Surname, new { #class = "form-control" })
Now, if I run in Debug mode I am getting the Id and name "Surname" in the output HTML. However, on Release mode I am getting "SurName".
I tried cleaning and rebuilding and I still have the same results. I tried to see if I have some weird JS that is changing this on the client-side, but there isn't any.
Did anybody encounter a similar situation? Do you have any recommendation where to look?
I am creating a feature in my app to process an uploaded CSV file containing multiple records to be imported. Data needs to be validated, and I want to show any validation errors BEFORE the Import button is clicked. High-level plan:
Step 1: Upload CSV file
Step 2: Display all records from CSV file and any validation errors next to each record (missing required fields, etc.)
Step 3: Click "Import" in order to actually import the valid records.
Here's a simplified version of what I have:
User View Model
public class UserViewModel
{
[Required]
[StringLength(100)]
public string Name { get; set; }
[Required]
[StringLength(150)]
public string Email { get; set; }
[Required]
[StringLength(10)]
public string Phone { get; set; }
}
File Upload Action Post
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
foreach (var csvRecord in csvRecords)
{
newUsersToCreate.Add(new UserViewModel
{
Name = csvRecord.Name,
Email = csvRecord.Email,
Phone = csvRecord.Phone
});
}
return View("ImportPreview", newUsersToCreate);
}
View ImportPreview.cshtml
#model IEnumerable<App.ViewModels.UserViewModel>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "alert alert-danger", role = "alert" })
<table>
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Validation Errors</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(model => model)
</tbody>
</table>
<button type="submit">Import</button>
}
Editor Template for UserViewModel.cshtml
#model App.ViewModels.UserViewModel
<tr>
<td>
#Html.HiddenFor(model => model.Name)
#Html.DisplayFor(model => model.Name)
</td>
<td>
#Html.HiddenFor(model => model.Email)
#Html.DisplayFor(model => model.Email)
</td>
<td>
#Html.HiddenFor(model => model.Phone)
#Html.DisplayFor(model => model.Phone)
</td>
<td>
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
#Html.ValidationMessageFor(model => model.Email, "", new { #class = "text-danger" })
#Html.ValidationMessageFor(model => model.Phone, "", new { #class = "text-danger" })
</td>
</tr>
Problem
While this generates a nice "preview" table with all prepared User records as essentially rows of hidden fields ready to go, the problem is that it does not display validation errors until the Import button is clicked.
How can I get it to show per-field validation errors in each row, right after the return View('ImportPreview', newUsersToCreate) comes back with the view?
You could do this in the view by checking if the $.validator is valid. Since hidden inputs are not validated by default, you also need to override the validator. Add the following after the jquery-{version}.js, jquery.validate.js and jquery.validate.unobtrusive.js scripts (but not in $(document).ready())
<script>
// override validator to include hidden inputs
$.validator.setDefaults({
ignore: []
});
// validate form and display errors
$('form').valid();
</script>
Note that you might include a (say) <p id="error" style="display:none;"> tag containing a 'general' error message that the data is invalid and use
if ($('form').valid()) {
$('#error').show();
}
The disadvantage is that you need to include the jQuery scripts that otherwise are not needed.
Another option is to validate in the controller using TryValidateObject on each item in the collection, and add any errors to ModelState which will be displayed in your ValidationMessageFor() placeholders. Note the following assumes csvRecords implements IList<T> so that you can use a for loop.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Upload(HttpPostedFileBase csvFile)
{
// var csvRecords = do stuff to retrieve data from CSV file
var newUsersToCreate = new List<UserViewModel>();
for (int i = 0; i < csvRecords.Count; i++)
{
UserViewModel model = new UserViewModel
{
Name = csvRecords[i].Name,
....
};
newUsersToCreate.Add(model);
// validate the model and include the collection indexer
bool isValid = ValidateModel(model, i));
}
return View("ImportPreview", newUsersToCreate);
}
private bool ValidateModel(object model, int index)
{
var validationResults = new List<ValidationResult>();
var context = new ValidationContext(model);
if (!Validator.TryValidateObject(model, context, validationResults, true))
{
foreach (var error in validationResults)
{
string propertyName = $"[{index}].{error.MemberNames.First()}";
ModelState.AddModelError(propertyName, error.ErrorMessage);
}
return false;
}
return true;
}
The advantage of the controller code is that you could add an additional property to your view model (say bool IsValid) and use it for conditional styling of your table rows, and that you could decide that if there are 'too many' errors, you could just display a different view rather that rendering the whole table and displaying potentially hundreds of repeated error messages
I need a help.
I have a User registration form and I have to map "Customer" with user.
Now I want to validate user "customer" which is came from another source and I put the "customer" in Select list "customer" are more then 2000 that's why I use JQuery Chosen plugin to search in select list
but "customer" Field depend on "roles" that's why on page load "customer" field is hidden by default when I change the role "customer" field(chosen select list) display and when i am Selecting customer its not firing remote validation.
I tried to make it visible on "inspect element" and I change the display:none to display:bock and try to change value from chosen its not working when i change the orignal select list value from clicking on select list then its working fine i mean its firing my remote validator method here is full code example what i am doing.
please help i want to validate on when chosen select list value change.
This is RegisterViewModel
public class RegisterViewModel
{
[Required]
[Display(Name = "Role")]
public string Role { get; set; }
//for edit view model additionalFields which will only require for edit mode
//[System.Web.Mvc.Remote("DoesCustomerCodeExist", "Account", AdditionalFields = "OldCustomerCode")]
[Required(AllowEmptyStrings = false, ErrorMessage = "Customer Code is required.")]
[Display(Name = "Customer Code", Description = "A customer code come from our oracle system.")]
[System.Web.Mvc.Remote("DoesCustomerCodeExist", "Account")]
[Range(0, int.MaxValue, ErrorMessage = "Please enter valid Customer Code in number only.")]
public string CustomerCode { get; set; }
}
Here is my view cshtml in this file also have js code to display customers chosen Select list when role changed.
//select Role
<div class="form-group">
#Html.LabelFor(m => m.Role, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.Role, ViewBag.Roles as SelectList,"", new { #class = "form-control chosen-select", data_placeholder = "Select a Role" })
#Html.ValidationMessageFor(m => m.Role, "", new { #class = "text-danger" })
</div>
</div>
//Customer Code
<div class="form-group condition-div user hidden ">
//this hidden field is only for edit mode
//#Html.Hidden("OldCustomerCode", Model.CustomerCode)
#Html.LabelFor(m => m.CustomerCode, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.CustomerCode, (SelectList)ViewBag.Customers, "", new { #class = "form-control chosen-customers", data_placeholder = "Select Customer" })
#Html.ValidationMessageFor(m => m.CustomerCode, "", new { #class = "text-danger" })
</div>
</div>
#section Styles{
#Styles.Render("~/Content/chosen")
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/bundles/chosen")
<script type="text/javascript">
$('input[type=text]').tooltip(
{
placement: "right",
trigger: "focus"
}
);
$(".chosen-select").chosen({ allow_single_deselect: true});
$('#Role').change(function () {
if (this.value == "") {
$('.condition-div').addClass('hidden'); // hide all the conidional divs
} else if (this.value == "NBP User" || this.value == "NBP Head" ) {
$('.condition-div.admin').addClass('hidden'); /// hide admin conditional divs
$('.condition-div.user').removeClass('hidden'); // show user role conditioanl div
//configure selectlist to Chosen select and if i remove this line and show orignal select list its working fine mean remote validating on change but if i use this is not working on change.
$(".chosen-customers").chosen({ allow_single_deselect: true, search_contains: true });
$.validator.setDefaults({ ignore: ":hidden:not(.chosen-customers)" });
} else if (this.value == "ICIL User" || this.value == "ICIL Head" || this.value == "FIO User" ) {
$('.condition-div.user').addClass('hidden'); /// hide user role conditional divs
$('.condition-div.admin').removeClass('hidden'); // show admin role conditional divs
$(".chosen-branch").chosen({ allow_single_deselect: true });
$.validator.setDefaults();
}
});
</script>
}
Controller Action to validate Customer Code
public ActionResult DoesCustomerCodeExist(string CustomerCode, string OldCustomerCode)
{
//the oldCustomerCode will come null in this case cause its register view and in edit view OldCustomerCode will be use
if (CustomerCode == OldCustomerCode)
return Json(true, JsonRequestBehavior.AllowGet);
if (DbContext.Users.Any(x => x.CustomerCode == CustomerCode))
return Json("Customer code already exists in application. Please verify user details.", JsonRequestBehavior.AllowGet);
if (DbOracle.IsCustomerCodeExist(CustomerCode))
return Json(true, JsonRequestBehavior.AllowGet);
else
return Json("The customer code does not exist in database.", JsonRequestBehavior.AllowGet);
}
All code working fine if i did not use jquery chosen plugin.
In short issue is when I use chosen plugin for select list remote validation is stop validating values.
I can share images if u guys need now I have a limited account so i cant upload snaps shots....
Please help me.
you should have to put some JQuery on client side to track the "CustomerCode" field when change of customer field jsut call "focusout()" event of "CustomerCode" e.g:
$('#CustomerCode').change(function () {
$(this).focusout();
});
I have got a model as below -
public string Password { get; set; }
[Compare("Password", ErrorMessage = "Password and Confirm Password have to be the same")]
public string ConfirmPassword { get; set; }
In my HTML, I am adding the code as
<label>Password</label>
<span class="req">*</span>
#Html.PasswordFor(x => x.Password, new { #class = "form-control form-control2", #required = "required" })
<p class="signuppace"></p>
<label>Confirm Password</label>
<span class="req">*</span>
#Html.PasswordFor(x => x.ConfirmPassword, new { #class = "form-control form-control2", #required = "required" })
The message for the required field gets displayed but here the ErrorMessage "Password and Confirm Password have to be the same" doesn't get displayed. I have already referred this 1,2 SO links. What am I doing wrong? Any help would be appreciated.
The don't think that the helper adds markup to display a validation error automatically, other than for client side validation using unobtrusive client validation which executes using JavaScript (Not server side).
You want to use #Html.ValidationMessageFor(x => x.ConfirmPassword) to show the error message or simply check for the error using the ModelState.
#if (ModelState.Errors["ConfirmPassword"] != null && !string.IsNullOrWhiteSpace(ModelState.Errors["ConfirmPassword"][0]))
{
// Display the first error message for this field
ModelState.Errors["ConfirmPassword"][0]
}
You don't show all relevant cshtml, but you need to display the validation message.
Either use #Html.ValidationSummary(excludePropertyErrors: false) to display all validation errors in one place, or put #Html.ValidationMessageFor(x => x.Password) near your input field.
I want to make an editing function where you can add metafields (= specific fields for a category) to a category.
What I want to do in the view is
foreach (App.Models.Metafield field in Model.Category.Metafields)
{
<div class="field">
#Html.TextBoxFor(model => field.Name, new { #class = "form-control title" })
#Html.DropDownListFor(model => field.Type, Model.MetaTypes, new { #class = "form-control type" })
</div>
}
The problem is that the Metafields are not added to the viewModel when I hit the save button. So I guess the field.Name and field.Type should be replaced by something else..
This can't work this way because the sent form can't contain these dynamically generated fields with the same name.
However, you can collect the data from these dynamic fields using js and serialize it into a hidden field just before submitting the form, then you can parse it in your server side.
Here is an example with jquery:
$('#save-btn').click(function(e) {
$hidden = $("#hidden");
$hidden.val(getDynamicData());
});
function getDyanmicData() {
var data;
$fields = $(".field");
// get children and calculate data
return data;
}
This may be a bit too 'manual work', but I find it useful to know what's happening. For other solutions you can search form dynamic forms in ASP.NET MVC.
Please try this code
#for(int i=0;i<=Model.Category.Metafields.count();i++)
{
<div class="field">
#Html.TextBoxFor(m=> m[i].Name, new { #class = "form-control title" })
#Html.DropDownListFor(m=> m[i].Type, Model.MetaTypes, new { #class = "form-control type" })
</div>
}