diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b7daf48..51a8ea02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ # Unreleased ## New Features +* `routing.lazy_route` - allows you to lazily load Forms whilst using routing + https://github.com/anvilistas/anvil-extras/pull/442 * Autocompletion: adds filter_mode property - either contains or startswith https://github.com/anvilistas/anvil-extras/discussions/444 diff --git a/client_code/routing/__init__.py b/client_code/routing/__init__.py index c85597f1..ac8f59f4 100644 --- a/client_code/routing/__init__.py +++ b/client_code/routing/__init__.py @@ -12,7 +12,7 @@ from . import _navigation from . import _router as _r from ._alert import alert -from ._decorators import error_form, redirect, route, template +from ._decorators import error_form, lazy_route, redirect, route, template from ._logging import logger from ._router import NavigationExit, launch from ._utils import ( diff --git a/client_code/routing/_decorators.py b/client_code/routing/_decorators.py index e2115be0..ee305185 100644 --- a/client_code/routing/_decorators.py +++ b/client_code/routing/_decorators.py @@ -93,3 +93,24 @@ def error_form(cls): cls._route_props = {"title": None, "layout_props": {}} _router._error_form = cls return cls + + +def lazy_route( + url_pattern="", url_keys=[], title=None, full_width_row=False, template=None +): + route_wrapper = route(url_pattern, url_keys, title, full_width_row, template) + + def wrapper(fn): + class Lazy: + _form = None + + def __new__(cls, **properties): + form_class = cls._form + if form_class is None: + form_class = cls._form = fn() + return form_class.__new__(form_class, **properties) + + route_wrapper(Lazy) + return fn + + return wrapper diff --git a/docs/guides/modules/routing.rst b/docs/guides/modules/routing.rst index 656c888e..fd33b64c 100644 --- a/docs/guides/modules/routing.rst +++ b/docs/guides/modules/routing.rst @@ -389,6 +389,22 @@ Decorators If the ``before_unload`` method is added it will be called whenever the form currently in the ``content_panel`` is about to be removed. If any truthy value is returned then unloading will be prevented. See `Form Unloading <#form-unloading>`__. +.. function:: routing.lazy_route(url_pattern, url_keys=[], title=None, full_width_row=False, template=None) + + .. code:: python + + from anvil_extras import routing + + @routing.lazy_route('article', url_keys=['id', routing.ANY], title="Article-{id} | RoutingExample") + def article_route(): + from ..ArticleForm import ArticleForm + return ArticleForm + + This decorator allows you to lazily load Forms. When using ``@routing.route`` all Forms that are routes must be imported before the app starts. + This is fine for most small applications, but as your application grows you may find that executing all the code for all the Forms is slow. + The ``lazy_route`` decorator should decorate a function that imports the Form and returns it. + + .. function:: routing.redirect(path, priority=0, condition=None) The redirect decorator can decorate a function that will intercept the current navigtation, depending on its ``path``, ``priority`` and ``condition`` arguments.