Hello @alistair.welch,
Check this out for the editor:
dagfuncs.DCC_Dropdown = class {
// gets called once before the renderer is used
init(params) {
// create the cell
this.params = params;
this.ref = React.createRef();
// function for when Dash is trying to send props back to the component / server
var setProps = (props) => {
if (props.value) {
// updates the value of the editor
this.value = props.value;
// re-enables keyboard event
delete params.colDef.suppressKeyboardEvent
// tells the grid to stop editing the cell
params.api.stopEditing();
// sets focus back to the grid's previously active cell
this.prevFocus.focus();
}
}
this.eInput = document.createElement('div')
// renders component into the editor element
ReactDOM.render(React.createElement(window.dash_core_components.Dropdown, {
options: params.values, value: params.value, ref: this.ref, setProps, style: {width: params.column.actualWidth},
}), this.eInput)
// allows focus event
this.eInput.tabIndex = "0"
// sets editor value to the value from the cell
this.value = params.value;
}
// gets called once when grid ready to insert the element
getGui() {
return this.eInput;
}
focusChild() {
// enter keyboard event
const keyboardEvent = new KeyboardEvent('keydown', {
code: 'Enter',
key: 'Enter',
charCode: 13,
keyCode: 13,
view: window,
bubbles: true
});
// needed to delay and allow the component to render
setTimeout(() => {
var inp = this.eInput.getElementsByClassName('Select-control')[0]
inp.tabIndex = '1'
inp.focus()
// disables keyboard event
this.params.colDef.suppressKeyboardEvent = (params) => {
const gridShouldDoNothing = params.editing
return gridShouldDoNothing;
}
// shows dropdown options
inp.dispatchEvent(keyboardEvent)
}, 100)
}
// focus and select can be done after the gui is attached
afterGuiAttached() {
// stores the active cell
this.prevFocus = document.activeElement
// adds event listener to trigger event to go into dash component
this.eInput.addEventListener('focus', this.focusChild())
// triggers focus event
this.eInput.focus();
}
// returns the new value after editing
getValue() {
return this.value;
}
// any cleanup we need to be done here
destroy() {
// sets focus back to the grid's previously active cell
this.prevFocus.focus();
}
}
It will automatically open up to show all the available options. I am sure there is some customization to how you want to use it.
app.py:
"""
Conditional Select options
"""
import dash_ag_grid as dag
from dash import Dash, html, dcc
app = Dash(__name__)
columnDefs = [
{
"field": "country",
"editable": False,
},
{
"headerName": "Select Editor",
"field": "city",
"cellEditor": {"function": "DCC_Dropdown"},
"cellEditorParams": {"function": "dynamicOptions(params)"},
"cellEditorPopup": True,
"cellEditorPopupPosition": 'under',
},
]
rowData = [
{"country": "United States", "city": "Boston"},
{"country": "Canada", "city": "Montreal"},
{"country": "Canada", "city": "Vancouver"},
]
app.layout = html.Div(
[
dcc.Markdown(
"This grid has dynamic options for city based on the country. Try editing the cities."
),
dag.AgGrid(
id="cell-editor-grid",
columnDefs=columnDefs,
rowData=rowData,
columnSize="sizeToFit",
defaultColDef={"editable": True},
dashGridOptions={'suppressRowTransform': True}
),
],
style={"margin": 20},
)
if __name__ == "__main__":
app.run_server(debug=True)
functions:
var dagfuncs = window.dashAgGridFunctions = window.dashAgGridFunctions || {};
dagfuncs.dynamicOptions = function(params) {
const selectedCountry = params.data.country;
if (selectedCountry === 'United States') {
return {
values: ['Boston', 'Chicago', 'San Francisco'],
};
} else {
return {
values: ['Montreal', 'Vancouver', 'Calgary']
};
}
}
dagfuncs.DCC_Dropdown = class {
// gets called once before the renderer is used
init(params) {
// create the cell
this.params = params;
this.ref = React.createRef();
// function for when Dash is trying to send props back to the component / server
var setProps = (props) => {
if (props.value) {
// updates the value of the editor
this.value = props.value;
// re-enables keyboard event
delete params.colDef.suppressKeyboardEvent
// tells the grid to stop editing the cell
params.api.stopEditing();
// sets focus back to the grid's previously active cell
this.prevFocus.focus();
}
}
this.eInput = document.createElement('div')
// renders component into the editor element
ReactDOM.render(React.createElement(window.dash_core_components.Dropdown, {
options: params.values, value: params.value, ref: this.ref, setProps, style: {width: params.column.actualWidth},
}), this.eInput)
// allows focus event
this.eInput.tabIndex = "0"
// sets editor value to the value from the cell
this.value = params.value;
}
// gets called once when grid ready to insert the element
getGui() {
return this.eInput;
}
focusChild() {
// enter keyboard event
const keyboardEvent = new KeyboardEvent('keydown', {
code: 'Enter',
key: 'Enter',
charCode: 13,
keyCode: 13,
view: window,
bubbles: true
});
// needed to delay and allow the component to render
setTimeout(() => {
var inp = this.eInput.getElementsByClassName('Select-control')[0]
inp.tabIndex = '1'
inp.focus()
// disables keyboard event
this.params.colDef.suppressKeyboardEvent = (params) => {
const gridShouldDoNothing = params.editing
return gridShouldDoNothing;
}
// shows dropdown options
inp.dispatchEvent(keyboardEvent)
}, 100)
}
// focus and select can be done after the gui is attached
afterGuiAttached() {
// stores the active cell
this.prevFocus = document.activeElement
// adds event listener to trigger event to go into dash component
this.eInput.addEventListener('focus', this.focusChild())
// triggers focus event
this.eInput.focus();
}
// returns the new value after editing
getValue() {
return this.value;
}
// any cleanup we need to be done here
destroy() {
// sets focus back to the grid's previously active cell
this.prevFocus.focus();
}
}