Finding dictionary Ids in the Dom

Hello,

I am using a dash community component, dash tours (GitHub - matthijsramlab/dash_tour_component: Tour component for Dash).
It is really useful but I came across one issue.

For my apps I use most times a dictionary as id. This component has issues to finding the Id in the Dom. I was thinking, that you had to solve this issue during the development process, since we provide dictionaries and Dash is working with them under the hood. Is there a way to process the dict on the Python side to make the example work without more significant changes? I tried to use json.dumps, but that did not help.

Here is a MRE for this case.

import dash_tour_component
import dash
import json
from dash.dependencies import Input, Output
import dash_html_components as html

app = dash.Dash(__name__)


app.layout = html.Div(
    [
        dash_tour_component.DashTour(
            steps=[
                {
                    "selector": f"[id={json.dumps({'type': 'div', 'index': '1'})}]",
                    "content": "This is my first step",
                    # 'position': "center"
                },
                {
                    "selector": f"[id={json.dumps({'type': 'div', 'index': '2'})}]",
                    "content": "This is my second Step",
                },
            ],
            isOpen=False,
            id="tour_component",
        ),
        html.Button("Open Tour", id="open_tour_button"),
        html.Div(
            "Test 1", id={"type": "div", "index": "1"}, style={"text-align": "center"}
        ),
        html.Div(style={"height": "400px"}),
        html.Div(
            "Test 2", id={"type": "div", "index": "2"}, style={"text-align": "center"}
        ),
    ]
)


@app.callback(
    Output("tour_component", "isOpen"),
    [Input("open_tour_button", "n_clicks")],
    prevent_initial_call=True,
)
def open_tour_component(value):
    return True


if __name__ == "__main__":
    app.run_server(debug=True)

Thank you

Hello @simon-u,

You are looking for this function:


function stringifyId(id) {
    if (typeof id !== 'object') {
        return id;
    }
    const stringifyVal = (v) => (v && v.wild) || JSON.stringify(v);
    const parts = Object.keys(id)
        .sort()
        .map((k) => JSON.stringify(k) + ':' + stringifyVal(id[k]));
    return '{' + parts.join(',') + '}';
}

Using this with the id will give you the string to use with document.getElementById

2 Likes

Hello @jinnyzor ,

Thank you, thats what I needed. I remade it in Python, so I won’t have to modify the package. Here is the Python version, just in case someone else might need it.

def stringify_id(id):
    if not isinstance(id, dict):
        return id

    def stringify_val(v):
        return v.get("wild") if isinstance(v, dict) and v.get("wild") else json.dumps(v)

    parts = [json.dumps(k) + ":" + stringify_val(id[k]) for k in sorted(id)]
    return "{" + ",".join(parts) + "}"

With this it worked perfectly fine.

1 Like