Is there a way to show a LoadingSpinner while the final application is loading?

Hello,

I have an app which take several seconds to build before showing anything.
I was wondering if it was possible to show a loading spinner while the app is initializing in an other thread
I succeed to make something similar when the app is embed in a standard Viewable (cf code below)
However I don’t know if it is possible to do it with a panel Template

import time
import threading
import panel as pn
from functools import partial


def my_app():
    time.sleep(1)
    return pn.pane.Markdown("App ready")
    # return pn.template.BootstrapTemplate()


def _center_loading_spinner():
    return pn.Column(pn.Spacer(sizing_mode="stretch_height"),
        pn.Row(
            pn.Spacer(sizing_mode="stretch_width"),
            pn.widgets.LoadingSpinner(align="center", value=True),
            pn.Spacer(sizing_mode="stretch_width"),
            sizing_mode="stretch_both"
        ),
        pn.Spacer(sizing_mode="stretch_height"),
        sizing_mode="stretch_both",
    )


def _on_app_ready(app, root):
    root.objects = [app()]


def _app_launcher(app):
    main = pn.Column(sizing_mode="stretch_both")
    spinner = _center_loading_spinner()
    main.objects = [spinner]
    th = threading.Thread(target=partial(_on_app_ready, app=app, root=main))
    th.start()
    return main

if __name__ == "__main__":
    # import debugpy
    # debugpy.listen(5678)
    # debugpy.wait_for_client()
    def app_launcher():
        return _app_launcher(my_app)
    server = pn.io.get_server(app_launcher)
    print(f"Bokeh app running at: http://localhost:{server.port}")
    server.run_until_shutdown()

Related
https://panel.holoviz.org/user_guide/Deploy_and_Export.html#pn-state-onload
https://panel.holoviz.org/gallery/simple/defer_data_load.html

indeed with pn.state.onload I can simplify a little bit my code to not use threads

def _app_launcher(app):
    main = pn.Column(sizing_mode="stretch_both")
    spinner = _center_loading_spinner()
    main.objects = [spinner]
    def on_load():
        main.objects = [app()]
    pn.state.onload(on_load)
    return main

but my problem with a panel Template remain since it can not be embed in a row or column but must do something with the bokeh document

I don’t know the answer, but I would like to know if it’s possible. The templates can not be rendered again as structured now.

One possibility if to change the div with the new element sending code by an HTML pane. Something like this

document.getElementById('main').innerHTML ="<div> Hola </div>"

What I do not know is how to get the panel div. I tried to use panel_object.get_root(), but the obtained id is not the same as the exposed id in Bokeh.index.

Aditionally, I know that Bokeh has some Bokeh.documents[0].get_element_by_Name() function, but not all panel object are exposed in the javascript namespace. It would be good to know how to get an arbitrary panel element from javascript.

1 Like

Maybe it would be an idea to add this (optional) functionality to the template it self.

For the fast templates would you prefer the loading spinner or a skeleton?

For my use case I don’t know at first if it will be a tempate or not which will be served.
We are developping a sort of plugin system based on panel embed in our software and I’m not the application creator. I just deploy it and I wanted a system to show that something is happened while the application is created.