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 HTMLElement
s 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 Bookmark
s 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:
- A
SequentialPageIndex
breaks the long list of Addresses into separate chunks. - AddressList is a
PagedPanel
—it displays the appropriate chunk of Addresses (itscurrent_contents()
). - An accompanying
PageMenu
allows the user to navigate.
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.