Multiselect and slider, can't get current value by on_change

What I’m trying to do is to update the table whenever users change category or count. (data from mongodb)

so for multiselect, I can choose categories. for slider, I can select amount of something.

the problem is I’m not sure how to use the values of these widgets on on_change callback.

and the weird thing is, multiselect updates its value on call while slider never update its value in this way.

seems like the codes are running again from top to bottom whenever I change the values like more than one?

and sometimes callback function updates by last value (default=10, change to 5, the value is still 10, after changing the value again, it’s now 5)

st.title("title")
my_table = st.empty()

def update_notice():
    global my_table
    global categories

    my_table.empty()

    filter = {}

    try:  # whenever I change category, it is changed too
        if categories:
            filter = {"$or": [{"category": category} for category in categories]}
    except NameError:
        pass

    sort = list({"id": -1}.items())

    # I tried same method like categories for count, but the count value never changes
    result = tuple(
        client["db"]["collection"].find(filter=filter, sort=sort, limit=count)
    )

    # print(result)

    data = {
        "title": tuple(article["title"] for article in result),
    }

    df = pd.DataFrame(data)
    df.index = [f"{i}th" for i in range(1, len(result) + 1)]
    my_table.table(df)

categories = st.multiselect(
    "label",
    categories,  # like ["a", "b"...]
    [],
    on_change=update_notice(),  # I should pass the function not return value, but the table disappears when I use  lambda: f() or f...
    help="help",
)

count = st.slider(
    "label",
    min_value=1,
    max_value=100,
    value=10,
    on_change=update_notice(),  # I should pass the function not return value, but the table disappears...
    help="help",
)

# print(count), if I print it in here, it prints updated value..

Any better idea to load global widgets in update callback fuctions and get the current values?

I used “st.session_state.my_key” to get the value but wanna know better approach as it updates several times when I click something

@Alfex4936 - Welcome!

Streamlit is designed to run from top to bottom whenever a widget’s state changes. Whatever code is dependent on that state change, will be executed. It’s a bit hard to get to grips with this idea if you’re expecting the code to run only from specific points in your program. This is especially problematic if the logic of your app and the widgets in your script are all in-line at the top level (like many of the tutorial samples!). I find the best approach for more elaborate situations is to wrap the functional aspects of your app in methods, capture all widget state changes at the top level, and then gate the execution of your function methods with a button or checkbox action. This promotes modularity and makes it easier to understand and debug.

So, in your app, collect all category selections, construct the filters, and then based on a button click make the database query.

HTH,
Arvindra

1 Like

ah it runs from top to bottom by the design! sorry I’m new to streamlit so I was trying to have funs with it first!

Thanks for the comment and I’ll try to reimplement my logics! :smiley: