What I’m trying to do:
Create a way for my custom Calendar component to persist the last Year Month it was on when returning to the Calendar page. More generally, trying to find a strategy of persisting state when navigating away from a form.
What I’m thinking:
The obvious thing to do is when clicking on the Calendar button load in the last saved state from DataTables, and then pass it into the constructor for the Calendar object, and somehow inject a method capable of saving the state of the calendar, into the constructor as well. Something that looks like:
Calling the CalendarContainer each time is the problem here.
Really you want to cache that Form so that you always load the same form… this way it persists across navigation changes.
This way you only create a single instance of the CalendarContainer and next time the button is clicked it loads the cached form.
You can adjust the code be more DRY, and even take advantage of functools.cache
e.g.
import functools
from ..MainForm import MainForm
from ..CalendarContainer import CalendarContainer
class Startup(StartupTemplate):
def __init__(self, **properties):
self.init_components(**properties)
self.tag_to_form = {"main": MainForm, "calendar": CalendarContainer}
self.button_cal.tag = "calendar"
self.button_main.tag = "main"
@functools.cache
def get_form(self, tag):
"""return the cached form or creates a new one if not in the cache"""
return self.tag_to_form[tag]()
def nav_button_click(self, sender, **event_args):
form = self.get_form(sender.tag)
self.content_panel.clear()
self.content_panel.add_component(form)
Another option is to use the hash routing module.
This caches the forms so you don’t have to.
from anvil_extras import routing
from ..MainForm import MainForm
from ..CalendarContainer import CalendarContainer
@routing.main_router
class Startup(StartupTemplate):
def __init__(self, **properties):
self.init_components(**properties)
self.button_cal.tag = "calendar"
self.button_main.tag = ""
def nav_button_click(self, sender, **event_args):
# loads a cached form or creates a new one based on the url_hash
routing.set_url_hash(sender.tag)
---
# In the calendar form
@routing.route("calendar")
class CalendarContainer():
...
---
# In the MainForm
@routing.route("")
class MainForm():
...
And then there’s the anvil_extras navigation module which is worth exploring to help with navigation techniques.
When I want to use the values used the last time the form was used as default, whether in this session on in the previous session, I do:
from anvil_extras.storage import local_storage
def form_show(self, **event_args):
year = local_storage.get('date picker year', 1999)
def form_hide(self, **event_args):
local_storage['date picker year'] = year
In my apps I rarely use the form_hide, I usually use the event that happens immediately after the value changes, this is just a quick example.
All my apps use the hash routing module. Often, when the value of a text box changes, I put all the values of the text boxes and other input components in url_dict, then I call:
so not only is the current page updated, it is also possible to go back and forth in the browser history and it is possible to create a shortcut that includes the input as is at any point in time.
as the person who implemented functools in skulpt I can confirm it’s available
But it’s only available client side.
client side remains 3.7(ish) and the ish means you’ll occasionally get a 3.9 feature springled in.
(type hinting generics anyone?)
(although you can also do that on the server with from __future__ import annotations)
and if you wanted it in a module that was used on both client and server, you could wrap the import in a try except.