HashRouting: Routing, navigation with URL Hash

That worked! I had to update to the newest version of the code, I was apparently a little behind, but with that change it works without generating the KeyError.

Thanks!

2 Likes

Another question. I looked through the code and didnā€™t find anything that seemed obvious as a way to trigger the Back operation through code.

Maybe thereā€™s something else I should be doing in my situation?

I have a form that is a detail editing form. That form is routed to from the more general form. I want the detail editing form on the stack, so if the user hits Back when theyā€™re on it, itā€™s effectively a cancel operation (they go back to the more general form without saving changes).

The detail editing form has Save and Cancel buttons. For both of those, I want to route back to the more general form, but with the same effect on the history as if the user had hit the Back button.

1 Like

thereā€™s no implementation for going back but you could do one of the followingā€¦

GitHub - s-cork/HashRouting: HashRouting - a dependancy for anvil.works that allows navigation in apps

you can use replace_current_url for the general form

routing.set_url_hash('general_form', replace_current_url=True)

This will remove edit_form from history at least.

If I were to add a routing.go_back() function it would look like

<script>
function go_back() {
    window.history.back()
}
</script>

then inside the routing module

def go_back():
    _anvil.js.call_js('go_back')
2 Likes

Thanks! The go_back () function worked nicely.

Iā€™d been using replace_current_url, but having the general form on the stack twice was bugging me. Definitely not a huge issue, but go_back () behaves more the way I think users would expect.

2 Likes

@stucork A relatively minor issue. Iā€™m trying to implement session timeout handling, and started with routing.reload_page() when the session times out. That reloaded the page, but without the hash part of the URL.

So I then tried modifying the Javascript to take routing.get_url_hash () and put it into window.location.hash before calling window.reload(). That had no effect.

Then I tried passing the entire URL (main domain and hash routing combined) to Javascript and set window.location.href to it before window.location.reload(). Still no change in behavior.

At this point I donā€™t think I understand enough to know what else to try. Do you have any ideas for how to get a page reload that maintains the URL hash route?

2 Likes

Updates:

Iā€™ve included the following features

routing.go_back()
routing.go(0) # equivalent to refresh
routing.go(-1) # equivalent to routing.go_back
routing.reload_page() # just replace the content panel (but not from cache)
routing.reload_page(hard=True) # reload the page # equivalent to routing.go(0)

for the issue regarding SessionExpiredError
@jshaffstall was using a solution I suggestion here:

Apparently that solution is wrong! You canā€™t catch SessionExpiredErrors with a custom error handler. :man_facepalming:

Anvilā€™s behaviour is to reload the page with the href (thereby losing the url_hash)

So iā€™ve added a feature

routing.on_session_expired(reload_hash=True, allow_cancel=True)
# default behaviour as per anvil is reload_hash=False, allow_cancel=True

The session expired alert will happen as before but it will change the behaviour of the refresh now button

best place to call this is probably above your @routing.main_router form

To test this feature you can create a button that does

def button_click(self, **event_args):
  raise anvil.server.SessionExpiredError()
4 Likes

Oh wow I needed the refresh today. My hack was to load a blank form (literally called blank) and then load the page again without the cache.

Do I need to re-clone the app and connect it again as a dependency for these updates?

Thatā€™s what Iā€™ve been doing. Once youā€™ve made a clone, I donā€™t know of any way to cause it to update itself from the original project.

1 Like

I would use git

(the first time)

git clone ssh://anvil...... # clone your anvil reporsitory
git remote add HashRouting https://github.com/s-cork/HashRouting.git
git fetch HashRouting
git reset --hard HashRouting/master # make your local version the github version
git push origin master -f # force push to your anvil repo

subsequent times

git pull HashRouting
git push -f origin master # force push to anvil
6 Likes

iā€™m grateful to @starwort for adding a pull request to HashRouting

you can now add simple dynamic urls like

@routing.route('articles/{id}')
class ArticleForm(ArticleFormTemplate):

for more info see the section in the readme - https://github.com/s-cork/HashRouting#dynamic-urls

4 Likes

Iā€™m sure this is an operator error, but I keep getting a KeyError when trying to navigate to my customer details page with an ā€œidā€?

Code calling the form:

def link_expand_click(self, **event_args):
    """This method is called when the link is clicked"""
    customer_id = self.item['customer_id']
    routing.set_url_hash(url_pattern="customer", 
                         url_dict={'id': customer_id}, 
                         item=self.item)

Customer details form:

from HashRouting import routing

@routing.route('customer', url_keys=['id'], title='Title | Customer ID: {id}')
class CustomerDetails(CustomerDetailsTemplate):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    if not self.item:
      try:
        self.item = anvil.server.call('so_get_customer', self.url_dict['id'])
      except:
        raise Exception(f'no customer with id {self.url_dict["id"]}')

This is the Error:
KeyError: customer?id=3751 does not exist
at app/HashRouting/routing.py, line 169 column 22
called from app/HashRouting/routing.py, line 123 column 20
called from app/HashRouting/routing.py, line 130 column 20
called from app/HashRouting/routing.py, line 480 column 8

Usually this error means I forgot to import the form into my @routing.main_router form. More details on main_router are in the HashRouting docs.

2 Likes

Ahh, that makes sense!

Thank you.

@stucork - is there a 3rd party dependency code for this (like there is for tabulator) ? Or do I still need to download it?

You can use the routing module within anvil extras - itā€™s a copy of the code from the HashRouting github repo.

Ah ok, I didnā€™t spot it there (which says more about me than anything else ā€¦)

Cheers!

Just to add - there are the two options for adding this library

  1. add it with anvil_extras and replace

    from HashRouting import routing
    # with
    from anvil_extras import routing
    

    Use the Token: C6ZZPAPN4YYF5NVJ to add anvil_extras

  2. The original dependency can be added as a standalone third party dependency
    It will continue to be maintained - the code base parallels the anvil_extras library.
    (the most up to date version will be in anvil_extras)
    the standalone third party dependency token is : ZKNOF5FRVLPVF4BI

Enjoy

5 Likes

Could you please add this to the Anvil Extra docs? Though referenced somewhere (in Navigation ā€” Anvil Extras documentation) there is no indication that routing is now (also) a part of Extras. TIA

1 Like

@mjmare I mean, the thing about anvil-extras is that anyone can make a pull request to address outstanding issues. In this case, I think the main challenge is to translate the HashRouting docs from markdown here to reStructured Text hereā€“looks like there are some tools available for automating that, actually. I donā€™t think it needs to be @stucork who does that. Iā€™ve thought about it, but havenā€™t gotten to it yet. (Alternatively, you could make a much more limited pull request that just better advertises the availability of routing in anvil-extras, perhaps linking temporarily to the old docs location.)

1 Like