Updates the use of renderDashComponents to use ExternalWrapper when Dash 3 and falls back on dash-extensions for Dash 2#531
Conversation
…endering when no path is given
…c pitfalls with rendering
|
Added the ability to handle async paths by helping to find context paths inside of different components. Here is an example that doesnt work on Dash 2 but works on Dash 3: This stems from the fact that |
| component_name: string; | ||
| }; | ||
| /** Holds the path of the component */ | ||
| componentPath?: any[]; |
There was a problem hiding this comment.
Is it possible to do this without adding a new prop to every component?
There was a problem hiding this comment.
Yeah, it was just a placeholder, its sometimes in there but sometimes not... It's not necessary as far as I can tell.
Co-authored-by: Ann Marie Ward <72614349+AnnMarieW@users.noreply.github.com>
|
Looks good to me! Would be nice though to add a couple of tests, maybe just the two examples you show here plus one or two that already worked. |
…ent to be hooked into the ecosystem
tests the async loading of components for dash-iconify in a non-standard component
|
@alexcjohnson what are your thoughts? I think the fact that the button renders at all is a testament to Dash 2 style running in the stepper test. |
| if i: | ||
| until(lambda: dash_duo.find_element(f'svg.iconify:nth-child({i})').get_attribute('innerHTML') != old_html, timeout=3) | ||
| else: | ||
| until(lambda: dash_duo.find_element(f'svg.iconify:first-child').get_attribute('innerHTML') != old_html, | ||
| timeout=3) No newline at end of file |
There was a problem hiding this comment.
:nth-child is 1-indexed, so should all of this be just :nth-child({i + 1})? Moreover, to be sure this test is really showing that the same element has changed, old_html and new should use the same selector, rather than old_html coming from the enumerate and new getting a new selector, something like:
for i in range(len(icons)):
icon_selector = f'svg.iconify:nth-child({i + 1})'
old_html = dash_duo.find_element(icon_selector).get_attribute('innerHTML')
dash_duo.find_element(f'#test-{i}').click()
until(lambda: dash_duo.find_element(icon_selector).get_attribute('innerHTML') != old_html, timeout=3)There was a problem hiding this comment.
It's not valid. I tried it...
There was a problem hiding this comment.
> document.querySelector('div:first-child')===document.querySelector('div:nth-child(1)')
<- trueThere was a problem hiding this comment.
nth-child(2) isnt found for some reason, though it should be.
There was a problem hiding this comment.
Of course, dash iconify doesnt pass the id to the component...
There was a problem hiding this comment.
@alexcjohnson what about what I just used? I wrapped the icons in divs and used that to target the components.
There was a problem hiding this comment.
Regardless as written this test is looking at the first one in both until calls, which is clearly not what you want. So one way or another we need to get the right elements, and get them in a symmetric way so it’s clear it’s the same element before and after
There was a problem hiding this comment.
Yeah, I updated the test, that's what I was referring to. 🙂
Might be able to do without the time.sleep.
There was a problem hiding this comment.
That's nice and clear 😎
…s with rerenders and added test to address this
|
@alexcjohnson while further verifying the fix for @AnnMarieW original issue (forcing color switching the standard way) the Is the other function in danger of this, or is it different enough that it wont cause this issue? Here is the image of the stores after the initial render in the old way: |
Co-authored-by: Ann Marie Ward <72614349+AnnMarieW@users.noreply.github.com>
|
Thanks @BSd3v 💃 |
|
@BSd3v Need to revisit this PR. After this PR, It's not possible to hit the back button with the stepper as reported in #543 Also, the callbacks for the components as props don't work quite right. In this example, there is an input component in the
dmc=1.1.0 from dash_iconify import DashIconify
import dash_mantine_components as dmc
from dash import Dash, _dash_renderer, Input, Output, State, callback, ctx
_dash_renderer._set_react_version("18.2.0")
app = Dash(external_stylesheets=dmc.styles.ALL)
min_step = 0
max_step = 3
active = 1
def get_icon(icon):
return DashIconify(icon=icon, height=20)
component = dmc.Container(
[
dmc.Stepper(
id="stepper-custom-icons",
active=active,
children=[
dmc.StepperStep(
label="First step",
description="Create an account",
icon=get_icon(icon="material-symbols:account-circle"),
),
dmc.StepperStep(
label="Second step",
description=dmc.Box(["verify email", dmc.TextInput("Go", id="btn")]),
icon=get_icon(icon="ic:outline-email"),
progressIcon=get_icon(icon="ic:outline-email"),
completedIcon=get_icon(
icon="material-symbols:mark-email-read-rounded"
),
children=[dmc.Text("Step 2 content: Verify email", ta="center")],
),
dmc.StepperStep(
label="Final step",
description="Get full access",
icon=get_icon(icon="material-symbols:lock-outline"),
progressIcon=get_icon(icon="material-symbols:lock-outline"),
completedIcon=get_icon(icon="material-symbols:lock-open-outline"),
children=[dmc.Text("Step 3 content: Get full access", ta="center")],
),
dmc.StepperCompleted(
children=[
dmc.Text(
"Completed, click back button to get to previous step",
ta="center",
)
]
),
],
),
dmc.Group(
justify="center",
mt="xl",
children=[
dmc.Button("Back", id="back-custom-icons", variant="default"),
dmc.Button("Next step", id="next-custom-icons"),
],
),
dmc.Box(id="out")
]
)
@callback(
Output("stepper-custom-icons", "active"),
Input("back-custom-icons", "n_clicks"),
Input("next-custom-icons", "n_clicks"),
State("stepper-custom-icons", "active"),
prevent_initial_call=True,
)
def update_with_icons(back, next_, current):
button_id = ctx.triggered_id
step = current if current is not None else active
if button_id == "back-custom-icons":
step = step - 1 if step > min_step else step
else:
step = step + 1 if step < max_step else step
return step
@callback(
Output("out", "children"),
Input("btn", "value")
)
def update(n):
return f"n={n}"
app.layout = dmc.MantineProvider(
component
)
if __name__ == "__main__":
app.run(debug=True)
|


The alteration will allow complex components to be mapped to allow callbacks from components.
eg:
In Dash 2, clicking on the button "rawr" doesnt trigger the callback, however, in Dash 3 you can see that this triggers.