What about Ajax?

Refreshing an individual Widget

You can build a Widget which gets refreshed without reloading the entire page.

The tutorial.ajaxbootstrap example has Nav and a Div. The contents of the Div changes each time an item is selected on the Nav without reloading the entire page.

Only HTMLElements can refresh. To let an HTMLElement refresh, it needs arguments and needs to call enable_refresh() in its __init__ method.

In the example, RefreshedPanel is given arguments in an exposed method named query_fields(). Each argument is defined by assigning a Field to an attribute of fields:

    @exposed
    def query_fields(self, fields):
        fields.selected = IntegerField(required=False, default=1)

This makes the value of self.selected available in RefreshedPanel.__init__ to be used when generating the RefreshedPanel (self.selected is set from the URL or the default of the Field):

class RefreshedPanel(Div):
    def __init__(self, view, css_id):
        super(RefreshedPanel, self).__init__(view, css_id=css_id)
        self.add_child(P(view, text='You selected link number %s' % self.selected))
        self.enable_refresh()

A special “in-page” Bookmark refers to a Widget on the current UrlBoundView, but with different argument values.

Construct such a Bookmark for a given value of selected by calling for_widget() with suitable query_arguments. Before using the Bookmark, call on_view() to bind it to the current View.

    def get_bookmark(self, for_selected):
        return Bookmark.for_widget('Select %s' % for_selected, query_arguments={'selected': for_selected}).on_view(self.view)

Use such bound Bookmarks as usual:

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

        panel = RefreshedPanel(view, 'my_refreshedpanel')
        bookmarks = [panel.get_bookmark(1),
                     panel.get_bookmark(2),
                     panel.get_bookmark(3)]

        self.add_child(H(view, 1, text='Refreshing widget'))
        self.add_child(Nav(view).use_layout(TabLayout()).with_bookmarks(bookmarks))
        self.add_child(panel)

Note

If a Widget declares query_fields, it must have a unique css_id.

Paging long lists

The tutorial.pagerbootstrap example lets a user page though a very long list of Addresses, displaying only a managable number at a time.

Three objects play a role in this scenario:

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

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

        self.page_index = SequentialPageIndex(Address.all_addresses(), items_per_page=5)
        self.address_list = AddressList(view, self.page_index)
        self.page_menu = PageMenu(view, 'page_menu', self.page_index, self.address_list)

        self.add_children([self.page_menu, self.address_list])

Since AddressList is a PagedPanel, it automatically refreshes and computes its current_contents based on the given SequentialPageIndex.

class AddressList(PagedPanel):
    def __init__(self, view, page_index):
        super(AddressList, self).__init__(view, page_index, 'addresslist')
        for address in self.current_contents:
            self.add_child(P(view, text='%s: %s' % (address.name, address.email_address)))

Other implementations of PageIndex are possible, such as AnnualPageIndex which arranges all items with the same year together.

../_images/pager.png