Input Mask on Mobile for Currency

Hello


I need some help with masking a currency field on a mobile app please. 


On the app I have a form with a decimal input field that has to be displayed in this format $4,545.87  (Dollar sign, "," as group seperator and "." as decimal seperator, 2 decimals at the end.


I have tried all the mobile mask components on the forge but none seems to do what I want. The best one is this one but it does not work either.  https://www.outsystems.com/forge/component-overview/2258/input-masks-mobile


On this component above the masks works relatively well and the value is saved correctly to the database. However, when the data is displayed from the database it displays incorrectly. It displays 100 times smaller than the database value if there is no decimals.


E.g. if I type the value 250 into the mask, it will save to the database as 250 but when I come back to the screen and display the value, it displays as 2.50.


If I type 250.01 it will save correctly and display correctly. 


Please see an example of the problem on this link: https://bfs-dev.outsystemsenterprise.com/PreviewInDevices/?IsMobilePreview=True&DeviceName=Smartphone&URL=/TestMask/Screen1?_ts=636898092027915086


I am attaching an OML as well.


Does anyone has any suggestions on how I can get this mask to work please? I am not a very technical developer and my javascript knowledge is zero.


Any help will be appreciated.


Thanks!



Hi Vonnelize,

I tried your example.
Created one Order (Order 5) with value 4545.87

Following is result:
Input :  $4,545.87
DB Value : 4545.87

Isn't this correct behavior?
Did you fix the problem?

Regards,

Hi Palek

Thanks for the feedback. It works when you have decimals eg $250.55

It does not work when there is no decimals eg $250.00, then it will show $2.50. Have a look at Order 1 in my example please.

I have not been able to fix it yet.

V



Hi Vonnelize,

I tried value $250.00 and its showing DB values correctly.
I also checked your record for Order 1.

For entering Value 250 in DB, you have to put $250.00 in input field. If you will add only $250, it will show $2.50 in input field and 2.5 in DB.
Please check below image.


If you don't want this behavior then please provide me any reference which is working correctly on any website ,where I can identify the different pattern.

Thanks & Regards,
Palak Patel

Hello Vonnelize,

the problem seems to be that the input mask you are using always interprets the last two digits of the stored value as the decimals, while the decimal-format of the value doesn't save trailing zeros (for reference: a stored value of 2.5 is shown as $0.25). This is similar to this problem https://www.outsystems.com/forums/discussion/35103/error-covnerting-data-type-decimal-to-decimal/ in that displaying a stored decimal value can be tricky.

The way I'd deal with this would be to not use the mask and not input the value as a number, but to use Text for input and output and convert between text and decimal data types. This would allow you to perform text-based checks in the OnAfterFetch-action, like

If(
 Index(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue), ".", searchFromEnd: True) = 1, 
  TextToDecimal(Concat(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue),"0")), 
  If(Index(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue), ".", searchFromEnd: True) = -1, 
   TextToDecimal(Concat(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue),".00")), 
   GetOrderById.List.Current.Order.CurrencyValue)
)

This would add the trailing zeros based on how many decimal places were stored with it. To display the stored value in an expression you could also potentionaly use function "format/formatcurrency" (like the others I used to be found under the built-in functions).

Similary, if you don't want to convert between decimal and text, you could try to continue using the input mask and the function "Mod(n,m)" to determine if you have less than 2 decimal places in your stored value, and then (temporarily) mulitply by 10 or 100. You just need to remember to divide by the same number again if the value doesn't get changed, since you'll increase the stored number everytime someone displays it otherwise.


I am sure there are more elegant ways to solve this, although they might involve JavaScript. I hope this helps.

Best regards,
Michael

Palak Patel wrote:

Hi Vonnelize,

I tried value $250.00 and its showing DB values correctly.
I also checked your record for Order 1.

For entering Value 250 in DB, you have to put $250.00 in input field. If you will add only $250, it will show $2.50 in input field and 2.5 in DB.
Please check below image.


If you don't want this behavior then please provide me any reference which is working correctly on any website ,where I can identify the different pattern.

Thanks & Regards,
Palak Patel


Hello, The value is always saving correctly to the database. If I only type 25000 and if I type 250.00.  The mask displays correctly while you are typing the value. The problem is when you come back to the same record and display the value from the database that was saved earlier. Then it displays incorrectly because the value in the database is not saved with the decimal e.g. 250.00. 

Michael Segbers wrote:

Hello Vonnelize,

the problem seems to be that the input mask you are using always interprets the last two digits of the stored value as the decimals, while the decimal-format of the value doesn't save trailing zeros (for reference: a stored value of 2.5 is shown as $0.25). This is similar to this problem https://www.outsystems.com/forums/discussion/35103/error-covnerting-data-type-decimal-to-decimal/ in that displaying a stored decimal value can be tricky.

The way I'd deal with this would be to not use the mask and not input the value as a number, but to use Text for input and output and convert between text and decimal data types. This would allow you to perform text-based checks in the OnAfterFetch-action, like

If(
 Index(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue), ".", searchFromEnd: True) = 1, 
  TextToDecimal(Concat(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue),"0")), 
  If(Index(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue), ".", searchFromEnd: True) = -1, 
   TextToDecimal(Concat(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue),".00")), 
   GetOrderById.List.Current.Order.CurrencyValue)
)

This would add the trailing zeros based on how many decimal places were stored with it. To display the stored value in an expression you could also potentionaly use function "format/formatcurrency" (like the others I used to be found under the built-in functions).

Similary, if you don't want to convert between decimal and text, you could try to continue using the input mask and the function "Mod(n,m)" to determine if you have less than 2 decimal places in your stored value, and then (temporarily) mulitply by 10 or 100. You just need to remember to divide by the same number again if the value doesn't get changed, since you'll increase the stored number everytime someone displays it otherwise.


I am sure there are more elegant ways to solve this, although they might involve JavaScript. I hope this helps.

Best regards,
Michael

Hi Michael, thanks for the detailed response. 

Your recommended solutions can work and I will try the second option. However I have loads of currency fields on the app  that I need to display this way. Your solutions requires coding on every field instead of just using standard functionality so it becomes a big task to never be able to use the database and always use temporary text variables or calculations. It kind of defeats the idea of simple drag and drop of basic functionality ;-( 


 I am going to try your solution but I was really hoping that there is a better and easy way to handle masks in OutSystems. 


I will let you know how it goes!




Vonnelize Haupt wrote:

Michael Segbers wrote:

Hello Vonnelize,

the problem seems to be that the input mask you are using always interprets the last two digits of the stored value as the decimals, while the decimal-format of the value doesn't save trailing zeros (for reference: a stored value of 2.5 is shown as $0.25). This is similar to this problem https://www.outsystems.com/forums/discussion/35103/error-covnerting-data-type-decimal-to-decimal/ in that displaying a stored decimal value can be tricky.

The way I'd deal with this would be to not use the mask and not input the value as a number, but to use Text for input and output and convert between text and decimal data types. This would allow you to perform text-based checks in the OnAfterFetch-action, like

If(
 Index(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue), ".", searchFromEnd: True) = 1, 
  TextToDecimal(Concat(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue),"0")), 
  If(Index(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue), ".", searchFromEnd: True) = -1, 
   TextToDecimal(Concat(DecimalToText(GetOrderById.List.Current.Order.CurrencyValue),".00")), 
   GetOrderById.List.Current.Order.CurrencyValue)
)

This would add the trailing zeros based on how many decimal places were stored with it. To display the stored value in an expression you could also potentionaly use function "format/formatcurrency" (like the others I used to be found under the built-in functions).

Similary, if you don't want to convert between decimal and text, you could try to continue using the input mask and the function "Mod(n,m)" to determine if you have less than 2 decimal places in your stored value, and then (temporarily) mulitply by 10 or 100. You just need to remember to divide by the same number again if the value doesn't get changed, since you'll increase the stored number everytime someone displays it otherwise.


I am sure there are more elegant ways to solve this, although they might involve JavaScript. I hope this helps.

Best regards,
Michael

Hi Michael, thanks for the detailed response. 

Your recommended solutions can work and I will try the second option. However I have loads of currency fields on the app  that I need to display this way. Your solutions requires coding on every field instead of just using standard functionality so it becomes a big task to never be able to use the database and always use temporary text variables or calculations. It kind of defeats the idea of simple drag and drop of basic functionality ;-( 


 I am going to try your solution but I was really hoping that there is a better and easy way to handle masks in OutSystems. 


I will let you know how it goes!




Hi Vonnelize,

I would actually recommend to use the first option if you have lots of fields. You should be able to create one or two custom client actions that contain the needed logic / conversions and you can just use those as your OnAfterFetch - action and one you can drag into every "save" action instead of manually coding every field etc. You can also just copy/paste an input field with the formatting set up the way you want it, only switching out the name of the field and the variable used. That should reduce the extra work considerably.

For replacing lots of the same variables F12 and Edit > Find & Replace (CTRL+R) save a lot of time and headaches.

Best regards;
Michael


Hi Michael

Thanks for your advice and help! I built a workaround based on your suggestions. This is what I did:

I created a webblock. On the webblock I have a form with a label and one input field that is inside the mask.  The purpose of the form is to allow me to use the standard form validation functions on the field as input from the parent.

 The webblock has input parameters for:

- the value to display in the field (masked)

- the label of the field

- the currency symbol, decimal places, group seperator and decimal seperator to use in the mask.

- a boolean value IsValid that is being used to show if the field is valid or not

- a message that is used to show below the field when the field is not valid.


The last two inputs are needed so that the parent page can instruct the webblock to show validation information on the field (standard form functionality.)


This is how I handle it:

- On parameters change I check if the input value has decimals or not. If it does have decimals I assign the value to a local variable and I display the local variable in the field that is masked. If it does not have decimals I multiply the value with 100 and assign it to the local variable that I display masked.

- On change of the field I trigger an event with the local variable that was changed as input into the event.


On the parent block I catch the event when it is raised and in the event handler I assign the value that gets returned from the event to the database field that I used as input into the webblock. On this event handler  can then do data validations and if the value that is returned is not valid (e.g. the income is too low) I send IsValid = false and a validation message back into the webblock. The form on the webblock then have a red border and a red message that explains to the user why it is invalid.


This is working well and I can easily pop the webblock onto all my pages in the place of all the currenct fields with almost no additional coding. I just need to assign the value that is returned from the block to the original field and handle the data validation.


I am attaching the OML if you want to have a look. 


Thank you for helping me think and pointing me into a different direction.


Oh yes, I encountered a java script error when I use the mask on a pop up. I then needed to implement the fix on this link to get rid of that error : 

https://www.outsystems.com/forums/discussion/34378/cannot-read-property-classlist-of-null/



Hello Vonnelize,

thank you for the detailed description of the workaround, using a webblock makes using it for a lot of fields even easier. And glad I could provide a different angle to tackle the problem.

I did take a look at the OML as well, and I wanted to let you know about two things I spotted:

  1. When I first compiled your OML and ran it, I got an error every time I changed the value in the field. I was able to locate the problem and it was an easy fix, however. The name of the output parameter of the evtAmountChanged event does not match up with the declared input parameter of the eventhandler in the webblock's properties. No idea how that happened or why it didn't flag it before compiling, but after changing it to the real output parameter everything is working for me.


  2. I mentioned this in my original post, that you would have to multiply by 10 or 100. Currently, your solution only works properly if you either have two decimals or none. You need to make a further determination if you only have one decimal and multiply by 10 in that case (e.g. 3.2 shows as 0.32).

Otherwise your solution looks great and I'll definitely have to keep in mind that I don't think of the possibilities webblocks offer nearly enough in my work :)

Best regards,
Michael