Input validation with value correction

Hey there!

First of all, I’m new to Aurelia, so it could well be something obvious that I’m missing, so sorry in advance.
I’m trying to implement an input with validation such that if a value typed in is incorrect, it instantly changes to the last correct value (or some other value dictated by the validation logic).

For instance say I have an input of type number, and the validation rule is that the number has to be less than 100. Otherwise, whatever I type gets set to 100.

First I tried making the property @bindable / @observable and watch the PropertyChanged callback. This gives me the old value and new value, so I could easily apply my validation logic, however setting this.property = correctValue this would cause the change callback to be called again, causing an infinite loop (and stack overflow).

The second trick I tried was using a Bidirectional Value Converter. In the fromView method, I checked if the value was greater than 100, and if it was, I would return 100, otherwise return the actual value.

export class MaxNumberValueConverter {

    fromView(value, maxNumber) {

        if (parseInt(value) > maxNumber) {
            return maxNumber;
        } else {
            return value;
        }
    }
}

Strangely, this works the first time I type a wrong value, but after the first correction is applied, the value from the input stops being updated so I can type whatever I want.

Lastly I tried this ugly hack, manually updating the value from the input:

< input type=“text” value.bind=“pageNumber | maxNumber:el:100” ref=“el” / >

export class MaxNumberValueConverter {

fromView(value, el, maxNumber) {

    if (parseInt(value) > maxNumber) {
        $(el).val(maxNumber);
        return maxNumber;
    } else {
        return value;
    }
}

}

This works, however:

  1. I get a feeling this is not the right way to do it
  2. I can’t get the old value from the input

Any tips are greatly appreciated,
Thanks!

1 Like

How about only setting the property to the old value if the new one is incorrect?

1 Like

Something like this? https://gist.run/?id=338a13207abc59dda875b9a062213ddd
It doesn’t create an infinite loop as far as I can see… still needs a bit more to handle invalid numbers because you can type 0-0 at least in Chrome.

Also added the value converter… both seem to work fine unless I’m missing something?

1 Like

Thanks for the replies, guys!
Something a little odd happens with this approach:

If I exceed by a digit, it doesn’t reset the value. If I add another digit, it updates properly. Same goes if I just paste in a number.

However, I tried it on my local setup and it seems to work fine, even when pasting in values.

Very odd… it didn’t do that the first time, however the ValueConverter seem to work ok :slight_smile:

Hmm, this is really peculiar, your value converter seems to work perfectly on gist, but on my machine it doesn’t. On the other hand the approach with pageNumberChanged callback works perfectly locally, but doesn’t in gist.

I’m not sure what version of the libraries gist.run uses so go with your local setup.

There is however a small issue:

Say I have a task to carry out when the property is changed to a valid value (like fetching something from the server).

  1. Say the value of the property “prop” is initially 2 (a valid value).
  2. I write an out of range value, say 2135231.
  3. The propChanged method gets called, I evaluate 2135231, I see it’s wrong so I set prop = oldValue.
  4. The propChanged method gets called yet again, oldValue = 2135231, newValue = 2, I see newValue is valid, so I call my expensive task.
  5. The propChanged gets called a 3rd time, I see newValue = oldValue so I stop.

My problem is at step 4. I would prefer to not call my expensive task every time an incorrect value is written down. So I’d need to also check my oldValue, and if my oldValue is an incorrect value, then it means this is an ‘after correction’ call and I shouldn’t do anything. Or store my last valid value in a separate variabile.

I can live with this, but it feels a little hacky to be honest.