2

Why code fragments that looks similar works in different ways?

<input data-value-max="10">

1. If script gets option from attr, it always updates input with option value:

$('input').keyup(function(e) {

  var $this = $(this);
      option = $this.attr('data-value-max');
      val = $this.val();

  if (val > option){   // ←---
    e.preventDefault();
    $this.val(option);
  }

});

I mean that if I type 3 or 10, script updates input to 10.

2. The second variant works just as I expect—it replaces input value only if it is greater then a number in if statement:

$('input').keyup(function(e) {

  var $this = $(this);
      option = $this.attr('data-value-max');
      val = $this.val();

  if (val > 10){   // ←---
    e.preventDefault();
    $this.val(option);
  }

});

So I can't understand why the first variant replaces input value all the time?

A. Z.
  • 728
  • 1
  • 11
  • 28

4 Answers4

6

You don't parse the values and attributes.

You should know that "3" > "10" but 3 < "10" (in the latter case, "10" is automatically converted for the comparison).

Use parseInt :

var option = parseInt($this.attr('data-value-max'), 10);

As your attribute has the data prefix, you might also use jQuery data's auto conversion feature :

var option = $this.data('value-max');

But personally I try to avoid it (especially given the bugs in 1.7 version) and I prefer to be explicit. And it wouldn't work for any value that you can parse as numbers : only those that give the same exact string if toString is called on the number (it would fail for "03" or "+03" for example).

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
1

Cleaner:

$('input').keyup(function(e) {

    var max_value = $(this).data('value-max') * 1;

    if( this.value * 1 > max_value )
        this.value = max_value;

});

You are comparing strings in your first example and in your second you are comparing a string to an integer (10). You want to convert your strings to an integer for your expected comparison. One method is the *1 I used above.

Finally e.preventDefault() is not needed.

iambriansreed
  • 21,935
  • 6
  • 63
  • 79
0

Your second example is relying on JavaScript's type-coercion to compare.

What you are literally doing is testing if "3" > 10 which JS interpreter realizes you're trying to do a numeric comparison and converts it internally to 3 > 10

This is just fine if you understand what the interpreter will try and coerce....similar examples would be:

var x = 0;
if(x) { /* do stuff */ } //0 is a falsy (but not === false) value so the test will always fail

var y = "10";
console.log(y * 10) //outputs 100;
BLSully
  • 5,929
  • 1
  • 27
  • 43
-1

I suspect your issue has root in weak typing and type conversion. try this:

 if(parseInt(val) > 10) { ...
bjorn
  • 46
  • 5
  • 1
    right guess, but wrong way around... Your example works, because val is coerced, but not the first one where both values are strings. – Christoph Feb 25 '13 at 14:05
  • My comment actually makes no sense at all because it addresses the second (working) code block and not the non-working first one. the point was parseInt() though. – bjorn Feb 25 '13 at 14:11