I was able to achieve this using a combination of a few hacky bits of code - Very open to suggestions for improvements.
First, use the streamlit html component to embed an iframe at the bottom of your app which contains some custom JS Code to ‘un-sandbox’ any AgGrid iframes present in your app. JS Code below. I found the call to .reload() the iframe was necessary for the updated attributes to ‘take hold’.
from streamlit.components.v1 import html
from st_aggrid import AgGrid, JsCode, GridOptionsBuilder as GOB
iframe_jscode = '''
var grid_frames = parent.document.querySelectorAll("iframe[title='st_aggrid.agGrid']")
for (var i = 0; i < grid_frames.length; i++) {
grid_frames[i].setAttribute("sandbox", "allow-forms allow-modals allow-popups allow-popups-to-escape-sandbox allow-same-origin allow-scripts allow-downloads allow-top-navigation-by-user-activation allow-top-navigation");
grid_frames[i].contentWindow.location.reload();
}
'''
After that, the code you posted above will work with target = “_top” however clicking the link in AgGrid triggers a reload of your browser tab so although the second page loads, it doesnt have access to the state from the first page.
I found you could sort of get around that by constructing the link in your cellRenderer function with query parameters based on the data in each row (accessible through params.node.data in the func), or if maintaining session state is a must then I found a solution using an onCellClicked callback as follows.
The callback adds query parameters to the url of your app based on the data in the row of the clicked cell and then searches through the links in the sidebar to find the one which points to your desired page. When it does, it simulates a click event on the sidebar link using .click() which changes the page without losing the session state.
I don’t think the ‘back’ button works properly to go back a page with this solution which I think is to do with my use of history.pushState(), but hopefully this is helpful
cell_click_callback = JsCode('''
function(event) {
var mainApp = window.parent.document;
var arrSidebarLinks = mainApp.querySelectorAll("div[data-testid='stSidebarNav'] li a");
const url = new URL(window.parent.window.location.href);
url.searchParams.set('row', event.node.data.Flavor);
for (var i = 0; i < arrSidebarLinks.length; i++) {
var currLink = arrSidebarLinks[i];
var currName = currLink.querySelector("span").innerHTML;
if (currName == 'second page') {
window.parent.window.history.pushState(null, '', url);
currLink.click()
};
};
};
''')
data = pd.DataFrame({'Flavor' : ['Vanilla', 'Chocolate', 'Strawberry', 'Mint Chocolate'], 'Select Favorite' : 'me!', 'me!', 'me!', 'me!']})
go = GOB.from_dataframe(data)
go.configure_column('Select Favorite', onCellClicked=cell_click_callback)
go = go.build()
response = AgGrid(dataframe=data, gridOptions=go, allow_unsafe_jscode=True, theme='dark', fit_columns_on_grid_load=True)
html(f"<script language=\"javascript\">{iframe_jscode}</script>")