Framework: Value binding can break change.delegate

Created on 17 Mar 2016  路  5Comments  路  Source: aurelia/framework

Textbox binding:

<input type="text" value.bind="myValue | numberFormat:'0,0[.]00'" change.delegate="myValueChanged()" >

Value converter:

import numeral from 'numeral'; export class NumberFormatValueConverter { toView(value, format) { if (value === null || value === undefined){ value = 0; } return numeral(value).format(format); } fromView(input) { return input.replace(/\$|,/g, ""); } }

myValueChanged() handler will not get hit if the value exceeds 999. As long as there are no commas, that handler will get hit. 1,000 breaks it, however, with no error message.

change.trigger also doesn't work here, nor does blur.delegate. blur.trigger does work, however, even when there are commas.

question

Most helpful comment

The change event is fired for <input>, <select>, and <textarea> elements when a change to the element's value is committed by the user.
https://developer.mozilla.org/en-US/docs/Web/Events/change

Let's look at what happens when the input has "12" for a value and the presses "3" and then "tab":

  1. The "3" key is pressed, triggering the input element's "input" event
  2. The binding system is listening for the "input" event and sends the input's value ("123") through the value converter's fromView method, updating the model from "12" to "123".
  3. The binding system is also listening for the model to change. When it changes from "12" to "123" the binding system sends the model value through the value converter's toView method. Because the converted value ("123") is the same as the input's value, no more work is done.
  4. The "tab" key is pressed, triggering the input's change event and myValueChanged is called.

Let's look at what happens when the input has "123" for a value and the presses "4" and then "tab":

  1. The "4" key is pressed, triggering the input element's "input" event
  2. The binding system is listening for the "input" event and sends the input's value ("1234") through the value converter's fromView method, updating the model from "123" to "1234".
  3. The binding system is also listening for the model to change. When it changes from "123" to "1234" the binding system sends the model value through the value converter's toView method. Because the converted value ("1,234") is different as the input's value ("123"), the binding system updates the input's value to "1,234"/
  4. The "tab" key is pressed, the input's change event _is not fired_ because the last change to the input was made programmatically by the binding system (vs by the user in the previous example).

Here's how you could change your binding expression to make it work like you expect:

<template>
  <input type="text" 
         value.bind="myValue | numberFormat:'0,0[.]00' & updateTrigger:'change'" 
         change.delegate="myValueChanged($event.target.value)" >
</template>

By using updateTrigger:'change' the binding system never changes the input's value until the change event is fired.

Here's a gist that demonstrates this approach: https://gist.run/?id=5aa9ba1e06f01e597745

All 5 comments

@FunkMonkey33 pretty much unrelated, but you should look into using numbro instead of numeral https://www.npmjs.com/package/numbro

@MarkHerhold any specific reason for that that you can share?

@alvarezmario The numeral project hasn't been touched for 2 years and there are bugs. The project is dead. See: https://github.com/adamwdraper/Numeral-js/issues/242

Don't waste your time with it like I did. Numbro is nearly a drop-in replacement so you should be able to switch easily.

@MarkHerhold thanks for the info, I wasn't aware of numeraljs not being maintained anymore.

The change event is fired for <input>, <select>, and <textarea> elements when a change to the element's value is committed by the user.
https://developer.mozilla.org/en-US/docs/Web/Events/change

Let's look at what happens when the input has "12" for a value and the presses "3" and then "tab":

  1. The "3" key is pressed, triggering the input element's "input" event
  2. The binding system is listening for the "input" event and sends the input's value ("123") through the value converter's fromView method, updating the model from "12" to "123".
  3. The binding system is also listening for the model to change. When it changes from "12" to "123" the binding system sends the model value through the value converter's toView method. Because the converted value ("123") is the same as the input's value, no more work is done.
  4. The "tab" key is pressed, triggering the input's change event and myValueChanged is called.

Let's look at what happens when the input has "123" for a value and the presses "4" and then "tab":

  1. The "4" key is pressed, triggering the input element's "input" event
  2. The binding system is listening for the "input" event and sends the input's value ("1234") through the value converter's fromView method, updating the model from "123" to "1234".
  3. The binding system is also listening for the model to change. When it changes from "123" to "1234" the binding system sends the model value through the value converter's toView method. Because the converted value ("1,234") is different as the input's value ("123"), the binding system updates the input's value to "1,234"/
  4. The "tab" key is pressed, the input's change event _is not fired_ because the last change to the input was made programmatically by the binding system (vs by the user in the previous example).

Here's how you could change your binding expression to make it work like you expect:

<template>
  <input type="text" 
         value.bind="myValue | numberFormat:'0,0[.]00' & updateTrigger:'change'" 
         change.delegate="myValueChanged($event.target.value)" >
</template>

By using updateTrigger:'change' the binding system never changes the input's value until the change event is fired.

Here's a gist that demonstrates this approach: https://gist.run/?id=5aa9ba1e06f01e597745

Was this page helpful?
0 / 5 - 0 ratings

Related issues

bsrdjan picture bsrdjan  路  5Comments

piet-v picture piet-v  路  3Comments

gbreeze picture gbreeze  路  4Comments

dasch88 picture dasch88  路  4Comments

firelizzard18 picture firelizzard18  路  3Comments