Canāt edit my comment after a certain time, so hereās what Iāve done instead based on what @alexcjohnson recommended if it can help anyone.
- For the custom view depending on the user: always registering the callback and returning either the componentās layout or an empty layout ("" for example) actually works. It would just be like
child1.py
def layout():
### insert some layout here
# Callbacks
@app.callback(Output('foo', 'foo_prop'), [Input('bar', 'bar_prop')])
def my_cb(value):
###
# some logic here
return new_foo_prop_value
####
parent.py
from children import child1
from flask_login import current_user
@app.callback(
Output('child-container', 'children'),
[Input('hidden-div-trigger', 'children')])
def render_child(_):
if current_user.role <= child1.allowed_role:
return child1.layout()
else:
return ""
- Iāve used the pattern matching in an admin panel to render a user management form which has three possible āactionsā: add (add a new user), edit (edit userās username, email etc but not password), update (update password). Each action would correspond to a different version of the form layout.
Thereās always only one form existing, it can just take several layouts. So all my components have a fixed index (0 here). But using the pattern matching prevents bugs where one of the input doesnāt exist anymore. For example, the username input doesnāt exist for the āupdate passwordā version of the layout.
Looks like this :
add_edit_user_form.py
def layout(action="add", **kwargs):
"""
Same layout function for Add User / Edit User / Update Password with a minor
change depending on the action input
args:
action: "add", "edit", "update" (str)
"""
action = action.lower()
index = 0
rows = list()
if action in ["add", "edit"]:
# Username + email form row
rows.append(username_email_row(index))
# Role + Accessible sites form row
rows.append(role_sites_row(index, role, sites))
if action in ["add", "update"]:
# Create / Update password + Confirm form row
rows.append(password_row(index))
return dbc.Card([
dbc.CardBody([
html.H1("H1"),
html.Br(),
dbc.Form([
dbc.Row(dbc.Col(rows)),
dbc.Button(btn_label, id={"type": f"{action}-user-form-btn", "index": index}),
dbc.Alert(
"",
id="add-edit-user-alert",
is_open=False,
duration=4000,
dismissable=True
),
])
])
])
# And the callback associated
@app.callback(
[
Output("add-edit-user-alert", 'is_open'),
Output("add-edit-user-alert", 'children'),
Output("add-edit-user-alert", 'color'),
Output("single-user-action-store", "data")
],
[
Input({"type": "add-user-form-btn", "index": ALL }, 'n_clicks'),
Input({"type": "edit-user-form-btn", "index": ALL }, 'n_clicks'),
Input({"type": "update-user-form-btn", "index": ALL }, 'n_clicks')
],
[
State({"type": "add-edit-username-input", "index": ALL}, "value"),
State({"type": "add-edit-email-input", "index": ALL}, "value"),
State({"type": "add-edit-role-input", "index": ALL}, "value"),
State({"type": "add-edit-sites-input", "index": ALL}, "value"),
State({"type": "add-edit-password-input", "index": ALL}, "value"),
State({"type": "add-edit-conf-password-input", "index": ALL}, "value"),
])
def add_edit_update_user(add_n_clicks, edit_n_clicks, update_n_clicks, username, email, role, sites, password):
# some more logic
# the only annoying part is since we need to match on index ALL
# (otherwise we would need to use the pattern MATCH on every input, output, state.
# At least using MATCH generated a bug which makes sense as we can create several callbacks for the same output ).
# Because of this, inputs of the functions are array-like objects. I just do this to get them back as I know I always have 1-length arrays
[add_n_clicks] = add_n_clicks
# more logic and return