0

I could not find anything that mentioned my issue, I am using my router file in backbone to navigate to a different page based on the current page ID through the use of next and previous buttons. However, when I click next or previous once, it works fine, but the second time the button is clicked, the functin is called twice instead of once, and then if I click it another time it seems to be called even more than twice to a point where it seems to go berserk.

Here is my router file:

define([
    'jquery',
    'underscore',
    'backbone',
    'views/page',
    'models/search',
    'views/search',
    'text!templates/search.html',
    'models/song',
    'text!templates/song.html'


], function($, _, Backbone, PageV, SearchM, SearchV, SearchT, SongM, SongT) { 
    var vent = _.extend({}, Backbone.Events);
    var AppRouter = Backbone.Router.extend ({
        routes: {
            'page/:id': 'showPage',
            'search': 'showView' ///:page
        }
    });

    var initialize = function () {
        var app_router
        app_router = new AppRouter;


        console.log('router file hit');

        app_router.on('route:showPage', function (id) {
            console.log('page rendered');
            var songies, collected, songM;
            songM = new SongM();
            songM.localStorage = new Backbone.LocalStorage("music");
            songM.localStorage.findAll().forEach(function (i) {
                collected = i;
            });
            var songPages = Math.ceil(collected.music.length / 25); //10 pages
            var start = id * 25;
            var songies = collected.music.splice(start, 25); 
            var titles = {
                week: collected.week,
                year: collected.year,
                channel: collected. channel
            };
            var page = new PageV({model: songM, collection: songies, vent: vent, titles: titles});
            page.render(id);
            vent.on('next', advance);
            vent.on('previous', moveBack);
            var currentId = parseInt(id);
   //PROBLEM OCCURS TO THE BOTTOM TWO FUNCTIONS, and they are triggered by the vent.on above.

            function moveBack () {
                console.log('here is the current ID');
                var newPage = 'page/' + (currentId - 1);

                if(currentId <= songPages && currentId > 0 ) {
                    app_router.navigate(newPage, true);
                } else {
                    app_router.navigate('search', true);
                }
            }
            function advance () {
                console.log('here is the current ID');
                var newPage = 'page/' + (currentId + 1);
                console.log(currentId);
                console.log(songPages);
                console.log(newPage);
                if(currentId < songPages && currentId >=0 ) {
                    app_router.navigate(newPage, true);
                } else {
                    app_router.navigate('search', true);

                }

            }

        });

        app_router.on('route:showView', function () {
            console.log('search page loaded');
            var searchM = new SearchM();
            var search = new SearchV({model: searchM, vent: vent}); //
            search.render();
            vent.on('nextPage', printCons);
            function printCons () {
                console.log('changing pages');
                app_router.navigate('page/0', true);
            }; 


        });

        Backbone.history.start();

    };

    return {
        initialize: initialize
    };
});

Here is the page with the page view:

define([
  'jquery',
  'underscore',
  'backbone',
  'models/song',
  'collections/songs',
  'views/song',
  'text!templates/page.html',
  'text!templates/song.html'

], function($, _, Backbone, Song, Songs, SongV, PageT, SongT){ 

  var Page = Backbone.View.extend({

    el: $("#Sirius"),
    events: { 
      "click .prev": "previous",
      "click .next": "next"
    },
    previous: function () {
       this.options.vent.trigger('previous');
    },
    next: function () {
       this.options.vent.trigger('next');
    },
    render: function () {
      var headings = this.options.titles; 
      var info = {
        week: headings.week,
        channel: headings.channel,
        year: headings.year
      }
      var pagetemp = _.template( PageT, info);
      this.$el.html( pagetemp );
      var songColl = this.collection;
      var songV = new SongV({collection: songColl});
      songV.render();

    }


  });
    return Page;
});

The only problems I can think of is that it somehow remembers the past instance and calls the function on both of them... or else I have no idea why it gets called twice... because if I refresh the page with that id and then click previous or next it does not increment it twice... so it must be in memory or something not sure how to go around it...

Lion789
  • 4,402
  • 12
  • 58
  • 96

2 Answers2

1

The problem is with the following event handler bindings within your app_router.on event handler:

vent.on('next', advance);
vent.on('previous', moveBack);

Each time you show a new route, you are binding those functions to the event aggregator again. You should move both of these bindings outside to the initialize function so you don't bind it multiple times.

Another quick fix, if for some reason moving these bindings outside breaks the functionality, would be to unbind the previous bindings and then bind the event handlers again:

vent.off('next');
vent.on('next', advance);
vent.off('previous');
vent.on('previous', moveBack);

See the Backbone docs for more details regarding this.

Herman Tran
  • 1,581
  • 2
  • 12
  • 19
  • The problem is I am using the id within that router.on so how do I pass the id to it? – Lion789 Oct 28 '13 at 19:23
  • See the edits I made regarding how to unbind and rebind the events – Herman Tran Oct 28 '13 at 19:26
  • Well essentially everything will be bound again when called again since it navigates to the new page right? – Lion789 Oct 28 '13 at 19:27
  • Yes you only need one binding for the advance() and moveBack() functions in this case, as long as you keep incrementing the id of each new page made – Herman Tran Oct 28 '13 at 19:30
  • I tried the vent.off('next'); and the previous, but it still seems to increment double, so this had to be done but I think the other answer also, need to be done where I unbind the views, etc... do you know how I can implement that correctly? – Lion789 Oct 28 '13 at 19:34
  • Try doing the same `vent.off('nextPage');` in your `app_router.on('route:showView')` and make sure you do the same for any other `on` bindings – Herman Tran Oct 28 '13 at 20:59
  • I tried it, I need to still somehow delete/destroy all the views and models when leaving the search and going to the nextPage and then doing the same thing when going through pages... – Lion789 Oct 28 '13 at 22:37
  • Yes let me push it to my site – Lion789 Oct 29 '13 at 00:37
  • Ok it is up on lgavra.com/music#search --- it might take a while to load I have to improve it somehow not sure why it takes forever to load right now, it is probably because of the scraping – Lion789 Oct 29 '13 at 00:49
  • It actually isn't slow, so yeah take a look once u search then going thru the pages – Lion789 Oct 29 '13 at 00:53
1

The problem is that you're creating a new view every time you change the route, but you're never deleting the old views. You're probably doubling the views every time you click on the next one!

Here's a post that might help:

Disposing of view and model objects in Backbone.js

Community
  • 1
  • 1
EmptyArsenal
  • 7,314
  • 4
  • 33
  • 56
  • Can you show me an example... I tried deleting the view after calling the trigger but it just removes the view completely – Lion789 Oct 28 '13 at 19:55