MVC3 edit for decimal fields and localization - asp.net-mvc

My locale uses a comma ,, and not a dot . for decimal separator.
In MVC3, when I open an Edit view where the decimal values are shown with
#Html.EditorFor(model => model.MyDecimalVal)
the value is shown correctly.
When I enter value with comma, I get error "Value is not a number" and if I enter value with dot, I get no error, but actually no value is saved.
How to handle this situation?

This blog post recommends overriding the default jQuery validate number and range rules in order to enable client-side support of the comma decimal separator.
To fix these problems, we can take the default implementation from the
jquery.validate.js file for the range() and number() functions. We
then create another .js file (say jQueryFixes.js), in which we
override these default functions with ones that contain support for
the comma as a decimal separator. The contents of the file should be
something like this:
$.validator.methods.range = function (value, element, param) {
var globalizedValue = value.replace(",", ".");
return this.optional(element) || (globalizedValue >= param[0] && globalizedValue <= param[1]);
}
$.validator.methods.number = function (value, element) {
return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:[\s\.,]\d{3})+)(?:[\.,]\d+)?$/.test(value);
}

Getting around with this by tweaking your validation logic has been already explained so here is a different approach.
Put the below code inside your web.config file under the <system.web> node if you would like to set the culture to en. It will take care of decimal delimiter:
<globalization culture="en-US" uiCulture="en" />
I am not sure but for DateTime, you are still bound to your server's locale.

Related

Can't enter space in textfield using forced uppercase textfield-formatter add-on in Vaadin 8

With the TextField Formatter add-on for Vaadin 8, I can do the following to allow only upper-case characters:
Options options = new Options();
options.setBlocks(dataLen);
if (format[1].equalsIgnoreCase("UPPER"))
options.setForceCase(ForceCase.UPPER);
new CustomStringBlockFormatter(options).extend(field);
However, after setting forced uppercase I can't enter space characters any longer. Does anyone how I can allow spaces as well as forced upper case characters?
The TextField Formatter add-on doesn't support arbitrary groupings.The setBlocks in method in Options determines the fixed space-separated groups, so you can specify e.g. options.setBlocks(3,3,2) to allow entering text in the format of XXX XXX XX. If you want to allow only capitals, but spaces allowed in the middle in any position, like so that both HELLO WORLD and HI WORLD are allowed, you can use a CSS trick to set the letters print in all uppercase. Add the following rule in your theme .scss file:
input.upper-textfield {
text-transform:uppercase;
}
and define your TextField without a formatter, like this:
TextField textField = new TextField("only upper");
textField.setStyleName("upper-textfield");
textField.setMaxLength(dataLen);
Now you just need to remember to change the text to uppercase in Java as well when you read it:
String value = textField.getValue();
if (value != null) {
value = value.toUpperCase();
}

grails and double values saving

In my Grails project I have a Domain Class with a double field as follows:
double totalAmount;
the value of this field are calculated by a sum done after selecting values in a multiple select. the function for sum values is in the controller, as follows:
def sumReceiptItems(){
params.list("receiptItemsSelected").each {i-> println("element "+i)}
def appList = params.list("receiptItemsSelected")
List<ReceiptItem> allSelectedIds = ReceiptItem.findAllByIdInList(params.receiptItemsSelected.split(',')*.toLong())
def totalAmount = allSelectedIds.amount.sum()
println("totalAmount is = "+totalAmount)
render totalAmount as Double
}
the function works well. After function calling, to update the field in GSP page, I use a javascript method as follows:
function updateTotalAmount(name, data, presentNullAsThis){
if(data !=null)
document.getElementById(name).value= data;
else
document.getElementById(name).value=presentNullAsThis;
}
The javascript works and I see the updating of the field at runtime, but the double value is shown with a dot, and not with comma to separate decimal values. Infact, after clicking by save button to save the instance of the domain class, the value is saved without separating decimals, for example:
if the value into the fiels is 10.50 it is stored as 1050
In this discussion how can save a double type correctly in grails? I've read a similar problem, but solution is not good for my issue.
Anybody can help me?
Values with decimal separator depends on the current Locale of the user. Normally you use g.formatNumber in the view to display correctly the value.
You can check this topic on how to discover the decimal separator for a Locale.
To get the user's Locale use:
Locale locale = RequestContextUtils.getLocale(request)
I have solved the problem in this way:
I've updated my Javascript as follows:
function updateTotalAmount(name, data, presentNullAsThis)
{
var data2 = data.toString().replace(/\./g, ',');
if(data2 != null) document.getElementById(name).value= data2;
else document.getElementById(name).value= presentNullAsThis;
}
I've removed "type="number"" in the gsp related field

Override Grails Error Messages to format Dates and Numbers

I have created a domain with a Double field. When the validation occurs it throws the error message with size value showing the number with commas. Following are the detials
Groovy Class
class Quote {
String content;
Double size;
static constraints = {
content(maxSize:1000, blank:false)
size(min: 0.00D, max:999.99D)
}
}
Value entered "11111", error obtained "Size 11,111 is exceeded the limit". I have added the property key/value pair in messages.properties.
Here, I would like to get the message back without the commas. My main aim is to take the key and format the message returned based on my requirements. I require this as I have other fields that need conversion. For example, a date is validated but when showing the error the Gregorian date needs to be converted to an Islamic date and shown to user.
Does anyone know if I can do something to make this work.
I have tried the solution provided in http://ishanf.tumblr.com/post/434379583/custom-property-editor-for-grails but this did not work.
I have also tried modifying the messages values, but this is not flexible in case of my date issue. Example, for a key value pair, instead of using {2} as a place holder I could use {2, date, mm/dd/yyyy}, but for Islamic dates I want to format and show things differently.
Also, please note I have created a separate key for default date formatting for my application.
Would appreciate the help.
In grails, the return of a constrain is an already translated string.
You can create a taglib to format that, or enhance the
Another option would be custom validators. A custom validator can return false or a key when failing.
For example in your domain class, to vaildate a field:
myDateField validator: {val, obj -> obj.myShinyDateValidatorMethod(val) }
private myShinyDateValidatorMethod() {
if (isNotValidDate(val) {
return [the_message_key, val.formatedAsYouWand]
}
}
and, in your properties file you have to have defined the key:
the_message_key=This date: {3} is not valid
The trick here is that in the return from the validator, first string is the key and the rest are parameters for that key, but grails already uses {0}, {1}, {2} placeholders for className, fieldName and value, and the first parameter that you pass will be used as {3} placeholder.
Hope this helps

Int32.ParseInt throws FormatException after web post

Update
I've found the problem, the exception came from a 2nd field on the same form which indeed should have prompted it (because it was empty)... I was looking at an error which I thought came from trying to parse one string, when in fact it was from trying to parse another string... Sorry for wasting your time.
Original Question
I'm completely dumbfounded by this problem. I am basically running int.Parse("32") and it throws a FormatException. Here's the code in question:
private double BindGeo(string value)
{
Regex r = new Regex(#"\D*(?<deg>\d+)\D*(?<min>\d+)\D*(?<sec>\d+(\.\d*))");
Regex d = new Regex(#"(?<dir>[NSEW])");
var numbers = r.Match(value);
string degStr = numbers.Groups["deg"].ToString();
string minStr = numbers.Groups["min"].ToString();
string secStr = numbers.Groups["sec"].ToString();
Debug.Assert(degStr == "32");
var deg = int.Parse(degStr);
var min = int.Parse(minStr);
var sec = double.Parse(secStr);
var direction = d.Match(value).Groups["dir"].ToString();
var result = deg + (min / 60.0) + (sec / 3600.0);
if (direction == "S" || direction == "W") result = -result;
return result;
}
My input string is "32 19 17.25 N"
The above code runs on a .NET 4 web hosting service (aspspider) on an ASP.NET MVC 3 web application (with Razor as its view engine).
Note the assersion of degStr == "32" is valid! Also when I take the above code and run it in a console application it works just fine. I've scoured the web for an answer, nothing...
Any ideas?
UPDATE (stack trace)
[FormatException: Input string was not in a correct format.]
System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) +9586043
System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) +119
System.Int32.Parse(String s) +23
ParkIt.GeoModelBinder.BindGeo(String value) in C:\MyProjects\ParkIt\ParkIt\GeoBinder.cs:42
Line 42 is var deg = int.Parse(degStr); and note that the exception is in System.Int32.Parse (not in System.Double as was suggested).
You are wrongly thinking that it is the following line that is throwing the exception:
int.Parse("32")
This line is unlikely to ever throw an exception.
In fact it is the following line:
var sec = double.Parse(secStr);
In this case secStr = "17.25";.
The reason for that is that your hosting provider uses a different culture in which the . is not a decimal separator.
You have the possibility to specify the culture in your web.config file:
<globalization culture="en-US" uiCulture="en-US" />
If you don't do that, then auto is used. This means that the culture could be set based on the client browser preferences (which are sent with each request using the Accept-Language HTTP header).
Another possibility is to specify the culture when parsing:
var sec = double.Parse(secStr, CultureInfo.InvariantCulture);
This way you know for sure that . is the decimal separator for the invariant culture.
Testing this (via PowerShell):
PS [64] E:\dev #43> '32 19 17.25 N' -match "\D*(?\d+)\D*(?\d+)\D*(?\d+(\.\d*))"
True
PS [64] E:\dev #44> $Matches
Name Value
---- -----
sec 17.25
deg 32
min 19
1 .25
0 32 19 17.25
So the regex is working with all three named captures getting a value, all of which will parse OK (ie. it isn't something like \d matching something like U+0660: ARABIC-INDIC DIGIT ZERO that Int32.Parse doesn't handle).
But you do not check that the regex actually makes a match.
Therefore I suspect that the value passed to the function is not the input you expect. Put a breakpoint (or logging) at the start of the function and get the actual value of value.
I think what is happening is:
Value isn't what you think it is.
The regex fails to match.
The captures are empty
Int32.Parse("") is throwing (just confirmed: it throws a FormatException "Input string was not in a correct format.")
Adendum: Just noted you comment on the assertion.
If things seem contradictory go back to basics: at least one of your assumptions is wrong eg. there could be an off by one in the exception's line number (an edit to the file before going to that line number: very easy to do).
Stepping through with a debugger in this case is by far the easiest approach. On every expression check everything.
If you cannot use a debugger then try and remove that restriction, if not how about IntelliTrace? Othewrwise use some kind of logging (if you app doesn't have it, add it as you'll need it in the future for things like this).
try remove non unicode ( if any - non-visible) chars from string :
string s = "søme string";
s = Regex.Replace(s, #"[^\u0000-\u007F]", string.Empty);
edit
also - try to see its hex values to see where it is doing exceptio n :
BitConverter.ToString(buffer);
this will show you the hex values so you can verify...
also paste its value so we can see it.
It turns out that this is a non-question. The problem was that the exception came from a 2nd field on the same form which indeed should have prompted it (because it was empty)... I was looking at an error which I thought came from trying to parse one string, when in fact it was from trying to parse another string...
Sorry for wasting your time.

jQuery Mobile Filtered List - only match beginning of string

Im using the jQuery mobile search filter list:
http://jquerymobile.com/test/docs/lists/lists-performance.html
Im having somer performance issues, my list is a little slow to filter on some phones. To try and aid performance I want to change the search so only items starting with the search text are returned.
So 'aris' currently finds the result 'paris' but I want this changed. I can see its possible from the documentation below but I dont know how to implement the code.
http://jquerymobile.com/test/docs/lists/docs-lists.html
$("document").ready( function (){
$(".ui-listview").listview('option', 'filterCallback', yourFilterFunction)
});
This seems to demonstrate how you write and call your own function, but ive no idea how to write it! Thanks
http://blog.safaribooksonline.com/2012/02/14/jquery-mobile-tip-write-your-own-list-view-filter-function/
UPDATE - Ive tried the following in a seperate js file:
$("document").ready( function (){
function beginsWith( text, pattern) {
text= text.toLowerCase();
pattern = pattern.toLowerCase();
return pattern == text.substr( 0, pattern.length );
}
$(".ui-listview").listview('option', 'filterCallback', beginsWith)
});
might look something like this:
function beginsWith( text, pattern) {
text= text.toLowerCase();
pattern = pattern.toLowerCase();
return pattern == text.substr( 0, pattern.length );
}
Basically you compare from 0 to "length" of what you're matching to the source. So if you pass in "test","tester" it will see you're passing in a string of length 4 and then substr "tester" from 0,4, which gives you "test". Then "test" is equal to "test"... so return true. Lowercase them to make it case insensitive.
Another trick to improve filter performance, only filter once they've entered more than 1 character.
edit it appears jQueryMobile's filter function expects that "true" means it was not found... so it needs to be backwards. return pattern != text.substr( 0, pattern.length );
This worked for me. I am using regular expression here so sort of different way to achieve the same thing.
But the reason why my code didn't work initially was that the list item had a lot of spaces at the beginning and at the end (found that it got added on it's own while debugging).
So I do a trim on the text before doing the match. I have a feeling Jonathan Rowny's implementation will also work if we do text.trim() before matching.
$(".ui-listview").listview('option', 'filterCallback', function (text, searchValue) {
var matcher = new RegExp("^" + searchValue, "i");
return !matcher.test(text.trim());
});

Resources