Moving between Views

The user interface of the address book application can be split up into two Views : one that lists all the addresses, and another on which you can add a new address.

A diagram showing two Views, and how one can move between them.

The address book application with two UrlBoundViews.

Deriving similar looking pages

The simplest way to have many pages look similar is to create a common page from which you derive pages, each with different extra content. Add AddressBookPanel to HomePage, and AddressForm to AddAddressPage:

class HomePage(AddressBookPage):
    def __init__(self, view, main_bookmarks):
        super(HomePage, self).__init__(view, main_bookmarks)
        self.body.add_child(AddressBookPanel(view))
class AddAddressPage(AddressBookPage):
    def __init__(self, view, main_bookmarks):
        super(AddAddressPage, self).__init__(view, main_bookmarks)
        self.body.add_child(AddressForm(view))

Bookmarks and Navs

A Bookmark marks a particular UrlBoundView. A Nav is a menu created from a list of Bookmarks. It is a means for the user to move around in the application.

Create the common AddressBookPage with a Navbar just like before, but add a Nav to it:

class AddressBookPage(HTML5Page):
    def __init__(self, view, bookmarks):
        super(AddressBookPage, self).__init__(view)
        self.body.use_layout(Container())

        layout = ResponsiveLayout('md', colour_theme='dark', bg_scheme='primary')
        navbar = Navbar(view, css_id='my_nav').use_layout(layout)
        navbar.layout.set_brand_text('Address book')
        navbar.layout.add(Nav(view).with_bookmarks(bookmarks))

        self.body.add_child(navbar)

Bookmarks are created for the UrlBoundViews in AddressBookUI.assemble, and passed to the WidgetFactory of each page. The WidgetFactory arguments match those of the __init__ method of each page.

class AddressBookUI(UserInterface):
    def assemble(self):
        home = self.define_view('/', title='Show')
        add = self.define_view('/add', title='Add')

        bookmarks = [v.as_bookmark(self) for v in [home, add]]
        home.set_page(HomePage.factory(bookmarks))
        add.set_page(AddAddressPage.factory(bookmarks))

        self.define_transition(Address.events.save, add, home)

The call to define_transition() is changed to take the user back to the home page after adding a new Address.

AddressBookForm is unchanged in this example. AddressBookPanel though contains a list of AddressBoxes, but no AddressBookForm. The AddressBookForm is now on the other UrlBoundView.

class AddressBookPanel(Div):
    def __init__(self, view):
        super(AddressBookPanel, self).__init__(view)

        self.add_child(H(view, 1, text='Addresses'))

        for address in Session.query(Address).all():
            self.add_child(AddressBox(view, address))

Guards

“Page flow” can further be controlled by adding more than one Transition for the same Event with an Action guarding each. The Transition whose guard returns True when evaluated is followed.