# Problem with client-side js function

**URL:** <https://community.plotly.com/t/problem-with-client-side-js-function/72768>\
**Category:** plotly.js\
**Tags:** question\
**Created:** [February 16, 2023, 10:23am UTC](https://community.plotly.com/t/problem-with-client-side-js-function/72768 "2023-02-16T10:23:19Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Garazh\_gazel](https://avatars.discourse-cdn.com/v4/letter/g/a9a28c/32.png) [@Garazh\_gazel](https://community.plotly.com/u/Garazh_gazel)\
**Post date:** [February 16, 2023, 10:23am UTC](https://community.plotly.com/t/problem-with-client-side-js-function/72768/1 "2023-02-16T10:23:19Z")

</div>

Good day everyone!  
I try to rewrite my original callback that updates graph components through time (and it works just fine) to the client-side callback. I don’t really know JS, so I’ve just tried to write my JS code regarding similar examples. The problem is that after the first initial update - my graph becomes completely cleared and such an error appears:

 ![изображение](https://us1.discourse-cdn.com/flex024/uploads/plot/original/3X/f/c/fc9441fa5f14825b5208c85b0fafd4992ca548b7.png)

I suggest, maybe I’ve made some kind of mistakes in my js file, but I don’t really see them… I would be very happy if you can spot where am I wrong!

My original Python callback

```auto
@callback(
    Output("heatmap", "figure"),
    Input("interval-graph-update", "n_intervals"),
    State("x_store", "data"),
    State("y_store", "data"),
    State("z_store", "data"),
    State("heatmap", "figure"),
    State("y_scatter", "data"),
    State("yz_scatter", "data"),
    State("x_scatter", "data"),
    State("xz_scatter", "data"),
    Input("x_click", "data"),
    Input("y_click", "data"),
    Input("heatmap", "clickData"),
    State("line-switches", "on"),
)
def update_graph(
    i,
    x,
    y,
    z,
    fig,
    y_scatter,
    yz_scatter,
    x_scatter,
    xz_scatter,
    x_click,
    y_click,
    click,
    line_switch,
):
    triggered_id = ctx.triggered_id
    if i == 0:
        raise PreventUpdate

    if x_click is None:
        fig["layout"]["shapes"][0].update({"visible": False})
        fig["layout"]["shapes"][1].update({"visible": False})
    else:
        fig["layout"]["shapes"][0].update({"visible": line_switch})
        fig["layout"]["shapes"][1].update({"visible": line_switch})

    if triggered_id == "interval-graph-update":
        fig["data"][0].update({"x": x, "y": y, "z": z})
        return fig
    elif triggered_id == "heatmap":
        fig["data"][1].update({"x": yz_scatter, "y": y_scatter})
        fig["data"][2].update({"x": x_scatter, "y": xz_scatter})
        fig["layout"]["shapes"][0].update(
            {
                "x0": x_click,
                "x1": x_click,
            }
        )
        fig["layout"]["shapes"][1].update({"y0": y_click, "y1": y_click})
        return fig

```

My JS script in the /assets folder

```auto
window.dash_clientside = Object.assign({}, window.dash_clientside, {
  clientside: {
    refresh_graph: function (
      i,
      x_click,
      y_click,
      click,
      x,
      y,
      z,
      fig,
      y_scatter,
      yz_scatter,
      x_scatter,
      xz_scatter,
      line_switch
    ) {
      const triggered_id = dash_clientside.callback_context.triggered.map(
        (t) => t.prop_id
      );

      if (x_click === null) {
        fig["layout"]["shapes"][0]["visible"] = false;
        fig["layout"]["shapes"][1]["visible"] = false;
      } else {
        fig["layout"]["shapes"][0]["visible"] = line_switch;
        fig["layout"]["shapes"][1]["visible"] = line_switch;
      }
      if (triggered_id === "interval-graph-update") {
        fig["data"][0]["x"] = x;
        fig["data"][0]["y"] = y;
        fig["data"][0]["z"] = z;
        return fig;
      } else if (triggered_id === "heatmap") {
        fig["data"][1]["x"] = yz_scatter;
        fig["data"][1]["y"] = y_scatter;

        fig["data"][2]["x"] = x_scatter;
        fig["data"][2]["y"] = xz_scatter;

        fig["layout"]["shapes"][0]["x0"] = x_click;
        fig["layout"]["shapes"][0]["x1"] = x_click;

        fig["layout"]["shapes"][1]["y0"] = y_click;
        fig["layout"]["shapes"][1]["y1"] = y_click;
        return fig;
      }
    },
  },
});

```

Python implementation of this code

```auto
clientside_callback(
    ClientsideFunction(namespace="clientside", function_name="refresh_graph"),
    Output("heatmap", "figure"),
    Input("interval-graph-update", "n_intervals"),
    Input("x_click", "data"),
    Input("y_click", "data"),
    Input("heatmap", "clickData"),
    State("x_store", "data"),
    State("y_store", "data"),
    State("z_store", "data"),
    State("heatmap", "figure"),
    State("y_scatter", "data"),
    State("yz_scatter", "data"),
    State("x_scatter", "data"),
    State("xz_scatter", "data"),
    State("line-switches", "on"),
)

```

---

<div class="post-metadata">

**Author:** ![AIMPED](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/aimped/32/21758_2.png) [@AIMPED](https://community.plotly.com/u/AIMPED)\
**Post date:** [February 16, 2023, 10:45am UTC](https://community.plotly.com/t/problem-with-client-side-js-function/72768/2 "2023-02-16T10:45:28Z")

</div>

In your Python callback you have this

> [@Garazh\_gazel](#):
>
> ```auto
> triggered_id = ctx.triggered_id
> if i == 0:
> raise PreventUpdate
> 
> ```

whereas you do not have something equivalent in JS, maybe this is intentionally but worth mentioning.

If you don’t want the callback to be triggered at startup, you could add `prevent_initial_call=True`

---

<div class="post-metadata">

**Author:** ![Garazh\_gazel](https://avatars.discourse-cdn.com/v4/letter/g/a9a28c/32.png) [@Garazh\_gazel](https://community.plotly.com/u/Garazh_gazel)\
**Post date:** [February 16, 2023, 12:15pm UTC](https://community.plotly.com/t/problem-with-client-side-js-function/72768/3 "2023-02-16T12:15:02Z")

</div>

I think, that the problem is in the way how I change values in the dictionary. For instance, if I comment out all except refreshing values with the Interval component, it will not work too (the graph would stay constant through time). I’m confused about how I update my values in the dictionary, maybe I do it incorrectly in JS?

> [@Garazh\_gazel](#):
>
> ```auto
> fig["data"][0]["x"] = x;
> fig["data"][0]["y"] = y;
> fig["data"][0]["z"] = z;
> 
> ```

---

<div class="post-metadata">

**Author:** ![AIMPED](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/aimped/32/21758_2.png) [@AIMPED](https://community.plotly.com/u/AIMPED)\
**Post date:** [February 16, 2023, 12:35pm UTC](https://community.plotly.com/t/problem-with-client-side-js-function/72768/4 "2023-02-16T12:35:42Z")

</div>

Try something like this from [this topic](https://community.plotly.com/t/coroplethmapbox-update-z-only/72575/2) (the newFig line)

```javascript
app.clientside_callback(
    """
    function(drop_val, fig, init_val) {
        newFig = JSON.parse(JSON.stringify(fig))
        if (drop_val == 1.0) {
            newFig['data'][0]['z'] = init_val
        } else {
            newFig['data'][0]['z'] = init_val.map(element => element * drop_val)
        }
        return newFig
    }
    """,
    Output('graph', 'figure'),
    Input('drop', 'value'),
    State('graph', 'figure'),
    State('store', 'data'),
    prevent_initial_call=True
)

```

---

<div class="post-metadata">

**Author:** ![Garazh\_gazel](https://avatars.discourse-cdn.com/v4/letter/g/a9a28c/32.png) [@Garazh\_gazel](https://community.plotly.com/u/Garazh_gazel)\
**Post date:** [February 16, 2023, 1:14pm UTC](https://community.plotly.com/t/problem-with-client-side-js-function/72768/5 "2023-02-16T13:14:10Z")

</div>

No, unfortunately, it doesn’t work ☹
