def open_form(form_name, full_width=False): """Use classic routing to open a registered form""" form = get_form(form_name) _title_label.text = _forms[form_name]["title"] get_open_form().content_panel.clear() get_open_form().content_panel.add_component(form, full_width_row=full_width)
def load_template(url_hash): global _current_form form = get_open_form() current_cls = type(form) if form is not None and current_cls not in _templates: raise NavigationExit # not using templates logger.debug("Checking routing templates") for cls, path, condition in chain.from_iterable( _ordered_templates.values()): if not url_hash.startswith(path): continue if condition is None: break elif condition(): break else: load_error_or_raise(f"No template for {url_hash!r}") if current_cls is cls: logger.debug(f"{cls.__name__!r} routing template unchanged") else: logger.debug( f"{current_cls.__name__!r} routing template changed to {cls.__name__!r}, exiting this navigation call" ) _current_form = None f = cls() logger.debug(f"form template loaded {cls.__name__!r}, re-navigating") open_form(f) raise NavigationExit
def on_navigation(self, url_hash=None, url_pattern=None, url_dict=None, path=None, dynamic_vars=None): # when there is navigation - back/forward navigation # or when the user changes the url_hash or when you call anvil.set_url_hash in code # calls the current_form's before_unload method # calls the MainForm's on_navigation method # get's the form to load (loads the error_form if there is no form to load) # loads the form global _on_navigation_stack_depth if _on_navigation_stack_depth > 5: logger.print('**WARNING** \nurl_hash redirected too many times without a form load, getting out\ntry setting redirect=False') return # could change this to a raise _on_navigation_stack_depth += 1 if getattr(_current_form,'before_unload', None): logger.print(f'{_current_form.__name__} before_unload called') """ # before_unload in the form to be unloaded will be called here if the method exists # Mostly useful to prevent unloading the current form # it's not perfect so use with caution!!! # if you don't need to prevent a form from unloading ...but ... # ... do need to do something when the form is hidden use the form_hide event instead # To stop_unload return a value from the before_unload method """ _anvil.js.call_js('setUnloadPopStateBehaviour',True) stop_unload = _current_form.before_unload() if stop_unload: logger.print(f"stop unload called from {_current_form.__name__}") _anvil.js.call_js('stopUnload') _on_navigation_stack_depth -= 1 return #this will stop the navigation _anvil.js.call_js('setUnloadPopStateBehaviour',False) if not (url_hash and url_pattern and url_dict): url_hash, url_pattern, url_dict = get_url_components() logger.print(f"on_navigation triggerd\nurl_hash = {url_hash}\nurl_pattern = {url_pattern}\nurl_dict = {url_dict}") if getattr(Cls,'on_navigation', None): logger.print(f'{Cls.__name__} on_navigation called') # on_navigation in your main form will be called here # in the example we change 'selected' role on links using this method Cls.on_navigation(self, url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, unload_form=_current_form) try: if url_hash not in _cache and path is None: path, dynamic_vars = self.find_path(url_hash, url_pattern, url_dict) except KeyError: logger.print(f'no route form with url_pattern={url_pattern} and url_keys={url_dict.keys()}') if _error_form is not None: load_error_form() elif _anvil.get_open_form(): # raising an exception before there is an open form stops anything loading raise # if you can't work out why your page won't load then take raise out of this if block... except: raise # this was an unexpected error so raise it else: self.content_panel.clear() # clear the form now just incase we end up with a new to cache form that is slow to load later self.load_form(url_hash=url_hash, url_pattern=url_pattern, url_dict=url_dict, path=path, dynamic_vars=dynamic_vars) _on_navigation_stack_depth -= 1
def add_form_to_container(form): if form.parent: # I may have been used within another template so remove me from my parent form.remove_from_parent() layout_props = getattr(form, "_routing_props", {}).get("layout_props", {}) cp = get_open_form().content_panel cp.clear() # clear it again cp.add_component(form, **layout_props)
def fire_show_event(e): if component is None: return open_form = _anvil.get_open_form() if open_form is not None and fake_container.parent is None: open_form.add_component(fake_container) if component.parent is None: # we add the component to a Container component # this doesn't really add it to the dom # it just allows us to use anvil's underlying show hide architecture fake_container.add_component(component)
def load_template_or_redirect(url_hash): global _current_form form = get_open_form() current_cls = type(form) if form is not None and current_cls not in _templates: raise NavigationExit # not using templates logger.debug("checking templates and redirects") for info in chain.from_iterable(_ordered_info.values()): callable_, paths, condition = info try: path = next(path for path in paths if url_hash.startswith(path)) except StopIteration: continue if condition is None: break elif not condition(): continue elif type(info) is TemplateInfo: break redirect_hash = callable_() if isinstance(redirect_hash, str): if navigation_context.matches_current_context(redirect_hash): # would cause an infinite loop logger.debug("redirect returned current url_hash, ignoring") continue from . import set_url_hash logger.debug(f"redirecting to url_hash: {redirect_hash!r}") set_url_hash( redirect_hash, set_in_history=False, redirect=True, replace_current_url=True, ) navigation_context.check_stale() else: load_error_or_raise(f"no template for url_hash={url_hash!r}") if current_cls is callable_: logger.debug(f"unchanged template: {callable_.__name__!r}") return info, path else: msg = f"changing template: {current_cls.__name__!r} -> {callable_.__name__!r}" logger.debug(msg) _current_form = None # mark context as stale so that this context is no longer considered the current context navigation_context.mark_all_stale() f = callable_() logger.debug(f"loaded template: {callable_.__name__!r}, re-navigating") open_form(f) raise NavigationExit
def load_error_form(): global _error_form, _current_form logger.debug(f"loading error form: {_error_form!r}") url_hash, _, _ = get_url_components() _cache[url_hash] = _error_form() _current_form = _cache[url_hash] f = get_open_form() if f is not None: add_form_to_container(_current_form) else: open_form(_current_form ) # just in case we somehow don't have a valid template!
def alert_form_loaded(**url_args): f = get_open_form() on_form_load = getattr(f, "on_form_load", None) if on_form_load is not None: logger.debug(f"{f.__class__.__name__}.on_form_load() called") on_form_load(**url_args)
def clear_container(): get_open_form().content_panel.clear()
def alert_on_navigation(**url_args): f = get_open_form() on_navigation = getattr(f, "on_navigation", None) if on_navigation is not None: logger.debug(f"{f.__class__.__name__}.on_navigation() called") on_navigation(unload_form=_current_form, **url_args)
def _update_key(key): if type(key) is str: key = (key, type(get_open_form()).__name__) return key