Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Last active October 20, 2020 10:11
Show Gist options
  • Save benjamingr/1fa2d840c0e99175458c to your computer and use it in GitHub Desktop.
Save benjamingr/1fa2d840c0e99175458c to your computer and use it in GitHub Desktop.
Routing

It is often desirable in single page application to have a form of state management.

In this exercise we'll example one such way using routing. You'll be implementing a router that allows clear state management in the application.

Implement a Router object with the following methods:

addRoute

router.addRoute(routeName, handler)

Adds the given route to the router.

  • routeName is the name of the route given, for example /Home.
  • handler is a function to call when routing to the route is done with the below route method.

route

router.route(routeName, handler);
  • routeName is the name of the route given, for example /Home.

Calling route after a call to addRoute with the same route should perform the actions in the handler. For example:

var router = new Router;
router.addRoute("/Home", function() {
    console.log("HI");
});
router.route("/Home"); // will log "HI" to the console

Once you're done with the basic functionality (you may use your event emitter for this). We'll want to support route parameters.

We'll now be allowing routes to have parameters with the following format:

router.addRoute("/Home/:name", handler(params) {
    params.name; 
});
router.route("/Home/Gilad"); // params.name is "Gilad" in the handler.

In case two handlers match the same route, an Error should be thrown.

For extra credit (not required) you may want to use the HTML5 history API to change the displayed URL in the address bar to the current route, support the back button and instant routing on navigation. Please do not start on thos before you've finished the rest of the exercise.

Here are some tests to get the point across:

describe("The router",function() {
    var router;
    beforeEach(function() {
        router = new Router();
    });
    it("supports adding a route", function(done) {
        router.addRoute("/Home", function() {
        	done();    
        });
        router.route("/Home");
    });
    it("supports adding two routes", function(done) {
        router.addRoute("/Home", function() {
        	done();
        });
        router.addRoute("/Foo", function() {});
        router.route("/Home");
    });
    it("conflicts on two conflicting routes", function(done) {
        router.addRoute("/Home", function() {});
        router.addRoute("/Home", function() {});
        assert.throws(function(){
            router.route("/Home");
        });
        done();
    });
    it("Supports passing a parameter", function(done){
        router.addRoute("/Home/:foo", function(params){
        	assert.equal(params.foo, "Bar");
            done();
        });
        router.route("/Home/Bar");
    });
    it("Supports passing two parameter", function(done) {
        router.addRoute("/Home/:foo/:bar", function(params) {
        	assert.equal(params.foo,"Bar");
            assert.equal(params.bar,"Baz");
            done();
        });
        router.route("/Home/Bar/Baz");
    });
    it("Supports passing three parameter", function(done) {
        router.addRoute("/Home/:foo/:bar/:baz", function(params) {
        	assert.equal(params.foo,"Bar");
            assert.equal(params.bar,"Baz");
            assert.equal(params.baz,"Foo");
            done();
        });
        router.route("/Home/Bar/Baz/Foo");
    });
    it("Contains the URL as params.url", function(done) {
        router.addRoute("/Home/:foo/:bar/:baz", function(params) {
        	assert.equal(params.url,"/Home/Bar/Baz/Foo");
            done();
        });
        router.route("/Home/Bar/Baz/Foo");
    });
    it("Stores the handler in the state", function(done) {
        var counter = 0;
        router.addRoute("/Home", function curState(params) {
        	if(counter === 1){
                console.error(router.state);
                assert.equal(router.state, curState, "not equal");
                done();
            }
            counter++;
        });
        router.route("/Home");
        router.route("/Home");
    });
    it("supports many calls", function(done) {
        var counter = 1;
        router.addRoute("/Home", function curState(params) {
        	if(counter === 12) {
                done();
            }
            counter++;
        });
        for(var i = 0; i < 120; i++) {
        	router.route("/Home");
        }
    });
    it("supports routes calling each other", function(done) {
        var counter = 1;
        router.addRoute("/Bar", function curState(params) {
        	if(counter === 20){
                done();
            }
            counter++;
            router.route("/Foo");
        });
        router.addRoute("/Foo", function() {
           router.route("/Bar"); 
        });
      	router.route("/Bar");
    });
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment