okld / streamlit-elements

Create a draggable and resizable dashboard in Streamlit, featuring Material UI widgets, Monaco editor (Visual Studio Code), Nivo charts, and more!
MIT License
734 stars 82 forks source link

onChange event not working on Streamlit 1.34 #35

Open dectoplate opened 6 months ago

dectoplate commented 6 months ago

onChange event is not working after Streamlit 1.34 release.

vikvikvr commented 6 months ago

@okld is this repo still mantained?

we love your library and use it extensively throughout our projects Unfortunately this issue prevents us from upgrading Streamlit 😣

Thanks! 😀

shuZro commented 5 months ago

Bump

moonbug-car commented 5 months ago

Bump x2 @okld it would be great if you could update it, Thank You.

KhabarovaNina commented 4 months ago

Bump @okld please!

KhabarovaNina commented 4 months ago

Hello!

This issue is related to the refactoring of streamlit in using custom components.

It is possible to restore the previous functionality by replacing in the file /streamlit_elements/core/callback.py: # from streamlit.components.v1 import components - OLD from streamlit.components.v1 import custom_component as components - NEW

However, I hope the streamlit developers will fix this issue in future releases.

vikvikvr commented 4 months ago

Thanks @KhabarovaNina a lot!

I made a small script to patch it automatically (needed for our Docker builds), hope it helps other people :)

import os
import streamlit_elements
import re

def patch_streamlit_elements():

    # issue: https://github.com/okld/streamlit-elements/issues/35
    relative_file_path = 'core/callback.py'
    library_root = list(streamlit_elements.__path__)[0]
    file_path = os.path.join(library_root, relative_file_path)

    # Read broken file
    with open(file_path, 'r') as file:
        lines = file.readlines()

    broken_import = 'from streamlit.components.v1 import components'
    fixed_import = 'from streamlit.components.v1 import custom_component as components\n'

    # Fix broken import line
    for index, line in enumerate(lines):

        if re.match(broken_import, line):
            print(f'Replaced broken import in {file_path}')
            lines[index] = fixed_import

    # Update broken file with fix
    with open(file_path, 'w') as file:
        file.writelines(lines)

if __name__ == "__main__":
    patch_streamlit_elements()
Yeqishen commented 1 month ago

vikvikvr

This is awesome, vikvikvr, thank you very much, the script still works great! 👍

KhabarovaNina commented 2 weeks ago

Hello everyone! Problem with onChange event is back in Streamlit 1.40.0 and fix import is not enough now :( If somebody fix it in new version - please, write solution here

bonajoy commented 1 week ago

This code works in Streamlit 1.40.0.

def patch_modules_streamlit_elements(file: str, old_line: str, new_line: str):
    import streamlit_elements
    import os

    relative_file_path = "core/callback.py"
    library_root = list(streamlit_elements.__path__)[0]
    file_path = os.path.join(library_root, relative_file_path)

    with open(file_path, "r") as file:
        lines = file.readlines()

    is_changed = False
    for index, line in enumerate(lines):
        if old_line in line:
            print(f"Replacing line {index + 1} in {file_path}")
            lines[index] = line.replace(old_line, new_line)
            is_changed = True

    if is_changed:
        with open(file_path, "w") as file:
            file.writelines(lines)
        import importlib
        importlib.reload(streamlit_elements)

    return True

def patch_streamlit_elements():
    # fix 1.34.0
    patch_modules_streamlit_elements(
        "core/callback.py",
        "from streamlit.components.v1 import components",
        "from streamlit.components.v1 import custom_component as components\n",
    )

    #fix 1.40.0
    patch_modules_streamlit_elements(
        "core/callback.py",
        '        user_key = kwargs.get("user_key", None)\n',
        """
        try:
            user_key = None
            new_callback_data = kwargs[
                "ctx"
            ].session_state._state._new_session_state.get(
                "streamlit_elements.core.frame.elements_frame", None
            )
            if new_callback_data is not None:
                user_key = new_callback_data._key
        except:
            user_key = None
        """.rstrip()
        + "\n",
    )

if __name__ == "__main__":
    patch_streamlit_elements()
KhabarovaNina commented 1 week ago

@bonajoy Thank you so much!

TheUkrainian1991 commented 1 week ago

This code works in Streamlit 1.40.0.

def patch_modules_streamlit_elements(file: str, old_line: str, new_line: str):
    import streamlit_elements
    import os

    relative_file_path = "core/callback.py"
    library_root = list(streamlit_elements.__path__)[0]
    file_path = os.path.join(library_root, relative_file_path)

    with open(file_path, "r") as file:
        lines = file.readlines()

    is_changed = False
    for index, line in enumerate(lines):
        if old_line in line:
            print(f"Replacing line {index + 1} in {file_path}")
            lines[index] = line.replace(old_line, new_line)
            is_changed = True

    if is_changed:
        with open(file_path, "w") as file:
            file.writelines(lines)
        import importlib
        importlib.reload(streamlit_elements)

    return True

def patch_streamlit_elements():
    # fix 1.34.0
    patch_modules_streamlit_elements(
        "core/callback.py",
        "from streamlit.components.v1 import components",
        "from streamlit.components.v1 import custom_component as components\n",
    )

    #fix 1.40.0
    patch_modules_streamlit_elements(
        "core/callback.py",
        '        user_key = kwargs.get("user_key", None)\n',
        """
        try:
            user_key = None
            new_callback_data = kwargs[
                "ctx"
            ].session_state._state._new_session_state.get(
                "streamlit_elements.core.frame.elements_frame", None
            )
            if new_callback_data is not None:
                user_key = new_callback_data._key
        except:
            user_key = None
        """.rstrip()
        + "\n",
    )

if __name__ == "__main__":
    patch_streamlit_elements()

You sir are a LEGEND. Unfortunately this isnt working for me. Running python 3.11.0 and streamlit 1.40.0. This is what the callback file looks like for me and it isn't working.

image