custom unobtrusive date validators for dates - c#

Maybe it's just the way my mind works, but I have a very hard time understanding how you're supposed to do custom unobtrusive validators. The C# part is easy enough, but the jqueryui adapters are where i get lost.
I've been trying to make a validator that requires a date to be a certain amount of time in the past. I use this for age validation, to make sure someone has entered a date that is 18 years in the past.
I finally decided to just make it a remote validator, that way the validation uses the same code both client and server side. Still, i'd be interested in the jquery to make this work.
I wish the Data Annotation Extensions had date functions.

You can find a lot of information in Brad Wilson's blog article about unobtrusive validation with asp.net mvc, including creating custom validators.
Based on the following html (should be the output of the TextBox helper)
<input type="text" name="Age"
data-val="true"
data-val-required="This field is required"
data-val-minage="You should be 18 years or older, go get your parents!"
data-val-minage-value="18" />
<input type="submit"/>
You can add the following javascript to get things validated on the client side:
// Extend date with age calculator
Date.prototype.age = function (at) {
var value = new Date(this.getTime());
var age = at.getFullYear() - value.getFullYear();
value = value.setFullYear(at.getFullYear());
if (at < value) --age;
return age;
};
// Add adapter for minimum age validator. Wrap in closure
(function ($) {
$.validator.unobtrusive.adapters.addSingleVal("minage", "value");
} (jQuery));
// Add client side minimum age validator
$.validator.methods.minage = function (value, element, params) {
// If no value is specified, don't validate
if (value.length == 0) {
return true;
}
var dob = new Date(Date.parse(value));
if (dob.age(new Date()) < params || dob == 'Invalid Date') {
return false;
}
return true;
};
Credits for the age calculator are due to Dave
The one thing missing here is globalization, but I figured it was out of the question's scope. btw very easy to implement using the jquery Globalize plugin
Hope this helps

Related

Unable to save Date to salesforce?

To my surprise , its not st.forward thing to do; saving Date to Salesforce .
I'm trying to update one field which is of type Date but it throws me some weird error .
Code :
var objSer = new JavaScriptSerializer();
string json = objSer .Serialize(new{
startdate = sfdcValue
});
MyUpdateMethod("objectName/" + id, json);
I tried to convert date to IS0 8601 standard (as suggested over SO)
1.) DateTime.UtcNow.ToString("s",System.Globalization.CultureInfo.InvariantCulture)
2.) DateTime.UtcNow.ToString("o")
Error Info :
{"message":"Cannot deserialize instance of double from VALUE_STRING
value 2017-05-26T10:31:40.5790708Z or request may be missing a
required field at [line:1, column:2]","errorCode":"JSON_PARSER_ERROR"}
You didn't elaborate on which method you are using to communicate between the server and client. I am using Javascript Remoting (#RemoteAction on the apex method) and I ran into this issue. For me, the date and datetime fields were being expected by Salesforce as date serials (your mileage may vary if using a different access method).
Given I was dealing with a dynamic list of fields, I ended up with a pair of marshall / unmarshall functions on the client that created client-only slave fields I removed before sending the data back to Salesforce (NB: the example below is javascript not c#). In your case, a marshall / unmarshall may take a different approach:
// Provide an client-only date field based on a date serial (SFDC input)
function createDateDerivedField(currentRecord, fieldName) {
Object.defineProperty(currentRecord, fieldName + '__ui', {
enumerable: true,
get: function () {
return currentRecord[fieldName] == null ? null : new Date(currentRecord[fieldName]);
},
set: function(newValue) {
// Update the original field
currentRecord[fieldName] = newValue == null ? null : (new Date(newValue)).getTime(); // Convert back to date serial
}
});
}

MVC format number EU style for both server and client side

I'm searching for days how to format my both double and double? inputs as
decimal = comma and thousand separator =dot
example:
123456.01 ==> 123.456,01
14,02 ==> 14,02
987654321,002 ==> 987.654.321,002
what i did so far:
I checked server/local region setting
add globalization in my web.config
globalization uiCulture="fr-BE" culture="fr-BE
In my model i used the following attribute (but i'm using TextBoxFor)
[DisplayFormat(DataFormatString = "{0:N3}", ApplyFormatInEditMode = true)]
#Html.TextBoxFor( model => model.size, new {tabindex=11, id = "SizTotText", #class = "form-control input-sm calc" })
but
How can I:
1- while user is typing, the number should be formatted ?
I found this solution: how to format input box text as I am typing it
but i cannot switch comma with Dot Fiddle
2- Created Custom helper following this post (changed decimal to double)Post
there are a lot of solution in stackoverflow but none seems to work for me.
I hope my question is clear and sorry for my bad english
EDIT:
I decided to ignore the client formatting, no more dot's and comma but i still have issue with the regional setting.
My application still treating the dot as decimal separator, how can i fix this?
and more funny, it accepts some fields and others not, although they all have the same attribute, settings ... etc see screen shot
The field that has an error is a calculated field
var url = '#Url.Action("CalculateDropPrec", "Drop")';
$('.calc').change(function () {
// get the values of the textboxes
var numUsed = $('#numUseText').val();
var totNumUsed = $('#totNumUseText').val();
$.post(url, { nUsed: numUsed, tUsed: totNumUsed }, function (response) {
$('#precText').val(response);
});
return false;
});
#Html.TextBoxFor(model => model.PerceDropTot, new {data_val = "false", id = "precText", name = "precText", #class = "form-control input-sm drop-read", placeholder = "0.0", #readonly = "readonly" })
public JsonResult CalculateDropPrec(double nUsed, double tUsed)
{
var result = CommonComputation.CalcPrecDrop(nUsed, tUsed);
return Json(result);
}
This is probably not going into the direction you want, but is "number formatting as you type" really desired? the downside is that the behaviour can become very tricky, and I mean also for the user. Assume that you type the number "1234" which becomes "1.234". When the input field is focused again and the caret is placed here: "1.|234", is it clear what happens when Backspace is hit? Is the point removed, or the 1? What happens when the user tries to type , or . manually? All the questions need to be considered. Also, when you POST the value in a FORM, it's not a valid numeric when formatted.
For those reason, even advanced Controls with Numeric Inputs like the Kendo UI NumericTextBox which we use heavily, choose to format a display-only value but not intercept user inputs (try the linked Demo).
But you can also check how cleave.js solves the issue, it does the realtime formatting, but probably uses the browsers culture settings. But personally don't like how it behaves when trying to correct already existing values.

Passing date as string - prevent json.net from parsing date

I have a Web API middle layer which consumes an API which exposes a field which carries a timestamp as string (the field is string and it contains a value like "2016-05-31T14:12:45.753Z").
The proxy classes in the middle tier are generated using Visual Studio from Swagger endpoint and under the hood the object is deserialized using Json.NET.
I can see that the field was received as string (that's good):
inputObject {{ "When": "2016-05-31T14:12:45.753Z" }} Newtonsoft.Json.Linq.JToken {Newtonsoft.Json.Linq.JObject}
However, even though the target field is string the value of inputObject["When"] is a parsed as a timestamp.
inputObject["When"] {31/05/2016 14:12:45} Newtonsoft.Json.Linq.JToken {Newtonsoft.Json.Linq.JValue}
Then
JToken whenValue = inputObject["When"];
if (whenValue != null && whenValue.Type != JTokenType.Null)
{
this.When = ((string)whenValue);
}
In the end this.When is a string with value 31/05/2016 14:12:45.
Is there an option to prevent json.net from parsing the date and then casting it to string again?
Please remember that this transformation happens in auto generated code so I'm looking for some way of decorating the field on the server side which would make Swagger mark it somehow and then the generated classes would avoid the deserialize/serialize issue.
Something like:
[JsonProperty("This really is a string, leave it alone")]
public string When { get; private set; }
(Answering my own question)
I needed a solution quickly and this is my temporary solution, for the record.
I format the date as
"When": "2016-05-31 14:12:45"
and not
"When": "2016-05-31T14:12:45.753Z"
This prevents it from being interpreted. The front end (javascript) code knows that timestamps from the API are UTC and it appends 'Z' before transforming the timestamp to local time and formatting for display, e.g:
<td>{{vm.prettyDateTimeFormat(item.StatusDate+'Z')}}</td>
The ctrl code:
vm.prettyDateTimeFormat = function (dateString)
{
var momentDate = moment(dateString, "YYYY-MM-DD HH:mm:ssZZ");
if (typeof(momentDate) === "undefined" || (!momentDate.isValid()))
{
return dateString;
}
//The format needs to be sortable as it ends up in the grid.
var nicePrettyDate = momentDate.format('YYYY-MM-DD HH:mm:ss');
return nicePrettyDate;
}
As far as I don't like this solution it carried us through the demo. This issue is obviously in the back log now to be addressed properly.
[JsonIgnore]
public string When { get; private set; }

Ordering of attributes makes a difference in C#? Behaving differently in different servers [duplicate]

The question here is similar, but I don't have any domain object inheritance. My field and validation tags are in the following order, but the MustBe18 error and the Required error are the only ones that print. I have several other fields in this model with much more validation, but the order of ValidationAttribute's in the code doesn't seem to matter. jfar's answer in the linked post seems to suggest a helper could be built, but how? How can the order be controlled?
[Required(ErrorMessage = "This field is required")]
[DisplayName("Date of Birth")]
[MustBeValidDate(ErrorMessage = "Must be a valid date")]
[MustBe18(ErrorMessage = "You must be 18 years old")]
[MustNotBeOver100(ErrorMessage = "This caller is too old")]
public string dob { get; set; }
MustBe18 : ValidationAttribute (the overloaded IsValid method)
try
{
DateTime dob = new DateTime(DateTime.Now.AddYears(-18).Year, DateTime.Now.Month, DateTime.Now.Day);
return DateTime.Compare(DateTime.Parse(value.ToString()), dob) <= 0;
}
catch
{
return false;
}
The only way to specify the order is to create your own ModelValidatorProvider which can then order the attributes. This will probably be tricky because you'd also need to create overloads for each attribute that takes an Order parameter ( don't know if they already do ).
If all you mind is the order in which validation summaries appear all you'd need to do is loop through the ModelState entries and spit out the errors from there.

Getting null datetime value from view to controller when i change CultureInfo

net mvc, i have a controller which gets a datetime parameter from view using jquery datepicker and then i pass
the value to the controller using json ,
it all works fine, except when i change language cultureInfo to German in my case, the value of datetime parameter is always null.
This is the controller:
public JsonResult GetDetails(DateTime? from, DateTime? to)
{
//Do something..
}
The model:
public class UsagesModel
{
public DateTime From
{
get;
set;
}
public DateTime To
{
get;
set;
}
}
The view in which data gets chosen and then pass to controller:
<input type="text" id="from" value="#Model.From.ToString("dd/MM/yyyy")" class="datepicker" />
<input type="text" id="to" value="#Model.To.ToString("dd/MM/yyyy")" class="datepicker" />
$("#filter").click(function (e) {
fromdate = $("#from").val();
todate = $("#to").val();
$.getJSON('#Response.ApplyAppPathModifier(#Url.Action("GetDetails"))', {
'from': StringToJSONDate(fromdate),
'to': StringToJSONDate(todate)
}, function (groupusages) {
.....Do Something....
}).error(function (xhr, textStatus, errorThrown) {
//document.location.href = "/Login";
});
});
//function for parsing data to json
function StringToJSONDate(stringDate) {
var dateParts = stringDate.split("/");
var date = new Date(dateParts[2], (dateParts[1] - 1), dateParts[0]);
return date.toJSON();
}
What can i do, where is the problem because it works fine in english and french culture. Please help me!
One thing you could do is to change your method signature to do something like this. You could spend a lot of time working on getting the right format for your mvc app for different cultures.
public JsonResult GetDetails(string from, string to)
{
var fromDate = DateTime.Parse(from);
var toDate = DateTime.Parse(to);
//Do something..
}
As Khan mentioned in his comment, you could make this a DateTime.ParseExact() so that you don't run into other culture issues.
https://msdn.microsoft.com/en-us/library/System.DateTime.ParseExact(v=vs.110).aspx
I do not know the exact change, but it may be because of a difference in the date/time format that Germany uses versus English and French speaking locations. I would try adding in a few alerts from the javascript to see at various points that you have a value there and then see where it gets screwy. I suspect the value still comes through but is not happy with the date formatting, should be a quick fix with some .split("/") and .join("/") function calls and addressing the index of the array

Categories