Search code examples
browserknockout.jswebkitroutessammy.js

Sammy.js with Knockout.js Not Running Route With Every URL Change


I have a single Sammy route that recognizes an arbitrary number of parameters. The route looks like this:

get(/^\/(?:\?[^#]*)?#page\/?((?:[^\:\/]+\:[^\:\/]+\/?)*)$/g, function() {
    var params = {};
    var splat = this.params.splat[0];
    var re = /([^\:\/]+)\:([^\:\/]+)/g;
    match = true
    while(match = re.exec(splat)) {
        params[match[1]] = match[2];
    }
    self.loadData(params);
});

This code works. What it does is it recognizes routes of the pattern #page/param1:value1/param2:value2/ for an arbitrary number of parameters. My loadData function has default values for many of these parameters. I'm confident there isn't a problem with the actual loading of the pages, since it works 100% on many computers in many browsers. However, it has weird behavior on my Android's browser and on my friend's Mac's Safari and Chrome (works on my PC's Chrome). I've noticed that these are Webkit browsers.

The behavior is that the route runs correctly for the first URL change, then won't for the next URL change (although the URL in the browser bar does indeed always change), then it'll work again for the third one, and won't for the fourth. That is, it works every other time. This seems like very strange behavior to me, and I'm at a loss as to how to debug this. For certain links, I was able to run a hack such that on click I set the window location to the URL and forcefully run the sammy code with runRoute('get', url);. It's impractical to have to add this for every click event on the page, and that doesn't really account for all URL changes anyway. Is there something I can do to debug why my route isn't being run every time the URL is changing?


Solution

  • For those of you who encounter similar behavior, on every other click in the above-mentioned browsers, this.params.splat was undefined. It's supposed to be set to the matched part of the URL (e.g. /#page/param1:value1/).

    The hack I came up with to deal with this is to add this to the top of the get route:

    if(this.params.splat === undefined) {
        app.unload().run();
        return;
    }
    

    This doesn't get to the root of the problem, it's just a hack that allows it to re-run the routes so that params.splat isn't undefined the next time through. If anyone has more information on what is going on, I'd be interested.