0

I have a site that displays bar graphs of data. I am trying to implement pagination for the graphs so that the user can click 'next' or 'previous' to scroll through different subsets of the total data.

Here is the HTML section in question:

<div class="graph_fields_wrap1 row backdrop col-lg-12">
    <div class="col-lg-6">
        <h3 class="titles">Top Ten Author Citations</h3>
        <h4 class="titles">All time (from 1970)</h4>
        <button class="pager" id="previous1" type="button"><span class="glyphicon glyphicon-chevron-left"></span> previous</button>
        <button class="pager" id="next1" type="button">next <span class="glyphicon glyphicon-chevron-right"></span></button>
        <div class="chart1 well bs-component"></div>
    </div>
    <div class="col-lg-6">
        <h3 class="titles">Top Ten Author Citations</h3>
        <h4 class="titles userTitle"></h4>
        <button class="pager" id="previous2" type="button"><span class="glyphicon glyphicon-chevron-left"></span> previous</button>
        <button class="pager" id="next2" type="button">next <span class="glyphicon glyphicon-chevron-right"></span></button>
        <div class="chart2 well bs-component"></div>
    </div>
</div> <!-- row -->

Here is the JavaScript:

$(document).ready(function() {
    // change graph according to author selection
    var wrapperG = $(".graph_fields_wrap1"); // wrapper for div containing citations graphs
    var next1 = $("#next1"); // pagination for all time cited graph
    var previous1 = $("#previous1");
    var next2 = $("#next2"); // pagination for user defined cited graph
    var previous2 = $("#previous2");
    // variables to log subset location in arrays (to use in slice)
    var from1 = 1;
    var to1 = 11;

    // PAGINATION //
    // all time cited, next author set
    $(wrapperG).on("click", next1, function (e) {
        // ignore default action for this event
        e.preventDefault();
        // shift pointers up 10 for next subset of array
        from1 += 10;
        console.log(from1);
        to1 += 10;
        console.log(to1);
        // remove currently displayed graph, 1st child of div (1st graph is 0th)
        $($(wrapperG).children()[0]).remove();
        // load new graph before other graph (1st child of div)
        $(wrapperG).prepend("<div class='col-lg-6'><h3 class='titles'>Top Ten Author Citations</h3><h4 class='titles'>All time (from 1970)</h4><button class='pager' id='previous1' type='button'><span class='glyphicon glyphicon-chevron-left'></span> previous</button><button class='pager' id='next1' type='button'>next <span class='glyphicon glyphicon-chevron-right'></span></button><div class='chart1 well bs-component'></div></div>").loadGraph((topCited.slice(from1,to1)), "chart1", palette1);
    });

    // all time cited, previous author set
    $(wrapperG).on("click", previous1, function (e) {
        // ignore default action for this event
        e.preventDefault();
        // shift pointers down 10 for previous subset of array
        from1 -= 10;
        console.log(from1);
        to1 -= 10;
        console.log(to1);
        // remove currently displayed graph, 1st child of div (1st graph is 0th)
        $($(wrapperG).children()[0]).remove();
        // load new graph before other graph (1st child of div)
        $(wrapperG).prepend("<div class='col-lg-6'><h3 class='titles'>Top Ten Author Citations</h3><h4 class='titles'>All time (from 1970)</h4><button class='pager' id='previous1' type='button'><span class='glyphicon glyphicon-chevron-left'></span> previous</button><button class='pager' id='next1' type='button'>next <span class='glyphicon glyphicon-chevron-right'></span></button><div class='chart1 well bs-component'></div></div>").loadGraph((topCited.slice(from1,to1)), "chart1", palette1);
    });
});

I initially used $(next1).on("click", function but the button only fired once then stopped working. Looking up similar queries on Stack Overflow I saw that, because the HTML is removed, the bound handlers are as well. So then I binded the handler to a part that is not removed (wrapperG).

I put the console.log lines to help me see what's going on when I click the buttons. When I load the page and click 'next', the console logs the data 11, 21, 1, 11 and keeps repeating that data on repeat clicks of either the 'next' or 'previous' button click. Obviously on clicking 'next' I want the data to log 11, 21 then 21, 31 then 31, 41 and so on. Similarly for the 'previous' button but decreasing by 10 each time. The bar graph then shows 10 bars of data according to where in the array the slice is taken.

If I comment out the 'previous' button jQuery section then the 'next' button works fine and the bar graph displays the data properly. This makes me think that the problem is in both buttons being contained within the same div. As I'm removing child()[0] of .graph_fields_wrap1 within the function then this is the only div I can refer to.

** ADDITIONAL **

Listing the console.log data above I realised I'd copied it out incorrectly. It is actually returning 11, 21, 1, 11.

This localizes the problem to being when clicking the 'next' button, it is firing both event handlers, so the first one increases the values by 10, but then the second one decreases them by 10, negating the effect.

Therefore, I need to find out why clicking the 'next' button is firing off both events and how to stop this from happening.

John Dawson
  • 443
  • 3
  • 10
  • 28
  • 2
    in your html both previous and next button has same **ID** : `id="previous1"` and `id="next1"` – Bhavin Solanki Jul 14 '15 at 14:34
  • 1
    Bhavin Solanki has a point, try to with different ids for next and previous buttons in pager 1 (All time (from 1970)) and for pager 2 – jyrkim Jul 14 '15 at 14:41
  • Sorry, that was a mistake, it's not actually like that in my code. I've edited it with corrected code... – John Dawson Jul 14 '15 at 14:45

4 Answers4

1

The problem is that you use the same element ID twice. To prevent double events add "return false" to your handler, or use differnt ID's

Sidenode: never use an ID twice instead use a class

Jasper Seinhorst
  • 1,056
  • 6
  • 19
0

Why not just do two onClick - one for next, and one for previous

var nextButton = $("#next1"); // pagination for all time cited graph
var previousButton = $("#previous1"); // pagination for all time cited graph

$(nextButton).on('click', function(){
    // load next graph & increment numbers
 });

$(previousButton).on('click', function(){
    // load previous graph & decrement numbers
 });
shanehoban
  • 870
  • 1
  • 9
  • 30
  • 2
    Why bother with `on()` if not using delegation? Just use `click()`. – isherwood Jul 14 '15 at 14:37
  • @isherwood TIL - Thanks very much! – shanehoban Jul 14 '15 at 14:43
  • There are two separate onClick functions, although mine are named `next1` and `previous1`. If I do it in format `$(next1).click...` though, the button works once and then stops working. Similarly to the problem in this query: http://stackoverflow.com/questions/13672021/jquery-click-only-firing-once – John Dawson Jul 14 '15 at 14:50
0

Because of the on click trigger being fired, the event handler maybe disposed of. What you can do is link a event handler to document and use that instead.

$(document).on('click', '.graph_fields_wrap1', function()
{
    ...
});

This should stop your event handler from disappearing

Canvas
  • 5,779
  • 9
  • 55
  • 98
  • That is just a small section of my JavaScript specifically to do with this problem. It's also doing a bunch of other stuff within `$(document).ready()` and changing that means the other functionality doesn't work until I click the 'next' button on the graph. It then still just loads data 11, 21, 1, 1 each time I click too. – John Dawson Jul 14 '15 at 15:11
  • Sorry, I mean `console.log` returning 11, 21, 1, 11 – John Dawson Jul 14 '15 at 15:21
0

I have got it working. Instead of passing the variable next1 (which refers to the id, #next1) into the parameters of on(), I tried passing in the direct reference to the selector as "#next1".

It seems that the on() event handler requires that you reference the selector directly, although I don't know why this would be the case.

So, to correct my previous code, the line:

$(wrapperG).on("click", next1, function (e)

Should be:

$(wrapperG).on("click", "#next1", function (e)
John Dawson
  • 443
  • 3
  • 10
  • 28