So it’s not possible to have this be part of the layout function already?
It has to be within a callback?
I’ll come back with an M(non)WE once I’m back at my machine.
EDIT: This somewhat does it:
from dash import Dash
from dash_bootstrap_components.themes import BOOTSTRAP
from dash import Dash, html, callback, Output, Input
from flask import request
@callback(
Output('IP', 'children'),
Input('btn-1', 'n_clicks')
)
def ip(_: int) -> html.Div:
req: dict = request.__dict__.copy()
return html.Div(
children=[
html.Div(f"{key}: {val}") for key, val in req.items()
]
)
def create_layout(app: Dash) -> html.Div:
return html.Div(
className="app-div", # type: ignore
children=[
html.H1(app.title),
html.Hr(),
html.Button('Button 1', id='btn-1'),
html.Div(id="IP"),
],
)
app = Dash(
__name__,
suppress_callback_exceptions=True,
#use_pages=True,
external_stylesheets=[BOOTSTRAP],
)
app.title = "TEST"
app.layout = create_layout(app)
def main(app: Dash) -> None:
app.run(debug=True, dev_tools_ui=True, dev_tools_hot_reload=True)
if (__name__ == "__main__"):
main(app)
However, this requires an option to be present that triggers the callback - a button in this example.
Can this be done without such an option right at call time but not after?
Calling the function in the layout, i.e., html.Div(id="IP", children=ip(0))
, breaks the request context (why even? we usually can call functions that generate a layout, can’t we?).
EDIT:
Can a callback have no input? somewhat deals with the same issue which makes it cleaner looking than my button solution:
from typing import Any
@callback(
Output('IP', 'children'),
Input('none', 'children')
)
def ip(_: Any) -> html.Div:
...
and in the layout:
...
html.Hr(),
html.Div(
id='none',
children=[],
style={'display': 'none'},
),
html.Div(id="IP"),
...
But it still should be able to get this done without a callback shouldn’t it?