0

I'm using .each to cycle through elements on the page and see the maximum bottom value. Script seems to be ok except that a simple check between two values returns something weird and I can't directly figure out what I have done wrong.

Here is my div setup:

<div id="zone1" data-top="38" data-bottom="1648" data-left="131" data-width="467" data-group="0">...</div>
<div id="zone2" data-top="38" data-bottom="957" data-left="597" data-width="467" data-group="0">...</div>
<div id="zone3" data-top="38" data-bottom="4508" data-left="1064" data-width="467" data-group="0">...</div>

Now the script:

maxb = 0;
console.log('init max '+maxb);
$('[data-group=0]').each(function()
    {
        tempb = $(this).attr('data-bottom');
        console.log(tempb+' '+maxb);
        if (tempb>maxb)     
            {
                maxb = tempb;
            }
        console.log(tempb+' '+maxb);    
    }); 

The objective of this script is to store the maximum data-bottom value of the data-group 0.

If I now look at my console output:

init max 0
1648 0
1648 1648
957 1648
957 957
4508 957
4508 957

So maxb is correctly initialized. The first data bottom is bigger than 0 so maxb takes this value but the second iteration is weird as 957 is below 1648, maxb should still be 1648 but it takes 957 as a max value and keeps it until the end. It's like the IF condition was not working properly but I probably need some sleep, I don't see where the issue is.

Thanks Laurent

Barmar
  • 741,623
  • 53
  • 500
  • 612
Laurent
  • 1,465
  • 2
  • 18
  • 41

3 Answers3

3

It's because you are comparing string values here - and that means, "sorting" resp. comparison happens character-by-character.

And by that metric, of course 957 is greater than 1648 - because it starts with the character 9, and that is greater than 1. Therefor the comparison ends here, and concludes that 957 is greater than 1648.

Convert the value into a real number first, using parseInt:

tempb = parseInt($(this).attr('data-bottom'), 10);
CBroe
  • 91,630
  • 14
  • 92
  • 150
  • Thanks, I feed the data-bottom value with this: $('#zone1').attr('data-bottom',Math.floor($('#zone1').position().top) + $('#zone1').height()); Is there something wrong with this? – Laurent May 18 '16 at 20:56
  • 1
    Nope, nothing wrong with that. It's just that HTML attribute values are _always_ read as string values. If you want them to be something else, then you have to convert/cast them afterwards. – CBroe May 18 '16 at 20:57
1

Are you sure these numbers are being treated as integers? I know you can use parseInt() to get javascript to force a string to be treated as a number but I'm lazy so I always just multiply by 1, which essentially does the same thing.

So basically, you would just change the code to be:

tempb = $(this).attr('data-bottom')*1;
rgbflawed
  • 1,957
  • 1
  • 22
  • 28
  • Wow, great, thank you rgbflawed, your proposition solved the problem. Didn't think of this but how could I prevent the data-bottom values from not being integers? – Laurent May 18 '16 at 20:52
  • 1
    Pretty sure that whenever you're pulling a value from the DOM like that it's always going to be treated as a string by default and it's up to you to get something to behave as an integer. If you were setting up these values via javascript in the first place, like `var data-bottom[1]=948` then you could set it as an integer right off the bat. But of course I'm sure you have reasons why everything is in the HTML like that. – rgbflawed May 18 '16 at 20:56
  • ok, I didn't know that. I have been using data-attributes this way for some time and never encountered the problem before...most likely because this scenario did not happen before. – Laurent May 18 '16 at 20:58
1

Please see my working example for the method to build up an array of values and then get the max value from it.

Source: jquery .each - strange calculation

Documentation:

Array prototype

.each()

.push()

Iterate through the object values and .push() them into an array.

var botArray = [];

$('[data-group=0]').each(function() {
  var item = parseInt($(this).attr('data-bottom'), 10);
  botArray.push(item);
});

var max = Array.prototype.max = function() {
  return Math.max.apply(null, botArray);
};

//https://stackoverflow.com/a/1669222/5076162

var botArray = [];

$('[data-group=0]').each(function() {
  var item = parseInt($(this).attr('data-bottom'), 10);
  botArray.push(item);
});

var max = Array.prototype.max = function() {
  return Math.max.apply(null, botArray);
};

$('.maxItem').text(max);
.maxItem {
  color: orange;
}
p {
  font-family: arial;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<div id="zone1" data-top="38" data-bottom="1648" data-left="131" data-width="467" data-group="0">...</div>
<div id="zone2" data-top="38" data-bottom="957" data-left="597" data-width="467" data-group="0">...</div>
<div id="zone3" data-top="38" data-bottom="4508" data-left="1064" data-width="467" data-group="0">...</div>
<p>
  data-bottom max value is: <span class='maxItem'></span>
</p>
Community
  • 1
  • 1
Alexander Dixon
  • 837
  • 1
  • 9
  • 24