Click here to Skip to main content
13,259,976 members (49,720 online)
Click here to Skip to main content
Add your own
alternative version

Stats

12.5K views
119 downloads
4 bookmarked
Posted 25 Nov 2015

Bobril - IV - Routing

, 13 Aug 2017
Rate this:
Please Sign up or sign in to vote.
Simple explanation of bobril routing mechanism

Download sample

In this article, we will learn how to handle routes definition by bobril embedded routing mechanism.

Background

Bobril is a component-oriented framework written by Boris Letocha (software architect and developer in GMC Software Technology). For more information, see the first article.

Using the Code

Preparing Environment

At first, we need to have prepared bobril-build on computer. Follow the steps in first article to perform bobril-build installation.

Now you can start a new project again or use a predefined skeleton simpleApp from bobril-build github repository.

Following example will use it. To get final code download the full sample.

Defining Routes

Bobril has few methods for defining the application route tree:

  • b.route - defines a route url, name, handler and a list of sub-routes
  • b.routes - registers routes to the application and calls b.init
  • b.routeDefault - defines the default route if no sub-route is specified in the current url

Example of the route definition in app.ts:

import * as b from 'bobril';
import { mainPage } from './page';
import { pageOne } from './pages/pageOne';
import { pageTwo } from './pages/pageTwo';

b.routes(
    b.route({ handler: mainPage }, [
        b.route({ url: '/one', name: 'one', handler: pageOne }),
        b.route({ url: '/two/:text?', name: 'two', handler: pageTwo }),
        b.routeDefault({ handler: pageOne })
    ])
);

The whole application will be handled by a handler mainPage with sub-routes one and two on urls '/one' and '/two' handled by handlers pageOne and pageTwo.

The default handler pageOne will be used when no sub-route is specified.

The url for page two contains a parameter specification after a second slash. It is defined by a colon and a name of the parameter. The question mark defines the parameter as optional. Route parameters can then be found in the handler's context at ctx.data.routeParams.

Handling Routes in Pages

Now, we need to define the mainPage to render some own content and the visual content of the active sub-route. To do this, we will use a function provided in component's ctx.data.activeRouteHandler, so we can change the code of page.ts as the following:

import * as b from 'bobril';

export const mainPage = b.createComponent({
    render(_ctx: b.IBobrilCtx, me: b.IBobrilNode): void {
        me.children = [
            tag('h1', 'Routing example'),
            tag('hr'),
            tag('div', me.data.activeRouteHandler()),
        ];
    }
});

This code will render a header, a line and the visual content of current active sub-route.

Now, we need to define sub-pages and transitions between these pages. Bobril offers the following functions and interface for these purposes:

  • b.IRouteTransition - interface for a transition definition (target name, parameters etc.)
  • b.createRedirectReplace - creates IRouteTransition object for redirect without saving history
  • b.createRedirectPush - creates IRouteTransition object for redirect with saving history
  • b.runTransition - runs a transition according to an input IRouteTransition object
  • b.link - changes an input IBobrilNode to a link to the route of a specified name and with specified optional params

Example of the redirect definition from the page one to the page two in pages/pageOne.ts:

import * as b from 'bobril';
import { textbox } from '../components/textbox';
import { button } from '../components/button';

let value = '';

export const pageOne = b.createComponent({
    render(ctx: b.IBobrilCtx, me: b.IBobrilNode): void {
        me.children = [
            textbox({ value, onChange: (newVal) => { value = newVal; b.invalidate(ctx); } }),
            button({
                title: 'Confirm',
                onClick: () => {
                    b.runTransition(b.createRedirectPush('two', { text: value }));
                    return true;
                }
            })
        ];
    }
});

The code in a button's onClick callback creates and runs a transition to the page two with an object defining the value of a text parameter.

The transition above has to be handled by the pageTwo handler defined in pages/pageTwo.ts:

import * as b from 'bobril';
import { tag } from '../helper';
import { loggedIn } from '../page';

export interface IData {
    routeParams: { text?: string };
}

export interface ICtx extends b.IBobrilCtx {
    data: IData;
}

export const pageTwo = b.createComponent<IData>({
    render(ctx: ICtx, me: b.IBobrilNode): void {
        let value = (ctx.data.routeParams.text || '').trim();
        me.children = [
            tag('p', 'Your text: ' + (!!value ? value : 'nothing')),
            b.link(tag('a', 'Go back'), 'one')
        ];
    }
});

The page receives the text parameter value in its ctx.data.routeParams.text so we can specify the context and data interfaces and use text in the render function of a page component. It also defines a link node to the page one by function b.link.

Transition Availability

There are some cases when we need to manage whether a current page on a current route is available or whether we can leave the current page. For these purposes, we can use the following static functions of IBobrilComponent:

  • canActivate - It can stop the current transition in a target handler by returning false or redirect to the new specified transition
  • canDeactivate - Can stop the current transition in the a source handler by returning false or redirect to the new specified transition

So for example, we can handle leaving the page one with empty value of a textbox by adding canDeactivate function definition to the page one component definition in pages/pageOne.ts:

canDeactivate() {
    return !!value.trim() || confirm('The textbox is empty. Are you sure?');
}

or handle the not logged user on accessing the page two by adding canActivate function definition to the page two component definition in pages/pageTwo.ts:

canActivate() {
    if (loggedIn)
        return true;
    alert('You are not logged in!');
    return b.createRedirectReplace('one');
}

Note: The loggedIn variable is declared and set in mainPage and imported to the pageTwo. See the page.ts in the attached full sample.

Summary

As you can see, the bobril framework contains really simple routing mechanism able to fulfill all standard requirements.

Download the full sample for the whole application with all the mentioned functions.

History

  • 2017-07-30 Revision (bobril-build@0.71.1, bobril@7.3.2, TS 2.4.2)
  • 2017-02-01 Revision (bobril-build@0.59.2, bobril@5.2.1)
  • 2016-11-04 Revision
  • 2015-12-16 Changed to simpleApp based on bobril-build
  • 2015-11-22 Article created

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Tomáš Růt
Team Leader Quadient
Czech Republic Czech Republic
No Biography provided

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.171114.1 | Last Updated 13 Aug 2017
Article Copyright 2015 by Tomáš Růt
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid