feder
feder

Reputation: 2058

How to design navigation for a Starlette SPA

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?

Any design experience is highly welcome.

Upvotes: 2

Views: 334

Answers (2)

feder
feder

Reputation: 2058

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));

Upvotes: 1

Irfanuddin
Irfanuddin

Reputation: 2605

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")

Upvotes: 1

Related Questions