Using get_url_hash() to get both a str() & dict()

Hello Friends:

When using get_url_hash(), is there a way to leverage both behaviors. For example:

  • https://example.com/#startForm # Emits str(): startForm
  • https://example.com/#?a=1&b=2 # Emits dict(): {'a':1, b:2}

What if you wanted both, say?

  • https://example.com/#startForm#?a=1&b=2 # Emits str(): startForm#?a=1&b=2

Are you on your own at that point in terms of parsing and converting? No big deal if yes; I was just wondering if there was something that I missed. I suppose get_url_hash() would have to emit something like a tuple (str, dict) in the example I showed. :slight_smile:

Thank you!

If you have that sort of URL structure, you really should be using Anvil Extra routing, which handles parsing the URL for you.

I don’t know the specific answer to your question, because my use of get_url_hash() ended as soon as the routing module showed up.

1 Like

Thank you. It’s not really for page navigation per se, but more passing in options that tweaks the behavior of code.

And here is the second answer that talks about the routing module instead of answering your question :slight_smile:

When I started using the routing module, I switched the self.search_text.change event from performing the search to redirecting to the same page with f'?search_term={self.search_text.text}', then performing the search in the form_show event.

My instinct says that this may be not ideal with very complex forms, but that’s what I do for example in a form with 6 data grids, each with hundreds of items, one of them has dozens of drawings dynamically generated in a canvas of its template. The whole form is regenerated, including the things that are not affected by the search, but you don’t even see it flickering. I will listen to my instinct only the day after I see performance problems.

The advantages are two:

  1. I don’t need to do the search twice, when it’s driven by the url and when it’s driven by the UI
  2. I can always copy the url and paste it in an email to go to the same page with the same search terms, regardless of how I ended up in that page with those search terms

In other words, if you look at the url for any page of any of my apps, you can see how many input elements each form has, because every change on every value of every input element is immediately reflected on the url.

I need to keep track of which input element has the focus, so I can restore it after the form has been rendered, and I do it with the local_storage module of Anvil Extras.

Here is an example of the form_show event:

def form_show(self, **event_args):
    self.search_text.text = self.url_dict.get('search', '')
    self.status_filter.text = self.url_dict.get('status', Status.default_filter)
    self.facility_filter.text = self.url_dict.get('facility', Facility.default_filter)

    focus_was_on = local_storage.get('focus')
    if focus_was_on == 'status_filter':
        self.status_filter.focus()
    elif focus_was_on == 'facility_filter':
        self.facility_filter.focus()
    else:
        self.search_text.focus()

And the function assigned to both search button click and search text pressed_enter events:

def search_click(self, **event_args):
    local_storage['focus'] = 'search_text'
    routing.clear_cache()
    routing.set_url_hash(url_pattern='projects', url_dict={
        'search': self.search_text.text,
        'status_filter': self.status_filter.text,
        'facility_filter': self.facility_filter.text,
    })

I also often switched from using the self.search_text.change to using the self.search_text.pressed_enter event, just to decrease the flickering.

3 Likes

Nice. I’ll have to take care to read your strategy. Thank you.

Ah, flickering. In my code comments I call it the same. At times I use Python ternaries (to avoid unnecessarily setting .visible); or checking if a nav-link is already selected and simply returning if so,… all to avoid YouTube reload flicker, especially if a user keeps clicking a darn link already rendered. :slight_smile:

If you really want to do the parsing yourself, as opposed to using the routing module for its benefits, you can do that pretty easily in Python:

url_hash = "startForm?a=1&b=2"
params = url_hash.split('?')[1]
result = {r.split('=')[0]:r.split('=')[1] for r in params.split('&')}

That’s quick and dirty, obviously with no error checking.

3 Likes

Hi! Yes, that’s exactly what I did (quite similar) and the spirit of what I was thinking of for this scenario (splits, partition, subscripting, etc almost identically), but wrapped in try/except and asserts. Then, if anything fails with the parsing, my escape hatch is just the default behavior of the application, which is robust. In order words, these URL options invoke nice to haves but not must haves, and should parsing fail, I simply parachute back to the default must haves of the application. :relaxed: Thank you!

1 Like