JS callback not updating source data on server-side

Hi
I’m having trouble updating source data when using Bokeh server and a customJS. Using the code below as an example, when I change the spinner value new rows are added to the table. Clicking the green button (after adding some new rows) should print the updated source data to the console, however it only prints {‘x’: [99]} which is the original source data. Any idea why the source data on the server side is not being updated with the source.change.emit() code?

I’m using the latest version of bokeh.

Thanks in advance
Matt

from bokeh.io import curdoc
from bokeh.models import ColumnDataSource, CustomJS, DataTable, TableColumn
from bokeh.models import Spinner, Button, Row
from bokeh.events import ButtonClick

source = ColumnDataSource({'x': [99]})

spinner = Spinner(low=0, high=10, step=1, value=5, width=100)
button = Button(label="print table to console", button_type="success", width=200)

columns = [TableColumn(field="x", title="x")]
table = DataTable(source=source, columns=columns, width=100)

callback_spinner = CustomJS(args=dict(source=source), code="""
    source.data['x'].push(cb_obj.value);
    source.change.emit();
""")

spinner.js_on_change('value', callback_spinner)

def callback_button(event):
    print(table.source.data)

button.on_event(ButtonClick, callback_button)   

curdoc().add_root(Row(spinner, table, button))

I fortunately found an answer and solution here: https://discourse.bokeh.org/t/bokeh-server-is-there-a-way-to-manually-sync-all-models-between-python-and-js/3206/3.

Editing the CustomJS callback to the code below will update the source data on the python side.

callback_spinner = CustomJS(args=dict(source=source), code="""
    var data = source.data;
    data['x'].push(cb_obj.value);
    source.data = data;
    source.change.emit();
""")
1 Like

@gibsms emit() has no bearing on the server. It is a pure-BokehJS eventing mechanism and will not trigger anything to happen on the server.

In general, if you want to trigger a server side foo.on_change("bar", ...) callback, then what has to happen is an actual assignment to foo.bar. A property being assigned to is the thing that the server responds to. In the above code, all that is needed is the source.data = data assignment.

1 Like