MVC 4 Date (custom format) validation - asp.net-mvc-3

In my application there's a requirement that date are entered like this : d-MMM-yyyy
I can render that just fine like this :
#model :
[DataMember] public DateTime SomeDateField { get; set; }
#View :
#Html.EditorFor(model => model.SomeDateField)
#Html.ValidationMessageFor(model => model.SomeDateField)
EditorTemplate: DateTime.cshtml
#model DateTime
#Html.TextBox("", (Model.Equals(DateTime.MinValue) ? string.Empty : Model.ToString("d-MMM-yyyy")), new { #class = "date" })
Shared._Layout.cshtml
$(".date").datepicker({ dateFormat: 'd-MMM-yyyy' });
I'm not sure why but there's something going wrong with the client-side validation on IE9 and FireFox. When leaving the field (even if it's valid) a red box is drawn around the input-field but no validation-message is shown. I'm not sure where the problem is but I'm pretty sure I'm not the first to encounter it. I've searched stackoverflow but didn't find a solution (yet).
Any help is greatly appreciated.
Jurjen.

Related

Required validation on hidden field

I am using client side validation on hidden field in asp.net MVC. I am using required validation using data annotations. I am trying to validate hidden field but it’s not working.
My Model
[Required(ErrorMessage = "From date is required")]
public DateTime? FromDate { get; set; }
My View
#Html.HiddenFor(m => m.FromDate, new { ID = "hfdFromDate" }
#Html.ValidationMessageFor(m => m.FromDate)
I would like to know how I can achieve the same, any small inputs on the same is also greatly appreciated.
Thanks in advance.
As some have pointed the validation isn't performed because the "hidden" property is set.
I had the same issue and ended up using the style tag:
#Html.TextBoxFor(m => m.Foo, new { style = "visibility:hidden"})
The validation is then performed.
Added this line before form.valid().
form.data("validator").settings.ignore = "";
where form is your form element.
In my case :
var form = $("#myForm");

MVC 5 Conditional Validation Option?

I'm developing an MVC 5 web application. Within a particular View I need to validate a ViewModel, however, I need some of the validation only to occur depending on the users inpupt.
For example, I have a ViewModel
public class TimeEntryViewModel
{
public int proposalID { get; set; }
public int proposalCode { get; set; }
public int nonchargeCode { get; set; }
public SelectList UserProposals { get; set; }
public SelectList TimeEntryClientCodes { get; set; }
public SelectList TimeEntryNonChargeCodes { get; set; }
}
This ViewModel is passed to a View which looks like this
<div class="form-group">
#Html.LabelFor(m => m.proposalID, "Proposal")
#Html.DropDownListFor(m => m.proposalID, Model.UserProposals, "No Proposal", new { #class = "form-control"})
#Html.ValidationMessageFor(m => m.proposalID)
</div>
<div id="ClientCodes" class="form-group" style="display:none">
#Html.LabelFor(m => m.proposalCode, "Client")
#Html.DropDownListFor(m => m.proposalCode, Model.TimeEntryClientCodes, "Select", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.proposalCode)
</div>
<div id="NonChargeCodes" class="form-group">
#Html.LabelFor(m => m.nonchargeCode, "Non Charge")
#Html.DropDownListFor(m => m.nonchargeCode, Model.TimeEntryNonChargeCodes, "Select", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.nonchargeCode)
</div>
If the user selects 'No Proposal' from the first drop down list, then the drop down list 'nonchargeCode' appears and I need to validate so that the user selects an option from it.
However, if the user selects another option from the first down drop list, then the drop down list 'nonchargeCode' will disappear and another drop down called 'proposalCode' will appear. I then want to validate to ensure the user selects an option from this drop down, but not the 'nonchargeCode' (which will be hidden).
In an MVC 4 application I previously coded, I used http://fluentvalidation.codeplex.com/ to help with this scenario.
I'm just wondering if anyone else had used anything else to overcome this problem of conditional validation? If so, I'd be keen to hear.
Thanks again.
You can use conditional validation in jQuery and in fluentvalidation.
You can use a jQuery selector on the validation, something like this.
I'm not sure about the HTML element names.
$( "#myform" ).validate({ rules: {
proposalCode: {
required: "#proposalCode:visible"
} }
Check out jQuery Dependency expression for more information.
In FluentValidation validation (Server side only) you can use the 'When' expression.
RuleFor(r => r.proposalCode).NotNull().When(e => // Check selected value);
Check out the documentation here
I think this should get you started.

How to keep the same data when return to the view?

How to keep the same data when return to the view?
I tried to put return the form to the view, but it did not work.
Is there any good and simple way to do this?
[HttpPost]
public ActionResult Register(FormCollection form)
{
string name = form["Name"].Trim();
if (string.IsNullOrEmpty(name))
{
TempData["TempData"] = "Please provide your name ";
return View(form);
}
string email = form["Email"].Trim();
var isEmail = Regex.IsMatch(email, #"(\w+)#(\w+)\.(\w+)");
if (!isEmail)
{
TempData["TempData"] = "Sorry, your email is not correct.";
return View(form);
}
//do some things
}
Not sure why you would be using FormCollection in the post but maybe you come from a WebForms background. In MVC you should use ViewModels for the transport of your data to and from the Views.
By default the Register method in an MVC 3 app uses a ViewModel in the Register View. You should simply post it back. In fact, the default app has that already created for you if you didn't know as part of the Internet template.
The standard pattern is to have a ViewModel that represents your data that you will use in your View. For example, in your case:
public class RegisterViewModel {
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
}
Your controller the should contain 2 actions, a Get and a Post. The Get renders the View and is ready for the user to enter data. upon submitting the View the Post action is then called. The View sends the ViewModel to the action and the method then takes action to validate and save the data.
If there is a validation error with the data, it's very simple to return the ViewModel back to the View and display the error messages.
Here is the Get action:
public ActionResult Register() {
var model = new RegisterViewModel();
return View(model);
}
And here is the Post action:
[HttpPost]
public ActionResult Register(RegisterViewModel model) {
if(ModelState.IsValid) { // this validates the data, if something was required, etc...
// save the data here
}
return View(model); // else, if the model had validation errors, this will re-render the same view with the original data
}
Your view would look something like this
#model RegisterViewModel
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Name) <br />
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Email) <br />
#Html.ValidationMessageFor(model => model.Email)
</div>
}
Using other strategies to capture and save data in an MVC app is absolutely possible, it's a very extensible framework. But there is a specific pattern that makes MVC what it is and working against that pattern can sometimes prove difficult. For a beginner it is best to understand the preferred patterns and strategies first and then once understood very well, you can then adopt some of your own custom strategies to meet your needs. By then you should understand the system well enough to know what you need to change and where.
Happy coding!!

Format Datetime to date in MVC3

Below is the Property in my viewModel of Datetime,I want to display only date on the View,
Can any one help me out in formatting this. right Now Im seeing 01/01/2010 12:00:00 AM
public DateTime ModifiedDate
{
get
{
return Region.ModifiedDate;
}
set
{
Region.ModifiedDate = value;
}
}
#Html.TextBoxFor(model => model.ModifiedDate)
Model
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyy}" )]
public DateTime RecipeDate{ get; set; }
Edit Template
#model DateTime
#Html.TextBox("", string.Format(ViewData.TemplateInfo.FormattedModelValue.ToString(), Model), new { #class = "date" })
EditorFor doesn't allow for custom attributes, you must use a TextBox or TextBoxFor
I created an editor template (located in the Shared\EditorTemplates folder in my solution) that looks like this:
#model System.DateTime?
#Html.TextBox("", Model.HasValue ? Model.Value.ToString("MM/dd/yyyy") : string.Empty, new { #class = "date"})
And then when I want to use it,
#Html.EditorFor(model => model.RecipeDate, new { #class = "date" })
#Html.ValidationMessageFor(model => model.RecipeDate)
Seems to work pretty well for me.

Client-side validation not firing for CompareAttribute DataAnnotation

I'm laying out a view that compares two password strings. The two properties in one of my models are pretty straightforward:
[Required]
[RegularExpression(#"(\S)+", ErrorMessage = "White space is not allowed")]
[StringLength(20, MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New Password")]
public string NewPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[RegularExpression(#"(\S)+", ErrorMessage = "White space is not allowed")]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Confirm Password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
Here's my view code:
<table class="fieldset center" width="400">
<tbody>
<tr>
<th width="150">
#Html.LabelFor(m => m.NewPassword)
</th>
<td>
#Html.PasswordFor(m => m.NewPassword, new { #class = "itext3" })
<br /><br />#Html.ValidationMessageFor(m => m.NewPassword)
</td>
</tr>
<tr>
<th width="150">
#Html.LabelFor(m => m.ConfirmPassword)
</th>
<td>
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "itext3" })
<br /><br />#Html.ValidationMessageFor(m => m.ConfirmPassword)
</td>
</tr>
</tbody>
</table>
All of the attributes fire their client-side validation messages when tested, except for the CompareAttribute on ConfirmPassword which is not firing until I hit the server. However, in my controller the ModelState.IsValid = false.
I compared what I'm doing to the default MVC application which is working correctly. Any suggestions for troubleshooting and fixing this?
I'm using MVC 3 RTM.
There is a BUG in jquery.validate.unobtrusive.js (and jquery.validate.unobtrusive.min.js, the minified version). The client-side validation emitted as a result of the [Compare] attribute will ONLY work if the compare-to field is the FIRST field on the form. To fix this bug, locate this line in jquery.validate.unobtrusive.js:
element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];
which results in this equivalent:
element = $(options.form).find(":input[name=MyExample.Control]")[0];
Unfortunately that's not the right syntax for find(), and causes it to reference the first input control on the form.
Change that line to:
element = $(options.form).find(":input[name='" + fullOtherName + "']")[0];
which results in this equivalent:
element = $(options.form).find(":input[name='MyExample.Control]'")[0];
Which is the correct syntax, and correctly matches the input control with the specified name.
Locate the same code block in jquery.validate.unobtrusive.min.js, which looks like this:
f=a(b.form).find(":input[name="+d+"]")[0];
and change it to:
f=a(b.form).find(":input[name='"+d+"']")[0];
Take a look at your script tags in your _Layout.cshtml. I'm guessing the issue is probably your jQuery references. Did you start the MVC 3 project form scratch or are you using an example project or something like that?
Here is what happend with me; I had similar issues...
I was using some example code that pointed to ajax.microsoft.com in the src attributes
So, for example one of the script tags looked like this: <script src="http://ajax.microsoft.com/ajax/jquery.validate/1.7/jquery.validate.min.js"></script>
I wanted to get a better handle on what js was executing on the client side so I changed it to this: <script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
That is just an example, I think there were a couple more script tags that I changed as well
So, after changing to internally served jQuery files it worked. I went back and looked at my local .validate.js file... and it was version 1.6. That is how i realized the issue was due to the version of jQuery or it's compatibility with one of the other the js libs anyway.
Bottom line is that it looks like 1.7 doesn't fully function with the validate.unobtrusive.js lib that I had... there may be a newer version that does function with 1.7... like I said, I was tinkering with an example project so there are some unknowns there. I suppose it could also be an incompatibility with the MvcValidation.js lib between it and one of the other js libs too?
At any rate, I'd say the simplest way to state your issue is that you are most likely referencing a bad combination of js libs. I'd say the best failsafe way to get a good combination of js libs is to create a new Asp.Net MVC 3 Project in Visual Studio and see what versions it gives you by default/with the project template... that is assuming that you didn't start the project from scratch. If you DID start it from scratch then may be you changed your layout file to have bad js references or if none of that is true then I suppose it could be a problem with the VisualStudio project templates?... realistically I'd say that is doubtful though. All of that said- I'd say the most likely cause [that I'd wager on anyway] is that you just got in trouble like me trying to quickly use some example code =)
I've tested this with ASP.NET MVC 3 RTM and it worked fine for me:
Model:
public class MyViewModel
{
[Required]
[RegularExpression(#"(\S)+", ErrorMessage = "White space is not allowed")]
[StringLength(20, MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "New Password")]
public string NewPassword { get; set; }
[Required]
[DataType(DataType.Password)]
[RegularExpression(#"(\S)+", ErrorMessage = "White space is not allowed")]
[StringLength(20, MinimumLength = 6)]
[Display(Name = "Confirm Password")]
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
#model SomeAppName.Models.MyViewModel
#{
ViewBag.Title = "Home Page";
}
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.LabelFor(m => m.NewPassword)
#Html.PasswordFor(m => m.NewPassword)
#Html.ValidationMessageFor(m => m.NewPassword)
<br/>
#Html.LabelFor(m => m.ConfirmPassword)
#Html.PasswordFor(m => m.ConfirmPassword)
#Html.ValidationMessageFor(m => m.ConfirmPassword)
<br/>
<input type="submit" value="OK" />
}
In this configuration client side validation works perfectly fine for all attributes including the [Compare].
I was never able to make the default way to work. Seems like in JQuery it fires only those validation methods that are registered with JQuery.validator.
Initially I was doing something like this...
jQuery.validator.unobtrusive.adapters.add("equaltopropertyvalidation", ["param"], function (rule)
{
alert("attaching custom validation adapter.");
rule.rules["equaltopropertyvalidation"] = rule.params.param;
rule.messages["equaltopropertyvalidation"] = rule.message;
return function (value, element, param)
{
alert("now validating!");
return value == this.currentForm[param].value;
};
});
But my second alert (now validating!) would never fire even though the first one would. I had seen this article but I was hesitating to implement it like this because it requires me to do something extra but I was lazy.
Well after spending lots of time to figure out what's wrong I implemented it in the way this article suggests and it works. Now it is like this and it works.
<script type="text/javascript">
jQuery.validator.addMethod("equaltopropertyvalidation", function (value, element, param)
{
return value == this.currentForm[param].value;
});
jQuery.validator.unobtrusive.adapters.add("equaltopropertyvalidation", ["param"], function (rule)
{
rule.rules["equaltopropertyvalidation"] = rule.params.param;
rule.messages["equaltopropertyvalidation"] = rule.message;
});
</script>
If you like detail then here it is: Look in jquery.validate.js and search for
check: function (element)
This is the function that is fired to check if the field is valid or not by firing all the applicable rules on the field. Now first it creates an array or rules to fire. It does that using the following code.
var rules = $(element).rules();
Then it iterates over the rules collection, creates a rule element for every item in the collection and then tries to find a corresponding method to fire for that rule. Once the method is found it is fired. It does that using the following code.
var result = $.validator.methods[method].call(this, element.value.replace(/\r/g, ""), element, rule.parameters);
Now the important thing is that if your custom method is not added to the $.validator.methods collection using the JQuery.validator.addMethod IT WILL NOT BE FOUND, even if it is sitting there in the JQuery.validator.unobtrusive.adapters collection.
There might be a way to make this work without using the JQuery.validator.addMethod (and if yes then someone please clarify) but this I believe is the reason the second approach works and the first doesn't.
I was using the following versions of Jquery files
JQuery: 1.6/1.7.1
Jquery.Validate: 1.9.0
JQuery.Unobtrusive.Validate: taken from Microsoft CDN on
2/14/2012.

Resources