Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Missing on_change parameter, key doesn't work as expected #28

Closed
Mi-La opened this issue Feb 2, 2022 · 2 comments
Closed

Missing on_change parameter, key doesn't work as expected #28

Mi-La opened this issue Feb 2, 2022 · 2 comments

Comments

@Mi-La
Copy link

Mi-La commented Feb 2, 2022

This is slightly related to #25.
I want to use the editor to edit a selected file on the filesystem - read at the beginning and write on any change.
With st.text_area I'am able to achieve this by using the on_change callback together with custom key.

But st_ace doesn't support on_change callback and yet it's not able to read content of the key which I provide.

st.session_state["content"] = "This is some content"
st_ace(key="content")

The editor's content remains empty and yet the st.session_state["content"] is not updated on change. However, if I remove the prepared session state and only use the second line, the st.session_state["content"] is updated properly on each change.

Here is my working example with st.text_area:

import streamlit as st
import os

def on_change_callback():
    with open("file.txt", "w") as f:
        f.write(st.session_state["content"])

if not os.path.exists("file.txt"):
    open("file.txt", "w").close()
with open("file.txt", "r") as f:
    st.session_state["content"] = f.read()

    st.text_area("file.txt", key="content", on_change=on_change_callback)

This allows me to edit the file.txt, update it multiple times and always have the correct content on the filesystem (and thus read the file again in another components).

Thanks for any help!

@Mi-La
Copy link
Author

Mi-La commented Feb 2, 2022

I've found a workaround but still I think it would be better if the widget would behave same as the built-in widgets.

import os
import streamlit as st

from streamlit_ace import st_ace

# create file if doesn't exist
if not os.path.exists("file.txt"):
    open("file.txt", "w").close()

with open("file.txt", "r") as f:
    content = f.read()

# the key must be assigned otherwise it's probably generated from content again an again on each re-run
# and thus the old content is still reloaded from the file
new_content = st_ace(content, key="content")

# after changing the editor's content, whole script will be executed from the top
# the content set to the st_ace won't be used since the key "content" exists in st.session_state
# and to accept a change on re-run the key must be changed
if new_content != content:
    with open("file.txt", "w") as f:
        f.write(new_content)

Note that it doesn't work with st.text_area, instead we must set st.session_state["content"] before the st.text_area is created:

st.session_state["content"] = content
new_content = st.text_area("caption", key="content") # do NOT touch the value here

Also note that if you want to change the editor content on some re-run (e.g. when choosing different file), the key must be changed or removed from st.session_state.

@okld
Copy link
Owner

okld commented Feb 4, 2022

Hello @Mi-La,

Unfortunately it is not an issue of this component, but of streamlit custom components in general. They don't support callbacks or session state binding for now.

This feature was already requested on streamlit repository : streamlit/streamlit#3977

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants