DaAnalyst

DaAnalyst

LiveView server-side validation/formatting of form inputs relying on ex_cldr_numbers

I am not really sure where to post this for it is both LiveView and cross-library related issue so I am posting it here.

What I am trying to do is having form input numbers (amounts) validated and formatted server-side by using ex_cldr_numbers library (which btw, is fantastic, kudos to @kip) while relying on an embedded_schema + changeset based validation.

The limitation I am encountering is as follows. If I use the combination of a text_input tag and a changeset based validation of the input numbers I don’t see how to validate and display them back in a server-side generated, locale-specific number format (e.g. with the thousand separator such as 1,000,000) since if I store them as :decimal (which is their actual data format) then the text_input tag will show them as numbers without the locale specific thousand separator (or any other desired locale-specific number format).

So, in my view (unless I am missing something big time), I can either choose not to use the text_input tag but write my own HTML input code mimicking the text_input output with an additional attribute updated by LiveView and used to override the value attribute in the element JS hook updated callback function, OR I need to have two fields in the schema for each such number (one as a string to read from/write to by the form and the other to store its decimal representation). The latter is so lame that it’s out of the question, so only the former option seems valid but still cumbersome.

Again, unless I am missing something, it would be nice if one of the following two features was added:
a) Either Ecto.Changeset taking an optional transform function when getting a field value (too far fetched maybe?) and having LiveView actually pass it and use it in such a manner, or
b) Have an optional input value-override feature in LiveView to avoid writing own proprietary hooks and manually replicating the text_input html output in each such case, as previously described.

Trying to replicate the feature rich ex_cldr implementation in JS is also out of the question and the only “light” option remaining outside one of those feature requests is to have such numbers stored in the schema as strings, manage their validation and formatting ourselves and transform them via the same cldr library into decimals with a proprietary function in the data module once the data is required for a later use.

Most Liked

LostKobrakai

LostKobrakai

Liveview won’t update inputs, which are focused anyways. So no matter what you do you cannot live replace the text in an input as user currently writes to without additional js. Given the latency of liveview I’d also strongly suggest to not even try to format input field values server side. I even had problems with js libraries being quite annoying by trying to format while supplying input (and in the mean time screwing up what I intended to write).

There are imo three options (from most to least prefered in my opinion):

  • Don’t do it
    Just let users supply number is whatever format they want to and apply formatting only afterwards. If you’re worried about incorrect inputs opt for making corrections easier or show a formatted preview next to the input.

  • Use JS library
    There are js libraries created for formatting input with delays or while writing. If they support cldr you might eben be able to supply patterns of ex_cldr to them.

  • Take on the complexity head on
    With client and server doing concurrent edits to text you’re tech. dealing with distributed state. One way to handle that could be using delta-elixir, which slab released recently, and the js counterpart and actually treat the changes made to the text like distributed changes, which need later consolidation. This is overengineering at its finest for your usecase, but I wanted to include it just to show the level of complexity the core of the requested functionality entails.

DaAnalyst

DaAnalyst

Actually, that’s not even necessary if opting not to format the number while the user is typing for which I agree with @LostKobrakai that thriving for the “ideal” solution may seriously impair UX which is why I am now using a focusout listener to detect when form inputs lose their focus and then simply push a proprietary event to my component e.g.:

function maybeFocusoutOfModalInput( me, e) {
  if( !isInput( e.target) || !isOfClass( e.target, MODAL_NUMBER_CLASS)) return false;

  me.__view.pushInput( e.target, e.target.form, 'rerender', e.target, null);
  return true;
}

With the following input tag in the template:

<%= text_input f, :amount, class: “modal-number-input”, value: @changeset.changes[ :amount] && CldrHelpers.amount( @changeset.changes[ :amount]) %>

Note that the ‘rerender’ handle_event is not really a rerender but has the effect of it as it simply recreates a changeset based on the provided form parameters (since, as per LiveView docs, JS is the single source of truth here).

And that’s it. No need for additional JS code.

03juan

03juan

I like the idea of letting the browser format the user’s number natively, and pretty-formatting it for the specific context on focus out. This is the way of least surprise for the user as the number input will behave in the same way as it does in other sites, and other apps when on mobile.

Following this frame of mind I wanted to test the native options for internationalization at our control. The result is the gist HTML5 input number localization study (codepen.io).

I wanted to see how Edge(Chromium) and Firefox behaved while influencing the localization of decimal number inputs.

From the input implementation notes in the HTML Standard (whatwg.org)

The formats shown to the user in date, time, and number controls is independent of the format used for form submission.

Browsers are encouraged to use user interfaces that present dates, times, and numbers according to the conventions of either the locale implied by the input element’s language or the user’s preferred locale. Using the page’s locale will ensure consistency with page-provided data.

The main point of study was how browsers interpret , and . for fractions of a number, and as a bonus how to influence the virtual keyboard presented to the user.

0.1 is a default representations of a floating-point number in the HTML Standard (whatwg.org), the other being exponent notation.

Setting the element’s lang attribute will influence whether value sanitization algorithm (whatwg.org) recognizes or ignores , as a valid decimal. The value must be a valid language tag (WAI) | W3C.

Set up

Configure two number inputs, individually displaying their value attributes and a text representation of their checkValidity() results.

Method

Test out each step in latest Edge and Firefox browsers.

  1. Step each input’s value up by clicking the spinner arrow
  2. Manually overwrite the inputs with 0,1
  3. Manually overwrite the inputs with 0.1

Results

Firefox
  1. Clicking the arrow on input en-CA makes the display use . as decimal, whereas fr-CA defaults to localized display of ,

  2. Both inputs recognise . as decimal

  3. Default language en-CA does not use , as decimal, so value is not valid.

Edge(Chromium)
  1. Changing the value with the spinner causes both values to display with , as decimal?

  2. Both inputs recognise . as decimal

  3. Input value does not care that , is not valid for en-CA, it parses it to a valid float anyway!

Moral of the story is that <input type=number> is not treated equally in different browsers.

Anyone willing to post their results below for other browsers, like Safari, please go ahead.

Where Next?

Popular in Questions Top

marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

Other popular topics Top

New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chrismccord
As promised, the first release candidate of Phoenix 1.3.0 is out! This release focuses on code generators with improved project structure...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31307 143
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

We're in Beta

About us Mission Statement