Edit - Much of the discussion in this post is no longer relevant
Summary
table
- used to get a row from the server and populateform.item
when the user navigates back to a previously visited page
This is definitely optional. It’s only really for a very simple case when your form is just a row from a table.
A lot of the Anvil Examples display a form where the item is a table row and I was trying to work it into the system. I based the routing initially on this example thinking how I might go about it…
But maybe it overcomplicates the process…
In my main app I actually never used this function I just retrieve my item
from a server call whenever the form is loaded based on the url_dict
keys
- this is sometimes a list and sometimes a key?
keys is always a list - it might be a list of 1 item (or an empty list) - but always a list. (could also be a tuple)
It’s also optional since your url might be text only.
keys was designed for a situation like article?id=1
Essentially - A form that needs to get a unique item based on parameters.
I use it a lot in my main app in the same way.
Maybe this is trying to be too clever. But let’s say that you open an article form because someone set the url to be /#article?id=3
then here it’s obvious that the url_dict should be {'id':3}
But what if you just do:
get_open_form.content_panel.clear()
get_open_form.content_panel.add_component(ArticleForm(id=3, user=user))
or even
get_open_form.content_panel.add_component(ArticleForm(item=item))
# and item includes item['id'] --> 3
then routing will go about searching the properties you passed to the form and (assuming) your form was sent that property - which it should, otherwise, what was the point in making it a key
in the first place…?
It will then create the url_dict
based on these properties you passed to the form…
But maybe you change the url_dict, because…
I did something in my main app like this - let’s say you have a create new article button
and do:
def create_new_article_button_click(self, **event_args):
get_open_form.content_panel.clear()
get_open_form.content_panel.add_component(ArticleForm(id=None))
...
@routing.route('article',keys=['id'])
class ArticleForm(ArticleFormTemplate):
def __init__(self, **properties):
init_components(**properties)
if not self.url_dict['id']:
# create a new article
self.item = anvil.server.call('create_new_article')
self.url_dict['id'] = self.item['id']
else:
self.item = anvil.server.call('get_article', self.url_dict['id'])
in other words you’ve changed the url_dict from in the init_method
You wouldn’t want the url to be /article?id=None
so after your form init
method Hash_Routing
will update the url_dict to ensure that the url_hash matches the url_hash you intended…
properties
- is this the same as the**properties
defined in the form?
yeah this is the same as **properties.
So it’s basically a dictionary
of all the kwargs
you might usually pass into a particular form.
Again you might never use this option. I haven’t, in my main app since there aren’t any properties that I always pass to a particular form.
The automatic population of
item
is not necessary
agree - you could totally disregard this in your routing behaviour. I do in my main app.
My items are typically Live table rows and I just don’t provide a table.
I can imagine that if the item is a dictionary then this might be more annoying so we’ll cross that bridge when it comes…
But I can’t foresee it being too much of an issue since you can just assign your self.item in the usual way based on the url_dict and all will be fine…
I don’t see the added value of
self.url_patterns
- I would like to use a simpler
@routing.route('article')
decorator in front of every form that should be managed- When the app starts and imports all the forms, a global dictionary should be populated automatically as the decorators are executed (rather than explicitly defining
self.url_patterns
inside the main form
Ooooh I like that. I’ll give it a try later!
I would like to add the management of the query_close event
- If an app uses this routing module, then all the form management should be done via this module (no more
get_open_form().content_panel.add_component()
)
I think this point is separate point…
That sort of is the case in that you can just do set_url_hash('article')
and everything is taken care of by routing. You don’t need to ever do get_open_form().content_panel.add_component()
if you don’t want to…
Similarly, if you do call get_open_form().content_panel.add_component()
you don’t actually need to do get_open_form().content_panel.clear()
before it as Hash_Routing
should just clear the current form when a new route Form
is opened…
In the example app I shared I think I only called this once when I loaded the ArticleForm
passing the item
as a kwarg
and I didn’t call the clear method…
but I could also have done.
set_url_hash(f"article?id={self.item['id']}")
- The routing module knows when a form is about to be unloaded, so it can (try to) call its
query_close
event and decide whether to interrupt the process of closing this form and navigating to the new one- The
query_close
event should be called when:- The app navigates to another form
- The URL changes for any other reason
- The browser tab/window is closed
I think I follow…
something like the form hide
event but it should be raised just before the form is cleared?
# pseudo code
on navigation
current_content_panel_form.raise_event('x-query-close')
then in that form you could do something like
self.set_event_hadler('x-query-close', self.query_close)
def query_close(self, **event_args):
if unsaved_changes:
if confirm('are you sure you want to close there are unsaved changes'):
pass
else:
cancel_navigation_somehow....?
What I was doing for the typical save changes was just saving the changes on the form hide
event.
Which worked well for me but I can see how this would be important for other apps…
Also note that the app has no control over the user deciding to close the tab because that’s outside of the window
(I think)