Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    Decimal point set to , instead of .

    Hy,

    My problem is this:
    For float numbers I need to set the decimal point to , and thousands point to .
    I need to this only in 2 situations: when I display it and when the user edits it.
    The rest of the time it should be as it is normal ( dot for decimal point and comma for thousands point)
    For displaying it I've started from ledfini money data type:
    http://forums.smartclient.com/showth...ighlight=money

    I've done some minor adjustments:
    Code:
    isc.SimpleType.create({
        name:"currency",inheritsFrom:"float",
        normalDisplayFormatter: function(value) {
            return this.shortDisplayFormatter(value);
        },
        shortDisplayFormatter: function(value) {
            // US currency formatter from http://javascript.internet.com/forms/currency-format.html
    
            if (value==undefined)
                return value;
            else {
                value = value.toString().replace(/\$|\./g,'');
                if(isNaN(value))
                value = "0";
                sign = (value == (value = Math.abs(value)));
                value = Math.floor(value*100+0.50000000001);
                cents = value%100;
                value = Math.floor(value/100).toString();
                if(cents<10)
                cents = "0" + cents;
                for (var i = 0; i < Math.floor((value.length-(1+i))/3); i++)
                value = value.substring(0,value.length-(4*i+3))+'.'+value.substring(value.length-(4*i+3));
    
                return (((sign)?'':'-') + value + ',' + cents);
            }
        }
    });
    But when I'm trying to edit everything goes wrong.

    Any help would be great.

    Thanks,
    John
    Last edited by JohnBlack; 29 May 2008, 10:24.

    #2
    Hy,

    Sorry to insit on it but any idea anybody?

    Comment


      #3
      Looks correct to me. What problem do you have when you try to edit the value?

      Comment


        #4
        Hy ledifni,

        First thanks for answering!


        The problem is that when using "," for decimal point the value is not transformed to a valid float and I get an error from inherited type float. So if I'll trye to input a number like this: "1.234,56" I'll get "Mut be a valid decimal" .

        In fact even in your moneyType (where you use the normal way) for example if you try to input $1,234.56 it will fail. It works only for 1234.56 .


        What I'm looking si something similar to :
        Date.setInputFormat
        Date.setShortDisplayFormat(myFormat)
        where the date type is preserved.
        Similar to that I want float type to be preserved (and that's why I don't want to use the text type as inherited type - not mentioning that evrithing will go apart - from sorting to adding/updateing data in my backend)

        Comment


          #5
          Well, I think in general the problem is that a string like, e.g., "$1,234.56" cannot be auto-converted to a float in any modern programming language or database engine. The same would apply to a string like "1.234,56", except in languages where a culture (and thus a number format) can be specified for automatic string-to-number conversion. But even in that case, a thousands separator generally will not be accepted, though a decimal comma should be.

          Since the DynamicForm renders a "float" field type as a text field, it should not return any errors unless you have validators specified. If you do have validators specified, you will have to override the validator code to permit those formats. However, I am guessing that the error you're receiving happens either when you try to send it to a web service (in which case the web service may refuse the value if it expects a float), or once you try to save it to your database. In other words, you need to make sure that the underlying value is a float, while the display permits the format you're looking for. The shortDisplayFormatter and normalDisplayFormatter functions are really only relevant to StaticTextItems and DetailViewers, where an underlying value is being displayed but not edited.

          I would recommend something like this:

          Code:
          // when creating form fields, set editorType: "NumberItem" to use this class
          isc.ClassFactory.defineClass("NumberItem","TextItem");
          
          isc.NumberItem.addProperties({
            mapDisplayToValue: function(displayValue) {
              var value = displayValue.toString().replace(/\./g,''); // strip out thousands separators
              value = value.replace(/,/g,".");  // replace decimal comma with decimal point
              
              if (isNaN(value))
                value=null;  // you should also create a validator that will not permit invalid entry
          
              return parseFloat(value);
            },
            mapValueToDisplay: function(internalValue) {
              var value = internalValue.toString().replace(/\./g,","); // replace decimal point with decimal comma
              
              // insert thousands separators
              var exp=new RegExp('(^\,-?[0-9]+)([0-9]{3})');
              while (exp.test(value)) {
                value = value.replace(exp,"$1.$2");
              }
          
              return value;
            }
          });
          Warning: I have not tested the above code. It may have errors. I believe it's correct, though.

          Comment


            #6
            Hy Isomorphic ,ledifni,

            Well, I think in general the problem is that a string like, e.g., "$1,234.56" cannot be auto-converted to a float in any modern programming language or database engine. The same would apply to a string like "1.234,56", except in languages where a culture (and thus a number format) can be specified for automatic string-to-number conversion. But even in that case, a thousands separator generally will not be accepted, though a decimal comma should be.
            That was out of the question from the start. :))

            Moving to the problem :) the code that you've posted worked great.
            10x a lot for the help.

            More, I combined both examples with a little tweak and something nice came out:
            Code:
            isc.ClassFactory.defineClass("NumberItem","TextItem");
            
            isc.NumberItem.addProperties({
              mapDisplayToValue: function(displayValue) {
                var value = displayValue.toString().replace(/\./g,''); // strip out thousands separators
                value = value.replace(/,/g,".");  // replace decimal comma with decimal point
            
                if (isNaN(value))
                  value=null;  // you should also create a validator that will not permit invalid entry
            
                return parseFloat(value);
              },
              mapValueToDisplay: function(internalValue) {
             if ((internalValue==undefined) || (internalValue=='') || isNaN(internalValue))
                      return '';
                    else {
                 var value = internalValue.toString().replace(/\./g,","); // replace decimal point with decimal comma
            
                 // insert thousands separators
                 var exp=new RegExp('(^\,-?[0-9]+)([0-9]{3})');
                 while (exp.test(value)) {
                   value = value.replace(exp,"$1.$2");
                 }
                 return value;
               }
              }
            });
            
            isc.SimpleType.create({
                name:"currency",inheritsFrom:"float",
                normalDisplayFormatter: function(value) {
                    return this.shortDisplayFormatter(value);
                },
                shortDisplayFormatter: function(value) {
                    // US currency formatter from http://javascript.internet.com/forms/currency-format.html
            
                    if (value==undefined)
                        return value;
                    else {
                        value = value.toString().replace(/\$|\,/g,'');
                        if(isNaN(value))
                        value = "0";
                        sign = (value == (value = Math.abs(value)));
                        value = Math.floor(value*100+0.50000000001);
                        cents = value%100;
                        value = Math.floor(value/100).toString();
                        if(cents<10)
                        cents = "0" + cents;
                        for (var i = 0; i < Math.floor((value.length-(1+i))/3); i++)
                        value = value.substring(0,value.length-(4*i+3))+'.'+value.substring(value.length-(4*i+3));
            
                        return (((sign)?'':'-') + value + ',' + cents);
                    }
                }
            });
            
            
            
            
            
              contactsData = [
                {salutation:"1",bani:"12.34", firstname:"John", lastname:"Black"},
                {salutation:"2",bani:"312.34", firstname:"Kathy", lastname:"Whitting"},
                {salutation:"3",bani:"5512.34",firstname:"Gwen",lastname:"Glover"}
                ]
            
            isc.DataSource.create ({
              ID:"contactsDS",
              fields: [
               {name:"salutation",title:"Title", valueMap:{"1":"Mr","2":"Ms","3":"Mrs"}},
               {name:"firstname",title:"First Name"},
               {name:"lastname", title:"Last Name"},
               {name:"bani", title:"Bani", type:"currency", editorType:"NumberItem", validator:[
                {type:"floatRange", min:0, max:10000}]}
               ],
               clientOnly: true,
               testData: contactsData
              })
            
            isc.ListGrid.create ({
              ID: "contactsList",
              left:50,
              top:50,
              width:550,
              alternateRecordStyles:true,
              canEdit:true,
              editEvent:"click",
              modalEditing:true,
              dataSource:contactsDS,
              showFilterEditor: true,
              autoFetchData: true
             })
            Now, looking in the Dev Console here is what I've seen:
            Code:
            23:49:43.890:TMR9:INFO:gridEdit:contactsList:Starting editing at row 0, colNum 3
            23:49:43.890:TMR9:INFO:gridEdit:contactsList:establishing new edit session at row: 0, col:3 with values: {}
            23:49:43.890:TMR9:DEBUG:gridEdit:contactsList:showing inline editor at: 0,3, will focus: true
            23:49:43.890:TMR9:DEBUG:gridEdit:contactsList:editRowForm created with values: {salutation: "1",
            bani: "12.34",
            firstname: "John",
            lastname: "Black",
            _selection_2: true}
            23:50:00.125:KPR4:INFO:gridEdit:contactsList:cellEditEnd: ending editing, completion event: enter
            23:50:00.125:KPR4:DEBUG:gridEdit:contactsList:change detection: newValues: {bani: 15.78}, oldValues: {salutation: "1",
            bani: "12.34",
            firstname: "John",
            lastname: "Black"}
            23:50:00.125:KPR4:DEBUG:gridEdit:contactsList:At field: bani applying validators: [
            {type: "isFloat",
            typeCastValidator: true,
            _generated: true,
            stopIfFalse: true}
            ] to value:15.78
            23:50:00.140:KPR4:INFO:gridEdit:contactsList:validateFieldValue, newValue: 15.78, passed validation: true, resultingValue: 15.78
            23:50:00.140:KPR4:INFO:gridEdit:contactsList:Saving newValues '{bani: 15.78}'
            More clearly I've seen that Smart Client do the normal typeCastValidator:
            Code:
            23:50:00.125:KPR4:DEBUG:gridEdit:contactsList:At field: bani applying validators: [
            {type: "isFloat",
            typeCastValidator: true,
            _generated: true,
            stopIfFalse: true}
            ] to value:15.78
            23:50:00.140:KPR4:INFO:gridEdit:contactsList:validateFieldValue, newValue: 15.78, passed validation: true, resultingValue: 15.78
            Now how can I define/use for instance a floatRange validator (i've tried to define one in the usually way but dindn't work).

            Thanks a lot for help,
            John

            Comment


              #7
              Haha,
              I've re-examined my code :) It is validators not validator

              here is an inproved one:
              Code:
              isc.ClassFactory.defineClass("NumberItem","TextItem");
              
              isc.NumberItem.addProperties({
                mapDisplayToValue: function(displayValue) {
                  var value = displayValue.toString().replace(/\./g,''); // strip out thousands separators
                  value = value.replace(/,/g,".");  // replace decimal comma with decimal point
              
                  if (isNaN(value))
                    value=null;  // you should also create a validator that will not permit invalid entry
              
                  return parseFloat(value);
                },
                mapValueToDisplay: function(internalValue) {
               if ((internalValue==undefined) || (internalValue=='') || isNaN(internalValue))
                        return '';
                      else {
                   var value = internalValue.toString().replace(/\./g,","); // replace decimal point with decimal comma
              
                   // insert thousands separators
                   var exp=new RegExp('(^\,-?[0-9]+)([0-9]{3})');
                   while (exp.test(value)) {
                     value = value.replace(exp,"$1.$2");
                   }
                   return value;
                 }
                }
              });
              
              isc.SimpleType.create({
                  name:"currency",inheritsFrom:"float",
                  normalDisplayFormatter: function(value) {
                      return this.shortDisplayFormatter(value);
                  },
                  shortDisplayFormatter: function(value) {
                      // US currency formatter from http://javascript.internet.com/forms/currency-format.html
              
                      if (value==undefined)
                          return value;
                      else {
                          value = value.toString().replace(/\$|\,/g,'');
                          if(isNaN(value))
                          value = "0";
                          sign = (value == (value = Math.abs(value)));
                          value = Math.floor(value*100+0.50000000001);
                          cents = value%100;
                          value = Math.floor(value/100).toString();
                          if(cents<10)
                          cents = "0" + cents;
                          for (var i = 0; i < Math.floor((value.length-(1+i))/3); i++)
                          value = value.substring(0,value.length-(4*i+3))+'.'+value.substring(value.length-(4*i+3));
              
                          return (((sign)?'':'-') + value + ',' + cents);
                      }
                  },
                  editorType:"NumberItem",
                  validators:[
                     {type:"floatRange", min:0, max:10000}
                   ]
              });
              Hope this helps others :))
              Last edited by JohnBlack; 17 Jun 2008, 03:46.

              Comment


                #8
                That's pretty neat, thanks for sharing that.

                We do plan to add editing-specific formatter and parser APIs (like ListGrid's formatEditorValue and parseEditorValue) to make it possible to encapsulate a type like this completely within a SimpleType declaration.

                Comment


                  #9
                  Hello Isomorphic,

                  have you realised your plans of "editing-specific formatter and parser APIs" within the comming SmartClient Version 7? We are wondering if number-i18n (eg decimal comma) for edit-operations and displaying are included too.

                  Comment


                    #10
                    Hello again,

                    I used a modified version of the code above in our actual project. The plan is to displaying all numbers (+ editing) as set in the user-profile. First step: german format.

                    Code:
                    isc.ClassFactory.defineClass("GsnumberItem", "TextItem");
                    isc.GsnumberItem.addProperties( {
                    	mapDisplayToValue : function(displayValue) {
                    		var value = displayValue.toString().replace(/\./g, '');
                    		value = value.replace(/,/g, ".");
                    
                    		if (isNaN(value))
                    			value = null;
                    
                    		return parseFloat(value);
                    	},
                    	mapValueToDisplay : function(internalValue) {
                    		if ((internalValue == undefined) || (internalValue == '')
                    				|| isNaN(internalValue))
                    			return '';
                    		else {
                    			var value = internalValue.toString().replace(/\./g, ","); 
                    			var exp = new RegExp('(^\,-?[0-9]+)([0-9]{3})');
                    			while (exp.test(value)) {
                    				value = value.replace(exp, "$1.$2");
                    			}
                    			return value;
                    		}
                    	}
                    });
                    isc.SimpleType.create( {
                    	name :"gsnumber",
                    	inheritsFrom :"float",
                    	normalDisplayFormatter : function(internalValue) {
                    		return this.shortDisplayFormatter(internalValue);
                    	},
                    	shortDisplayFormatter : function(internalValue) {
                    		if ((internalValue == undefined) || (internalValue == '')
                    				|| isNaN(internalValue))
                    			return '';
                    		else {
                    			var value = internalValue.toString().replace(/\./g, ",");
                    			var exp = new RegExp('(^\,-?[0-9]+)([0-9]{3})');
                    			while (exp.test(value)) {
                    				value = value.replace(exp, "$1.$2");
                    			}
                    			return value;
                    		}
                    	},
                    	editorType :"GsnumberItem"
                    });
                    We added "type: 'gsnumber'" to the field-decarations of some datasources. It works great: All internal float values are shown as 'german' numbers (eg. 123,22), getValue() delivers a real float for internal usage (123.22 / as requested) and editing throug dynamic forms works fine too.

                    BUT: We override or forgot to override the mechanism to deactivate formfields. When we set one field of a dynamic form to "type: 'gsnumber'" and "canEdit: false" the field can although be edited. When we set the type to "float" as before the "canEdit" attribute works fine.

                    Can you see the mistake?

                    Comment


                      #11
                      It seems very unlikely that this could be related to your simpleType definition. Can you show the code for the actual grid and DataSource where you see this difference?

                      And have you checked for canEdit:"false" (incorrect) vs canEdit:false (correct) ?

                      Comment


                        #12
                        As example I added the code to your "Form Layout"-Title-Example (Field Username):

                        Code:
                        isc.ClassFactory.defineClass("GsnumberItem", "TextItem");
                        isc.GsnumberItem.addProperties( {
                         mapDisplayToValue : function(displayValue) {
                          var value = displayValue.toString().replace(/\./g, '');
                          value = value.replace(/,/g, ".");
                          if (isNaN(value))
                           value = null;
                          return parseFloat(value);
                         },
                         mapValueToDisplay : function(internalValue) {
                          if ((internalValue == undefined) || (internalValue == '')
                            || isNaN(internalValue))
                           return '';
                          else {
                           var value = internalValue.toString().replace(/\./g, ","); 
                           var exp = new RegExp('(^\,-?[0-9]+)([0-9]{3})');
                           while (exp.test(value)) {
                            value = value.replace(exp, "$1.$2");
                           }
                           return value;
                          }
                         }
                        });
                        isc.SimpleType.create( {
                         name :"gsnumber",
                         inheritsFrom :"float",
                         normalDisplayFormatter : function(internalValue) {
                          return this.shortDisplayFormatter(internalValue);
                         },
                         shortDisplayFormatter : function(internalValue) {
                          if ((internalValue == undefined) || (internalValue == '')
                            || isNaN(internalValue))
                           return '';
                          else {
                           var value = internalValue.toString().replace(/\./g, ",");
                           var exp = new RegExp('(^\,-?[0-9]+)([0-9]{3})');
                           while (exp.test(value)) {
                            value = value.replace(exp, "$1.$2");
                           }
                           return value;
                          }
                         },
                         editorType :"GsnumberItem"
                        });
                        
                        
                        
                        
                        isc.DynamicForm.create({
                            ID: "exampleForm",
                            width: 250,
                            fields: [
                                {name: "username",
                                 title: "Username",
                                 type: "gsnumber",
                                 canEdit: false,
                                 defaultValue: 1234
                                },
                                {name: "email",
                                 title: "Email",
                                 required: true,
                                 type: "text",
                                 defaultValue: "bob@isomorphic.com"
                                },
                                {name: "password",
                                 title: "Password",
                                 required: true,
                                 type: "password"
                                },
                                {name: "password2",
                                 required: true,
                                 title: "Password again",
                                 type: "password"
                                }
                            ]
                        });
                        
                        isc.Button.create({
                            left: 300,
                            title: "Swap titles",
                            click: function () {
                                exampleForm.setTitleOrientation(exampleForm.titleOrientation == "top" ? "left" : "top");
                            }
                        });
                        Change the type of the field Username to whatever you want and the canEdit attribute will work fine.

                        Comment


                          #13
                          I have searched for a mistake of my own, but I couldn't find one. Have you discovered the reason or even now found a solution?

                          Comment


                            #14
                            Hi gravityshock,

                            It's a precedence issue - canEdit:false effectively flips the editorType of the field to "StaticTextItem", but in this case your explicit setting for editorType overrides. We haven't figured out yet whether this is the right behavior or too subtle. In the meantime, instead of setting canEdit:false, you can set editorType:"StaticTextItem" to disable editing in both this case and for any other form items.

                            Comment


                              #15
                              Thanks for the workaround. We have tested it on some elements and it works fine. But a generel solution would be nice. We have dozens of dynamic forms and dozens of grids too. Changing all would cost 1-2 man-days.

                              Can we access the canEdit-Parameter within the SimpleType "gsnumber"? Then we could write insted of
                              Code:
                              isc.SimpleType.create( {
                               name :"gsnumber",
                               ....
                               editorType : "GsnumberItem"
                              }
                              something like this:
                              Code:
                              isc.SimpleType.create( {
                               name :"gsnumber",
                               ....
                               editorType : function(){
                                 if(xyz.canEdit == false)
                                   return "StaticTextItem";
                                 else
                                   return "GsnumberItem";
                               }
                              }

                              Comment

                              Working...
                              X