I have a single page application that uses Knockout.js for data binding and Sammy.js for routing client-side (hash-based) URLs.
I'm seeing a weird problem in Internet Explorer, however: sometimes links, when clicked, will change the URL in the browser's address bar, but the corresponding Sammy route will not execute.
It doesn't happen every time (but I can consistently reproduce the error), and it only happens in IE10 (Chrome works fine every time). It appears to be related to Knockout as well, since a set of hard-coded links don't exhibit the same problem.
To illustrate, I've stripped away everything but the bare minimum to recreate the problem and created two jsbin examples:
Example 1 (with Knockout): http://jsbin.com/aretis/2/
To see the problem, open the link above and click "Record #1", then "Baz", then "Record #1" again. The URL for record 1 will appear in the address bar, but the route for that record will not be appended to the list.
Example 2 (without Knockout): http://jsbin.com/amivoq/1/
In this example, I have a static list of record links instead of a data-bound list. Clicking on any of the links (in any order) will result in that route being appended to the list (as it should).
A reminder that these must be run in IE to reproduce the problem.
Any ideas?
As per my comment above, I worked around this problem by just catching the window.hashchange event and parsing out the URL myself. This is the only part of Sammy.js I was really using and I wasn't having any luck tracking down the actual problem. Hopefully, this will help someone else.
The first thing I did was bind the hashchange event:
$(function () {
$(window).on("hashchange", HandleUrl);
// Call our URL handler to deal with any initial URL given to us.
HandleUrl();
}
This calls the following URL parser:
function HandleUrl() {
var hash = location.hash;
if (hash.indexOf("#Account") >= 0) {
var splitParts = hash.split("/");
if (splitParts.length >= 2) {
ShowLoadingBox();
ShowAccountDetailFromId(splitParts[1]);
}
} else if (hash.indexOf("#Contact") >= 0) {
var splitParts = hash.split("/");
if (splitParts.length >= 2) {
ShowLoadingBox();
ShowContactDetailFromId(splitParts[1]);
}
} else if (hash.indexOf("#ThingsToDo") >= 0) {
SwitchToPanel("navPanelThingsToDo");
} else if (hash.indexOf("#ThingsIveDone") >= 0) {
SwitchToPanel("navPanelThingsIveDone");
} else if (hash.indexOf("#Reports") >= 0) {
SwitchToPanel("navPanelReports");
} else {
SwitchToPanel("navPanelMyAccounts");
}
}
The functions like ShowAccountDetailFromId()
and SwitchToPanel()
just show and populate (using Ajax calls to web services) the appropriate <div>
. This is probably a completely naive approach, but it is working (i.e. you can bookmark URLs, the back button and browser history work, etc.) My apologies for the non-answer "answer".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With