PablocFonseca / streamlit-aggrid

Implementation of Ag-Grid component for Streamlit
https://pypi.org/project/streamlit-aggrid/
MIT License
1.05k stars 199 forks source link

Version 0.3.4 seems to have broken the clickable hyperlinks hack. #198

Open vovavili opened 1 year ago

vovavili commented 1 year ago

It seems that the trick to make links clickable doesn't work anymore in 0.3.4.

The code:

for col in links:
    js_hyperlinks = JsCode(
        """
        function(cell) {
            return `<a href="${cell.value}" target="_blank">Click me!</a>`
        }
        """
    )
    gb.configure_column(col, cellRenderer=js_hyperlinks)

On 0.3.3 - the tab of URLs is populated with 'Click me!' On 0.3.4 - <a href="link goes here" target="_blank">Click me!</a>

PablocFonseca commented 1 year ago

I had to upgrade aggrid-react. And pure html responses won't work anymore. You'll need to use a cellRenderer.

More info:

https://github.com/ag-grid/ag-grid/issues/5427

VovaViliLox commented 1 year ago

Got it. I guess that's unavoidable, so if change can be noted in the documentation the issue can be closed for now.

mkleinbort-ic commented 1 year ago

I think to get JSX to work I need to import react somewhere - how have you solved it? Otherwise I get syntax errors.

To be explicit:

js_hyperlinks = JsCode(
        """
        function(cell) {
            return <a href={cell.value} target="_blank">Click me!</a>;
        }
        """
    )

does not work for me - I get a syntax error telling me "unexpected token < ".

ecal99 commented 1 year ago

I'm running into the same problem, and I am sure many others will as well. Is there an "easy" way to turn a hyperlink as a string into something AG Grid will allow to be rendered as a hyperlink?

Thanks! Ed

fplanque commented 1 year ago

I had to upgrade aggrid-react. And pure html responses won't work anymore. You'll need to use a cellRenderer.

More info:

ag-grid/ag-grid#5427

In the original post, he is using cellRenderer=js_hyperlinks

How is that not using a cellRenderer?

Your "more info" link is not really helpful for Python programers :'(

How do we return "JSX" in Python?

Do you know how to fix this? Can you explicitly say what is wrong with the code and how to fix it?

Thanks.

kbarton1212 commented 1 year ago

I found my way to this thread as I was researching any leads on this same exact issue. Any ideas would be greatly appreciated.

salman-moh commented 1 year ago

Got it. I guess that's unavoidable, so if change can be noted in the documentation the issue can be closed for now.

@vovavili @VovaViliLox How did you fix it? Can you please show the code changes?

StephenCooper commented 1 year ago

This is a minimal cell renderer that you should be able to use instead of providing a function to the cellRenderer property.

class BoldCellRenderer {
  init(params) {
    this.eGui = document.createElement('span');
    this.eGui.innerHTML = '<b>'+params.value+'</b>';
  }
  getGui() {
    return this.eGui;
  }
}

https://plnkr.co/edit/vnQTtGG9k4oMR1Fm?open=index.jsx&preview

matkozak commented 1 year ago

This works, thank you.

For reference, my code looks like this:

gb = GridOptionsBuilder()
gb.configure_column(
    "URL", "URL",
    cellRenderer=JsCode("""
        class UrlCellRenderer {
          init(params) {
            this.eGui = document.createElement('a');
            this.eGui.innerText = 'SomeText';
            this.eGui.setAttribute('href', params.value);
            this.eGui.setAttribute('style', "text-decoration:none");
            this.eGui.setAttribute('target', "_blank");
          }
          getGui() {
            return this.eGui;
          }
        }
    """)
)
yoeldk commented 1 year ago

@matkozak Worked for me too, thanks for that! Is there a way to somehow use python variables within the JSCode scope? The use case is that I have a table where one of the columns is a filename, but the link should direct to the full path of that filename which is defined elsewhere in the Python code.

gudbrand3 commented 8 months ago

@yoeldk I took the awesome solution from @StephenCooper and @matkozak <3 and adjusted it to take some variables

  def link(linkText,url,linkColor):
      return JsCode(f"""
          class UrlCellRenderer {{
            init(params) {{
              let linkText = "{linkText}";
              let url = "{url}";
              let linkColor = "{linkColor}";
              url = !url || url.length === 0 ? params.value : url;      
              linkText = !linkText || linkText.length === 0 ? params.value : linkText;      

              this.eGui = document.createElement('a');
              this.eGui.innerText = linkText;
              this.eGui.setAttribute('href', url);
              this.eGui.setAttribute('style', "text-decoration:none");
              this.eGui.setAttribute('target', "_blank");
              this.eGui.setAttribute('style', `color:{linkColor};`);
            }}
            getGui() {{
              return this.eGui;
            }}
          }}
      """)
arkp1612 commented 2 months ago

I get the error AttributeError: module 'streamlit.components.v1' has no attribute 'components' when I try the above code. Using streamlit-aggrid version 1.0.5 and streamlit version 1.36.0

Code:

def link(linkText,url,linkColor):
      return JsCode(f"""
          class UrlCellRenderer {{
            init(params) {{
              let linkText = "{linkText}";
              let url = "{url}";
              let linkColor = "{linkColor}";
              url = !url || url.length === 0 ? params.value : url;      
              linkText = !linkText || linkText.length === 0 ? params.value : linkText;      

              this.eGui = document.createElement('a');
              this.eGui.innerText = linkText;
              this.eGui.setAttribute('href', url);
              this.eGui.setAttribute('style', "text-decoration:none");
              this.eGui.setAttribute('target', "_blank");
              this.eGui.setAttribute('style', `color:{linkColor};`);
            }}
            getGui() {{
              return this.eGui;
            }}
          }}
      """)
# Create GridOptionsBuilder instance
gb = GridOptionsBuilder.from_dataframe(df)
gb.configure_default_column(editable=False, filter=True)
gb.configure_pagination(paginationAutoPageSize=False, paginationPageSize=12)
gb.configure_grid_options(domLayout='normal')
gb.configure_column("document_url",cellRenderer = link)

# Build grid options
grid_options = gb.build()

# Display the grid with custom options
st.title('AgGrid with HTML Content')
AgGrid(df, gridOptions=grid_options, enable_enterprise_modules=True, update_mode=GridUpdateMode.GRID_CHANGED)
arkp1612 commented 2 months ago

Updating response = AgGrid(df,gridOptions=gb.build(),enable_enterprise_modules=True,update_mode= GridUpdateMode.GRID_CHANGED,allow_unsafe_jscode=True) makes it work