Date formats in input forms - C# - c#

I've been following this tutorial to learn ASP.NET Core MVC with Entity Framework. My problem is that when I run my solution and try to add a new entry on the students table using my browser, it automatically imposes a date format in the form of MM/dd/yyyy, as shown here. I want it in the format yyyy-MM-dd.
My Student model is the following:
public class Student
{
public int StudentID { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
[Display(Name = "First Name")]
public string FirstMidName { get; set; }
[Display(Name = "Enrollment Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime EnrollmentDate { get; set; }
public ICollection<Enrollment> Enrollments { get; set; }
}
And in my view, the date input is implemented as follows:
<div class="form-group">
<label asp-for="EnrollmentDate" class="control-label"></label>
<input asp-for="EnrollmentDate" class="form-control" />
<span asp-validation-for="EnrollmentDate" class="text-danger"></span>
</div>
What's even weirder is that the specified format works outside input forms, such as here, in the index page where it shows every student in the table.
I can't seem to find a solution for this problem anywhere, most people just say to add ApplyFormatInEditMode = true on the data annotation and it should work.
Any help is appreciated, thanks in advance!

This problem occurs because of the [DataType(DataType.Date)] declaration on your EnrollmentDate. When the page is rendered, this element is converted to
<input type="date">
When the browser sees this it will impose its own internal datepicker on the input element if it supports it. Here's a nice link to all the information on the Mozilla site.
One problem with this is every browser has its own styling/conventions, which makes for a different user experience across platforms.
You can write a tiny piece of JavaScript to overwrite the data type on the client and replace the browser datepicker with a common one. This example just
$("input[type=date]")
.datepicker({ dateFormat: "yy-m-d", changeYear: true, yearRange: "-4:+0" })
.attr("type", "text");
Note how in the last line we change the type attribute to text.
And one issue is that it relies on the view model date formatting for the initial load and the javascript to format when using the datapicker.

Sean T pointed out that a solution already existed here.
Apparently this has nothing to do with C# or anything, it has to do with the way browsers handle date input and try to use a format that the user is more familiar with.
So, to change this behavior on Google Chrome (the browser I use), I followed these steps.
For reference, here are instructions on how to do it in Firefox. Couldn't find for Opera, and Edge seems to either not have a way to change this, or it's bound with windows' regional settings (see this).

Related

How to format numbers in C# MVC 4 to reflect a two decimal point currency?

So I'm having trouble with my view wanting more numbers behind the decimal point as input than I want it to need.
I am using this model:
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[DisplayFormat(DataFormatString = "{0:F2}", ApplyFormatInEditMode = true)]
public decimal Price { get; set; }
}
This is in my view:
<div class="editor-label">
#Html.LabelFor(model => model.Price)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Price)
#Html.ValidationMessageFor(model => model.Price)
</div>
It seem that simply adding the DisplayFormat attribute to Movie.Price isn't enough to allow users to enter numbers like 2,79, if they try they'll get the validation error. The input field created by #Html.EditorFor(model => model.Price) instead requires the number to be 2,790 (notice the additional 0 added behind the decimal).
I've tried a variety of DataFormatStrings but all to no effect, what am I missing/not understanding?
How do I adjust my code so users are able to enter 2,79 as a valid input instead of 2,790?
The problem here is the server - and most likely client-side validation scripts too - is parsing a comma (,) not as a decimal separator, but as a thousands separator. This is because, in the default culture, the decimal point is .. So 1234 + 56/100 is "normally" represented as 1,234.56 and not 1.234,56.
You need to set the proper culture so parsing works correctly in your format. Do this by either globally setting a value in web.config, or manually setting Thread.CurrentThread.CurrentUICulture / Thread.CurrentThread.CurrentCulture from the controller if you need more fine-grained control.
This will also most likely not bubble down to client-side validation, so you will need to make sure you write the proper JavaScript validation rules as well to override the default ones.
As a side note, you may want to do something to indicate to your users which format to expect. People from other parts of the world write numbers differently, and might expect things to be in their native format. (Sometimes the language of the page is a good hint of the expected number/date formats though.)

What is the relationship between the MVC Display decorator and View applied using EditorFor?

I'm working through an example of creating an Editor Template in MVC4.
I added the following to my Model:
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email"]
public string Email { get; set; }
Added this to the View for the model:
#Html.EditorFor(m => m.Email)
And created an EditorTemplate named EmailAddress.cshtml with just this line:
#Html.TextBox("", null, new {#class="text-box single-line", type="email", placeholder="Enter an email address"})
I couldn't get the placeholder to show in Chrome until I changed the Display attribute to this:
[Display(Name = "Email address")]
Can someone please describe to me why it didn't work before I changed it? What is the relationship between that attribute and what is generated when I call EditorFor, and how did this change cause the placeholder show up correctly?
Thanks.
in model, the decorator
[Display(Name = "Some Name")]
public string myproperty{get;set;}
is used to display labels in view, which are accessed with
#Html.Labelfor(m=>m.myproperty)
I believe that it got nothing to do with placeholder

Performing client-side validation in MVC4 View against ViewModel

I would like to know what is the best approach to handle client-side, javascript or jQuery driven validation of MVC4 fields against attributes placed on a ViewModel's fields.
First, let's pick the example. A login creation screen for Administrators shown the first time the application starts (just not to say to the site owner "use admin/admin as login the first time").
ViewModel:
public class AdministratorViewModel : AbstractViewModel
{
[Required]
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblUsername")]
public string Username { get; set; }
[Required]
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblEmailAddress")]
[EmailAddress]
public string EmailAddress { get; set; }
[Required]
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblPassword")]
[AdminPassword]
public string Password { get; set; }
[Required]
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblPasswordConfirm")]
[Compare("Password")]
public string PasswordConfirm { get; set; }
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblLastLogin")]
public DateTime? LastLogin { get; set; }
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblPasswordExpiry")]
public DateTime? PasswordExpiry { get; set; }
[Display(ResourceType = typeof(ManageAdminsViewModelResources), Name = "lblBlocked")]
public bool Blocked { get; set; }
}
Partial view (only a few fields needed when creating the first admin)
#using (Html.BeginForm())
{
#Html.ValidationSummary(false)
#Html.AntiForgeryToken()
<fieldset>
<legend>#ManageAdminsViewResources.legendCreateAdmin</legend>
<div class="desktoptile">
#Html.LabelFor(m=>m.Username)
#Html.EditorFor(m => m.Username)
#Html.ValidationMessageFor(m => m.Username)
</div>
<div class="desktoptile">
#Html.LabelFor(m=>m.Password)
#Html.PasswordFor(m => m.Password)
#Html.ValidationMessageFor(m => m.Password)
</div>
<div class="desktoptile">
#Html.LabelFor(m=>m.PasswordConfirm)
#Html.PasswordFor(m => m.PasswordConfirm)
#Html.ValidationMessageFor(m => m.PasswordConfirm)
</div>
<div class="desktoptile">
#Html.LabelFor(m=>m.EmailAddress)
#Html.EditorFor(m => m.EmailAddress)
#Html.ValidationMessageFor(m => m.EmailAddress)
</div>
<input type="submit" value="#ManageAdminsViewResources.btnCreate"/>
</fieldset>
}
Controller
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateFirst(AdministratorViewModel viewModel)
{
if (!ModelState.IsValid) return View(viewModel);
[...................]
Currently
If I enter an invalid email address, an empty password, etc. in the form and hit Submit I'm correctly notified of the errors. Ok, let's go on
What I want
Since I'm doing a Metro-stylish design, I would like that every time the user unfocuses a text box validation for that field occurs.
Writing hard-coded jQuery fragments is not the best option. I would like a data-driven approach, possibly embedded in MVC4 which I'm currently learning.
So, given a ViewModel with standard and custom attributes (for which, no matter what, a little Javascript is required, think about the Org.Zighinetto.AdminPasswordAttribute that checks password complexity), how do I enforce client-side validation the most unobtrusive way, without specifying client-side tags on each and every html tag and writing the least possible amount of code?
Is still there any secret in ASP.NET MVC 4 validation that I have to unhide?
Well, you would have to invoke jQuery validate using jQuery (because it's written in jQuery :))
You could add a global event for your inputs, then invoke it on the blurred element. Something like:
$("input").blur(function () {
$(this).valid();
});
From my (learning) point of view, the correct answer should be:
Explanation:
Validation of common attributes is done by MVC4 automatically when jQuery Unobtrustive Validator is loaded into the page, otherwise only server-side validation is performed.
Most, if not all of MVC4 ValidationAttributes implement IClientValidation. This interface wraps jQuery Validator validation functions in server-side code. It's hard to explain how exactly it works, but saying that this interface returns the name of the client-side function (either provided by jQuery distribution or implemented by user), while basically wrong at least gives the idea to a novice user trying to understand how validation works.
Answer:
Continue using data-driven model/viewmodel annotations.
Check if NuGet package jQuery Unobtrusive Validation is loaded in the page, then implement IClientValidation as needed (I found a tutorial here about multiple errors), fields are validated automatically.

Ajax.BeginForm() with checkbox syntax error

I have an Ajax.BeginForm() in a partial view that contains a CheckBox for a bool value. The model is as follows;
public class ViewBusinessAdd
{
[Required(ErrorMessage="Name must be supplied")]
[Display(Name = "Business Name")]
public string Name { get; set; }
[Required(ErrorMessage = "Contact must be supplied")]
[Display(Name = "Business Contact")]
public string Contact { get; set; }
[Display(Name = "Phone Number")]
public string Number { get; set; }
public string Postcode { get; set; }
public Dictionary<string, string> States { get; set; }
public string AddressRegion { get; set; }
public bool IsFacebookPost { get; set; }
public List<RecommendationViewAttribute> Attributes { get; set; }
}
The CheckBox is rendered using the Html helpers;
<div class="control-group">
<label class="control-label">
#Html.LabelFor(m => m.IsFacebookPost, "Post recommendation")
<img src="~/Content/images/f_logo.png" alt="Facebook" />
</label>
<div class="controls">
#Html.CheckBoxFor(m => m.IsFacebookPost)
</div>
</div>
This produces the following HTML when rendered;
<input data-val="true" data-val-required="The IsFacebookPost field is required." id="IsFacebookPost" name="IsFacebookPost" type="checkbox" value="true" /><input name="IsFacebookPost" type="hidden" value="false" />
When submitting the form with, it produces this error in Chrome;
Uncaught SyntaxError: Unexpected token u
If I remove the CheckBox the form submits without any error. If I convert this to a non-Ajax form, it also submits but that's not going to work with the page design unfortunately.
I'm absolutely stumped on this - I even changed this to a RadioButton and the same behavior exists. Does anyone have any ideas?
Edit: Forgot to add it's a Javascript error.
Edit: The error is coming from jQuery library on the return below;
parseJSON: function( data ) {
// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
}
But this only happens if I use the Razor HTML helpers to generate the checkboxes.
I got bit by this and burned about 6 hours trying to figure out what the issue was. According to the Jquery developers this is intended behavior in 1.9.1. If you use the jQuery Migrate 1.1.1 plugin everything should work, other than the console warnings which I think can be turned off.
http://bugs.jquery.com/ticket/13412
See the bug report, which isn't actually a bug :)
Well it seems there was a bug introduced with jQuery 1.9.1. I've downgraded to 1.8.3 and the Razor helpers for the Checkboxes now work correctly. Steps to downgrade if anyone is interested;
Uninstall-Package jQuery -force
Install-Package jQuery -version 1.8.3

Localizing the fields / attributes on the AccountModel for ASP.NET MVC

I want to localize / globalize the fields on my Login page. I am using ASP.NET MVC 3 Preview 1 with the razor view engine.
Some background
First of all, i've set my routing and added a localization attribute handler so that I can write http://mysite.com/{lang}/{controller}/{action}/{id}. Now this works all good. In my Viewsfolder I've added a Home folder with a corresponding App_LocalResources so far so good. I can even add language files for different languages such as Index.resx and Index.sv.resx`.
The problem
Having a file called Account.resx in the root's App_GlobalResources I of course imagine I should be able to access that from my pages. In my AccountModel.cs ( which came with the installation / template project ) I have added the following to the LogOnModel
public class LogOnModel
{
[Required]
[Display(Name = "UserName", ResourceType = typeof(Account))]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password", ResourceType = typeof(Account))]
public string Password { get; set; }
[Display(Name = "RememberMe", ResourceType = typeof(Account))]
public bool RememberMe { get; set; }
}
I have two files in my App_GlobalResource
Account.resx
Account.sv.resx
And it does in fact take the text from the english / default file. But when I append /sv/ to my URL or even ensure that the culture is swedish, it doesn't change the language to what is in my ``Account.sv.resx`.
An example of what could be in the LogOn.cshtml
<div class="editor-label">
#Html.LabelFor(m => m.UserName)
</div>
Any ideas?
Not MVC 3 specific, however this may help
http://geekswithblogs.net/shaunxu/archive/2010/05/06/localization-in-asp.net-mvc-ndash-3-days-investigation-1-day.aspx

Categories

Resources