How to design navigation for a Starlette SPA

Viewed 39

I want to create a light-weight-SPA.

I thought of passing in a path param (nav_element), which also corresponds to the resource. The Jinja2 engine can then simply access the value by {{nav_element}}.

async def dashboard(request: Request):
    """For this page you must be authenticated."""    
    await request.send_push_promise("/static/styles.css")

    try:
        nav_element = request.path_params['nav_element']
    except KeyError as ex:
        nav_element = None
    logger.info(nav_element)

    return templates.TemplateResponse('dashboard.html', {'request': request, "nav_element": nav_element})

routes = [
    Route('/', endpoint=dashboard, methods=["GET"]),
    Route('/{nav_element:str}', endpoint=dashboard, methods=["GET"]),
    Mount(path="/static", app=StaticFiles(directory="static"), name="static")
]

webapp = Starlette(routes=routes )

(there is one thing I don't like with this approach, it requires 2 routes. anyhow.)

So, but how do I load the page elements?

  • JavaScript I could do. But what is the best practice with Jinja2/Starlette to load only specific elements of the page after clicking them in the navigation?
  • Are there Jinja2/Starlette elements that could help me rendering/loading page elements/fractions/webcomponets for the SPA? I know {% include a_page.html %}. But that would not be how we load a SPA, right?!
  • I really want to avoid to load entire pages.

Any design experience is highly welcome.

2 Answers

I did not have a sample to try, but can you try this?

async def dashboard(request: Request):
    """For this page you must be authenticated."""
    async def streamer():
        try:
            nav_element = request.path_params['nav_element']

        except KeyError as ex:
            nav_element = None
        yield templates.TemplateResponse('dashboard.html', {'request': request, "nav_element": nav_element}).body

    return StreamingResponse(streamer(), media_type="text/html")

I must say any other solution than loading widgets for an Starlette-SPA by Javascript becomes utterly complex. There is one reason, when you load a HTML-template and you use the jinja2 include statements, it will NOT invoke the endpoint that is associated with it in Starlette. Thus, the data, which needs to be fetch for displaying in the widget (processed in the HTTPEndpoint), is never invoked. Makes sense in a way.

So the only way I found is to send another http request after the page has been loaded. I think that is the cleanest/shortest way to go for widgets (which have no SEO-requirements) not trying to work against Starlette's concept.

main = document.querySelector("#main_content > .title");
fetch("/dashboard/widgets/test")
                .then(response => response.text())
                .then(data => main.insertAdjacentHTML("afterend", data));
Related