One click nav handler without initializing pages

Hey all,

I’ve stumbled on to a modification of the “one click nav handler” from the Docs that seems to work better for me than the provided example. I want to put it up here so anyone can tell me if there’s a good reason not to do it this way.

In the docs, each link clicked has an associated tag with an instance of the page it should display, like so:

# set each Link's `tag.form_to_open` attribute to an instance of the Form you want to open
self.home_link.tag.form_to_open = Home()
self.about_link.tag.form_to_open = About()
self.contact_link.tag.form_to_open = Contact()

That tag is accessed as:

form_to_open = event_args['sender'].tag.form_to_open

This created some issues for me, though, as I was managing my data on the page level (ie, the Product List page should retrieve a list of products). The big issue was that the above setup causes each page to retrieve the data when the app is first loaded. This meant that:
A) All my pages were making their trips to the database at once
B) The page’s data reflected the data as it was when the app loaded, not when the link was clicked (what if it was edited on another page since the app was loaded?)

I discovered that not instantiating the page until the link is clicked solves these problems. Instead of storing the tag as above, I would do so without the parentheses at the end (without instantiating) like so:

 self.home_link.tag.form_to_open = Home
self.about_link.tag.form_to_open = About
self.contact_link.tag.form_to_open = Contact

Then when we grab it from the tag:

form_to_open = event_args['sender'].tag.form_to_open()

This will cause a page to only load its data when its link is clicked, not pre-load the data. If you ever need to refresh your data on a page, like after editing something in the table, you simply run its init again.

While page loading times are ever so slightly higher because of the server call when the page is loaded, it saves the complexity of having to manage all my client side data in a single spot.

Am I missing a reason why this might be a bad idea? Its not even mentioned as a possibility in the docs (as an alternative to pre-loading all your client-side data up front).

2 Likes

I can think of a few situations where this might be less-desirable. They all revolve around “global variable” issues. When a Form provides variables or functions used elsewhere, one or both of the implicit assumptions below may apply.

  1. Each Form is constructed in advance, i.e., because other code uses its parts right away.
  2. Each Form is constructed at most once, preserved, and reused (re-displayed) when needed, i.e., because there should be only one copy of the Form’s data (e.g., a single “source of truth” about a value).

In your revised code, a new instance of a Home form will be created each time home_link is clicked, each with its own set of variables.

Whether these assumptions actually apply depends on how the App is written.

2 Likes

Hi @leeself and welcome to the forum,

The docs highlight possible navigation techniques but they’re not exhaustive. Another technique would be to outsource navigation to a separate module whose job it would be to handle all things related to navigation. This method is very well presented in the talkpython anvil course and worth a watch.

If you do have a bunch of server calls on those forms then avoiding loading each form at startup is a good idea.

But you might also want to cache those forms. This way you get super snappy page transitions which users will appreciate. And the benefits mentioned from @p.colbert

If data changes between page clicks then silent server calls in the form show events are often a good way to keep the page up to date. It may also be that you can be cleverer if you know an action somewhere should trigger an update of data on another page.
You can look in the cache. Check if that form exists and then update its data.

You also might want to check out the HashRouting dependency if you’re thinking about navigation.

It caches the form so that the same form instance loads each time and that instance is only loaded upon navigation to the page (not at start up).

2 Likes

Thank you @p.colbert and @stucork for the help!

Sounds like the potential downsides were pretty much in line with what I expected. I hadn’t thought of silent server calls in the form show events, and will look into both that and the HashRouting dependency.