Stop page rerun from multiselect via onchange event

I have this simple code below, which consists of two multi-select controls. However, even only one control changes, the other control’s callback method is also invoked, which seems a bug to me.
Any idea?

import streamlit as st
def multiselect_callback(val):
    print(val)

def multiselect_callback2(val):
    print(val)

options = st.multiselect(
    "What are your favorite colors",
    ["Green", "Yellow", "Red", "Blue"],
    ["Yellow"],
    on_change=multiselect_callback("get"),
    key= "select1"
)

st.write("You selected:", options)


options2 = st.multiselect(
    "colors",
    ["1", "2", "3", "4"],
    ["2"],
    on_change=multiselect_callback2("get2"),
    key= "select2"
)

st.write("You selected2:", options2)

Hello,
The issue lies in how you are invoking the on_change callback function within the st.multiselect. When you use on_change=multiselect_callback("get"), you are calling the function immediately and passing its return value (in this case, None, since print(val) does not return anything) to the on_change parameter. This causes both callbacks to be triggered prematurely and not behave as intended.

        options = st.multiselect(
            "What are your favorite colors",
            ["Green", "Yellow", "Red", "Blue"],
            ["Yellow"],
            on_change=multiselect_callback, args=("first",),
            key="select1"
        )

        st.write("You selected:", options)

        options2 = st.multiselect(
            "colors",
            ["1", "2", "3", "4"],
            ["2"],
            on_change=multiselect_callback2, args=("second",),
            key="select2"
        )

You should see like a function (will call directly the function)

this_function('thisisatest')

but not this :

lambda: this_function('thisisatest')

creates an anonymous function that does not call this_function immediately.

Callbacks are supposed to be function (actually callables). multiselect_callback("get") is not a function but None You can check it by adding this to your code:

assert multiselect_callback("get") is None

The funcion is called not when the widget changes but when the widget is created.

You probably want

on_change=multiselect_callback,
kwargs={"val": "get"},

instead.

1 Like

Thanks, but it should be args=[“first”]

I will mark it as an answer.

Hi,
Thanks!
This is also correct, but @Faltawer provided the answer earlier. I cannot mark two answers.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.