Marcos
Marcos

Reputation: 353

Why is my property observer being called twice with the same 'newValue'?

I am making an observer that adds a thousands separator, be it a '.' or a ',', to whatever number the user types.

For those who don't know, in Polymer it's possible to bind an observer to a property which is basically a function called everytime that property changes.

The observer is called with two parameters, 'newValue' and 'oldValue' pretty self-explanatory parameters names.

Right now it adds the separators correctly but when I press delete it doesn't delete what it's supposed to delete.

This is my use case:

1) I type '123456'.

2) The code changes it to '123.456'.

3) I press delete with the cursor at the last position '123.456|'.

4) The observer is called three times.

I first started using the property observer but as I came up with this problem I switched to using an on-input listener as it lets me check the inputType property and act accordingly.

When the action is delete the inputType is 'contentDeleteBackward' and when it is insert the inputType is 'insertText'.

This is the observer function

_turnoverObserver: function (newValue, oldValue) {
      let parsedWithoutCommas = String(parseInt(newValue.replace(/\D/g, ''), 10));
      if (parsedWithoutCommas !== oldValue) {
        this.fire('turnover-event', {turnover: parsedWithoutCommas});
        let result = [];
        let reversed = parsedWithoutCommas.split("").reverse();
        if (reversed.length > 3) {
          reversed.forEach((digit, index) => {
            if (index !== 0 && index % 3 === 0) {
              result.push('.');
            }
            result.push(digit);
          });
          this.turnover = result.reverse().join("");
        }
      }
    },

This is the on-input listener function

 _addSeparatorTurnover (e) {
      let value = e.target.value;

      let parsedWithoutCommas = String(parseInt(value.replace(/\D/g, ''), 10));

      if (e.inputType === 'insertText') {
        let result = [];

        if (parsedWithoutCommas.length > 3) {
          let reversed = parsedWithoutCommas.split('').reverse();
          reversed.forEach((num, index) => {
            if (index !== 0 && index % 3 === 0) {
              result.push('.');
            }
            result.push(num);
          });
          e.target.value = result.reverse().join('');
        }
      } else {
        let result = [];

        let {selectionStart, selectionEnd} = e.target.$.input;
        let deletedVal = parsedWithoutCommas.slice(0, selectionStart - 2) + parsedWithoutCommas.slice(selectionStart - 1);

        deletedVal.split('').reverse().forEach((num, index) => {
          if (index !== 0 && index % 3 === 0) {
            result.push('.');
          }
          result.push(num);
        });

        e.target.value = result.reverse().join('');
      }
    },

Typing '123456' should display '123.456'

Deleting the last digit from '123.456' should change it to '12.345'

Upvotes: 0

Views: 280

Answers (1)

Vin
Vin

Reputation: 171

I tried using your code and could see that the observer over the property is calling exactly twice and not thrice as you mentioned. However, I have commented the below line from your code.

`this.fire('turnover-event', {turnover: parsedWithoutCommas});`

There is a chance that you might be trying to change the same value even in the above event and probably causing the third call. Also, you code seems to work properly while inserting the numbers. If we start deleting the numbers, it would stop working as expected below 4 digits. i.e., For 4 digits it show 1.234 and if you delete one more it shows 1.23 which is not correct as per your expectations(assuming). I tweaked your code and below is working perfectly.

_turnoverObserver: function(newValue, oldValue) {
                if (newValue) {
                    let parsedWithoutCommas = String(parseInt(newValue.replace(/\D/g, ''), 10));
                    if (parsedWithoutCommas !== oldValue) {
                        //this.fire('turnover-event', { turnover: parsedWithoutCommas });
                        let result = [];
                        let reversed = parsedWithoutCommas.split("").reverse();
                        if (reversed.length >= 3) {
                            reversed.forEach((digit, index) => {
                                if (index !== 0 && index % 3 === 0) {
                                    result.push('.');
                                }
                                result.push(digit);
                            });
                            this.somevalue = result.reverse().join("");
                        }
                    }
                }
            }

Upvotes: 2

Related Questions