Inspired by the example in the KnockoutJS SPA tutorial, I'm trying to use Sammy.js to wire up some simple behaviour in a single-page application, using the URL hash to keep track of which API endpoint is being invoked. I'm trying to end up with a page history that looks like this:
In every case, the URL fragment is actually the raw URL that was used to make the API call which rendered the current page.
The problem is, I can't get Sammy's route handling to work properly when the location hash contains a forward-slash character - and I have no idea why. According to RFC3986, "the characters slash ("/") and question mark ("?") are allowed to represent data within the fragment identifier", so it sounds to me like I should just be able to use unescaped slash and question mark characters in the URL fragment.
Here's a complete repro case covering several different scenarios. There's two Sammy routes defined - if my understanding of the syntax is correct, one should capture anything containing a hash and the other should match only the empty route. That's not what's happening, though.
<!DOCTYPE html>
<html>
<head>
<title>SammyJS routing demo</title>
<script type="text/javascript" src="Scripts/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="Scripts/sammy-0.7.5.min.js"></script>
</head>
<body>
<ul>
<li><a href="#foo">#foo</a> - prints 'foo'</li>
<li><a href="#/bar">#/bar</a> - prints 'NOPE'</li>
<li><a href="#!/baz">#!/baz</a> - prints 'NOPE'</li>
<li><a href="#foo/bar">#foo/bar</a> - prints 'NOPE'</li>
<li><a href="#foo/bar#bop">#foo/bar#bop</a> - prints 'bop'</li>
<li><a href="#why?not">#why?not</a> - prints 'why'</li>
<li><a href="#why?not#zoidberg">#why?not#zoidberg</a> - prints 'why?not#zoidberg'</li>
<li><a href="#why?not#zoidberg/">#why?not#zoidberg/</a> - prints 'NOPE'</li>
</ul>
<script type="text/javascript">
Sammy(function () {
this.get('#:url', function () { console.log(this.params.url); });
this.get('', function () { console.log('NOPE'); });
}).run();
</script>
</body>
</html>
Any ideas what I need to do to get Sammy to handle these fragments consistently?
So, Sammy.js as noted on http://sammyjs.org/docs/routes says "It does not work if you want to match strings that contain ‘/’. If you want that you can use Regexp and ‘splat’", and hence why this example fails.
If however you replace the first this.get
with this.get('#(.*)', function () { console.log(this.params['splat']); });
then it works pretty much fine (well, the "#why?not" misses out the not, but that's probably further in the query string and "#why?not#zoidberg" isn't that happy, but I'd say you should stick to a single # in a URL)
https://jsfiddle.net/gymt828r/ demonstrates a fixed instance of this.