Telerik blogs

I've spent a few days lounging around in the SPA so far, and I'm beginning to grow acustomed to the luxuries of this life. From the HTML massage of kendo.View to the DOM replacement therapy of kendo.Layout, the SPA life has proven to be quite relaxing.

But this life can be difficult. It can lead to some #FirstWorldProblems, too. What if I want to get started with my treatments and therapy, but I have to stop in the middle and come back later? I don't want to re-start the procedure that I've already started. I would rather return to the same therapist and pick up where I left off.

1st world problems

Enter the kendo.Router - your personal placeholder for application state. A router allows you to create URLs that are bookmarkable, directly linkable, and shareable on social media sites. A router is like a personal assistant at the SPA - a person that will keep track of what you've already done that day, so that you can pick up where you left off. When a routable URL is clicked, the router kicks in and tells the application to put itself back in to the state that was encoded in to the route.

You may resume my therapy, now

Getting started with a router is simple. After creating an instance of kendo.Router, call the route method to set up a route definition and handler. Lastly, the router's start() method needs to be called. This tells the router to start monitoring the URL for changes, so that it can work it's magic and fire the route handler methods as needed.

var router = new kendo.Router();

router.route("/myPage", function(){
  console.log("the /myPage route was triggered!");
});

router.route("/foo/:id", function(id){
  console.log("the /foo/" + id + " route was triggered!);
});

router.start();

The route definition is a string - a path that is used to identify the state of the application that the user wants to see. When a route definition is matched from the browser's URL hash fragment, the route handler is called.

Run this code and point your browser to your page, attaching "#/myPage" the end of the URL. This hash fragment is picked up by the router and matched against the first route. The route handler is triggered, and "the /myPage route was triggered!" is logged to the browser console.

Therapy Options

A route doesn't have to just be a hard coded string. It can also contain parameters, like a back-end server router (Ruby on Rails, ASP.NET MVC, Django, etc). To do this, name a route segment with a ":" before the variable name you want.

router.route("/foo/:id", function(id){
  // use the id param from the url
  console.log("the /foo/" + id + " route was fired!");
});

When you run this route, you can specify a URL hash fragment of /foo/anything you want here. All of the URL after the /foo/ will be provided to the router callback function as the id parameter of the function. If you run this on a page and point your browser to #/foo/1, for example, the message "the /foo/1 route was fired!" will show up in the browser's console window.

You can add as many variables as you want, to a route:

router.route("/foo/:bar/baz/:quux/:id", function(bar, quux, id){
  // ... matches routes like #/foo/this/baz/is/awesome
  console.log(bar, quux, id);
});

There are still more options and capabilites for routes. Be sure to read the documentation and the getting started guide for routers.

Save my spot?

In addition to handling routes, a router can update the URL's hash fragment with a route. This is done by calling the .navigate method on the router, passing in the route that you want the browser to show and an option to tell it whether or not to fire the route immediately (with the default being true: fire the route immediately).

// update the URL hash fragment and fire the route handler
router.navigate("/my/route/1234");

// update the URL hash fragment and do not fire the handler
router.navigate("/another/thing", false);

Setting the browsers hash fragment is done when the user of the app has reached a point in the app that should be bookmarkable or directly linkable. For example, in the Kitteh Gallereh app that we've been building for this series, viewing an image is an application state that should be bookmarkable. That means when a user clicks on a kitty image, we show it and we update the browser's URL hash with a "route" to the kitty.

If you tell the router to navigate to a route like "/images/2" it will look like this:

route hash

Note that the route really truely is a hash fragment in the URL. It's as if you had put an <a href="#images/2">kitteh</a> link in the page and the user clicked it.

Using the hash fragment like this has become standard practice for SPA routers. It allows a browser to have it's URL updated with information that is specific to the current browser sesstion, without having to make a round trip to the server.

Clicking a link that has a hash in it's "href" doesn't do a server request, after all. It only jumps to the named anchor on the current page. In the case of a router, there isn't an an explicitly named anchor in the page, though. The router is monitoring the URL for changes. When it seems the hash fragment has changed, it checks that fragment against the registered routes and runs your JavaScript code accordingly.

Hash fragments are never sent to the server, either. If you click a link like this: <a href="http://localhost:3000#/image/2">kitteh</a> your browser will only request "http://localhost:3000" from the server. It will not send the hash fragment to the server. The best part, though, is that named anchors and hash fragments also update your browser history. You can use the forward and backward buttons in your browser to move to a previous hash fragment, or back to the current one. This has been the standard way of handling URLs in browsers for many, many years now. SPA routers are only taking advantage of hash fragments and using JavaScript events and string parsing to turn an ancient technology (by web standards) in to something very useful in the new world of SPAs.

built SPA router using 15 year old tech

Herding Kittehs

I KNOW! I haven't shown you any kittehs today! I'm sorry! Here, let me fix that:


(from Emergency Cute Stuff)

Ok, that's better. Now, where was I? Oh, right... clicking an image and updating a browser's route.

When someone clicks a kitty to view it in the Kitteh Gallereh app, the browser's URL should be updated to show an identifier that says "show this image", with the id of the image to show. This would typically look like "/images/1" where "1" is the id of the image to show.

var id = image.id; // 1, for example

// update the URL route to show that the current
// application state can be bookmarked
router.navigate("/images/" + id, false);

This requires a route handler to be available, to handle this route definition.

router.route("/images/:id", function(id){
  // tell the view model to show the image
  // because the view model knows how to
  // load the correct image, and display it
  kittehModel.showById(id);
});

Now when you click an image, you'll see the URL update to show the hash route of the image you clicked.

For a complete listing of the code to make the image load and display, see this JSFiddle. It's hard to make this work in an iframe embedded in to a blog post, though, because you won't see the URL updating. So instead of trying to do that, go see the Kitteh Gallereh in action.

At this link, you'll be able to see the page's url updating when you click an image. Then when you refresh the page, the same kitty image will show up, because the router read the id from the URL's hash fragment.

Setting Up Your Usual SPA Treatment

I've shown you how to get a very basic router up and running, and how to integrate it in to the Kitteh Gallereh application that we've been building in this series. But we also have to think about what to do when no route is requested vs when a route is requested. We don't want to duplicate work, and we don't want to show a blank screen. To handle this, a default route should be provided. This is done by specifying a "/" as the route and providing a callback function for it.

router.route("/", function(){
  // default route fired. show the "home" screen
  kittehModel.showHome();
});

Once again, see this same JSFiddle and the working version of the fiddle to see this code in action.

Treat yourself to a day at the SPA!

Interested in seeing what Kendo UI can do for you and your project? Want to try out the latest and greatest in the Single Page Application structures that Kendo UI provides? Head over to the download page, and start working with Kendo UI today!


About the Author

Derick Bailey

About the Author
Derick Bailey is a Developer Advocate for Kendo UI, a developer, speaker, trainer, screen-caster and much more. He's been slinging code since the late 80’s and doing it professionally since the mid 90's. These days, Derick spends his time primarily writing javascript with back-end languages of all types, including Ruby, NodeJS, .NET and more. Derick blogs atDerickBailey.LosTechies.com, produces screencasts atWatchMeCode.net, tweets as @derickbailey and provides support and assistance for JavaScript, BackboneJS,MarionetteJS and much more around the web.

Comments

Comments are disabled in preview mode.