DEV Community

Cover image for Handling popstate by Route object - craftkit code pattern
CraftkitJS
CraftkitJS

Posted on • Updated on

Handling popstate by Route object - craftkit code pattern

routing

In craftkit application, routing is managed by RootViewController, a special type of ViewController.

It defines interface for handling popstate event, by resolveRoutingRequest(route) method.

When you implement your own RootViewController, you have to implement this method.

The routing request is encapsulated by Route object, and it is passed to the method.

Route object

param desc
launch true if called from RootViewController#bringup
path parsed path
event defined if this is called by browser back/forward with popstate event

Parsing and normalizing Route.path is responsibility of your RootViewController implementation. (This is not the same as location.pathname)

To control History correctly, you have to check popstate event and launch flag like this:

let event  = route ? route.event  : null;
let launch = route ? route.launch : false;

if( launch ){
    // your are in launching sequence, and you should update history
    window.history.replaceState({},title,path);
}else{
    if( !event ){
        // called by browser back/forward with popstate event
        window.history.pushState({},title,path);
    }
}
Enter fullscreen mode Exit fullscreen mode

This is idiom.

Every time you implement your application's RootViewController, your will write this kind of block.

Example

class Apple extends Craft.UI.View {
    template(componentId){
        return `
            <div class="root">🍎</div>
        `;
    }
}
class Orange extends Craft.UI.View {
    template(componentId){
        return `
            <div class="root">🍊</div>
        `;
    }
}
class PageController extends Craft.UI.DefaultRootViewController {
    constructor(options){
        super(options);
        this.data = {
            map: {
                apple: new Apple(),
                orange: new Orange()
            }
        };
    }
    resolveRoutingRequest(route){
        let path = route.path || 'apple'
        let view = this.data.map[path];
        this.replaceView(view);
        if( route.launch ){
            // launching the app
            window.history.replaceState({},'','#/'+path);
        }else{
            if( !route.event ){
                // in app navigation
                window.history.pushState({},'','#/'+path);
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

This example code can be run on playground like following:

var rootViewController = new PageController();
Craft.Core.Context.setRootViewController(rootViewController);

rootViewController.bringup();
Enter fullscreen mode Exit fullscreen mode

bringup method starts resolving Route object from popstate.
In this case, default view 🍎 is shown.

Then, focus url bar (command-l), and change trailing 'apple' to 'orange'.
🍊 is shown.

Push back button, 🍎 is shown again.

NOTE

Path normalization is supported by Craft.Core.HashRouter and Craft.Core.PathRouter. This is GoF Strategy pattern.

HashRouter is default. You can set it at the boot time of your application.


// in your bootloader

Craft.Core.Bootstrap.boot({
    router : Craft.Core.HashRouter,
    didBootApplication : function(){
        Craft.Core.Defaults.ALLOW_COMPONENT_SHORTCUT = true;
        let rootViewController = new PageController();
        Craft.Core.Context.setRootViewController(rootViewController);
        rootViewController.bringup();
    }
})

// in your RootViewController 

let normalized_path = Craft.Core.Context.getRouter().normalize(path);

if( route.launch ){
    window.history.replaceState({},'',path);
}else{
    if( !route.event ){
        window.history.replaceState({},'',path);
    }
}
Enter fullscreen mode Exit fullscreen mode

See GitHub for more about boot setting.

https://github.com/craftkit/craft-uikit

Top comments (0)