5

I am doing a little carousel with a pager. The carousel displays elements 6 by 6 and I have 36 elements to display. I have a next and previous button. The first elements displayed are [0, 6]. If I press the previous button and there is no previous elements (eg I am on the first page), it should wrap around and go to the end. The same applies for the last elements and the next button.

My code looks like this:

$('#img_prev').click(function (e) {
    # change this line so it wraps around
    imgIndex = (imgIndex - 6) % 36;
    alert(imgIndex)
    refreshImages(imgIndex);
    e.preventDefault();
    return false;
});
$('#img_next').click(function (e) {
    imgIndex = (imgIndex + 6) % 36;
    refreshImages(imgIndex);
    e.preventDefault();
    return false;
});

And it fails miserably because -6 % 36 is -6 and not 30. I could handle it with if (index < 0) ... but I would prefer a condition with a modulo that best capture the wrapping behavior.

How can I get this to wrap around (see 2nd line) ?

Benjamin Crouzier
  • 40,265
  • 44
  • 171
  • 236
  • 2
    _“And it fails miserably because -6 % 36 is -6 and not 30.”_ – well then add another 36 (so `+30` with subtracting 6 in one step already) before doing the modulo division … – CBroe Jun 06 '13 at 14:08
  • @CBroe Yes actually it is equivalent with what I had in mind (see my answer) – Benjamin Crouzier Jun 06 '13 at 14:11
  • `imgIndex = ((imgIndex - 6) + 36) % 36;` which is `(imgIndex + 30) % 36` though that's harder to read. – Orbling Jun 06 '13 at 14:18
  • simpliest workarroud is imgIndex = (36 + imgIndex + 6) % 36; – Serge Jun 07 '13 at 13:43

2 Answers2

12

One possible solution would be with this answer:

function mod(x, m) {
    return (x%m + m)%m;
}

$('#img_prev').click(function (e) {
    # this line has been changed, now it wraps around
    imgIndex = mod(imgIndex - 6, 36);
    ...
Community
  • 1
  • 1
Benjamin Crouzier
  • 40,265
  • 44
  • 171
  • 236
  • 1
    You don’t need to do modulo with the same “divisor” twice, `return (x + m)%m` should be enough. – CBroe Jun 06 '13 at 14:22
  • 1
    @CBroe The author of the function mod (@ShreevatsaR) must have a good reason for doing that. I was thinking maybe for some edges cases with negative numbers. But I can't figure any were `(x + m)%m` and `(x%m + m)%m` are different. So good point. – Benjamin Crouzier Jun 06 '13 at 14:41
  • 2
    No, you are actually right – if the index we are trying to “contain” here was _very_ out of bounds already (manipulated elsewhere in code or whatever), so for example `-41`, then we would get `(-41+36)%36 = -5` with my proposal – so doing modulo on the input value first does have its eligibility: `(-41%36+36)%36 = 31` – CBroe Jun 06 '13 at 14:48
1

You could try this:

var maxElements = 36;
$('#img_prev').click(function (e) {
    // change this line so it wraps around
    imgIndex = (maxElements - 1) - (imgIndex % maxElements);
    alert(imgIndex)
    refreshImages(imgIndex);
    e.preventDefault();
    return false;
});
$('#img_next').click(function (e) {
    imgIndex = (imgIndex % maxElements);
    refreshImages(imgIndex);
    e.preventDefault();
    return false;
});

Here's a fiddle showing the output of:

(imgIndex % maxElements)

and

(maxElements - 1) - (imgIndex % maxElements);
pete
  • 24,141
  • 4
  • 37
  • 51