Hey guys! How would you add dbc.Switch() to a DataTable so that a boolean column is visualized by switches instead of “true” or “false”? Is that even possible? Thanks!
At this time, you can’t put components in DataTable cells. A workaround is to use an HTML Table.
Hi @AnnMarieW is there any change regarding this topic? Thanks
Hey @dashamateur !
Consider switching to ag-grid.
Hey @AIMPED thanks for the reply! I tried avoiding js but i guess it will be necessary
Hi @dashamateur
In the next major release of Dash AG Grid, the boolean values will automatically render as check boxes. No custom components required
Until then, you can see examples of how to add components to cells in the docs. If you would like a dbc.Switch instead of a checkbox, you can find an example here:
There shouldn’t be too much JavaScript coding involved if you copy one of the examples, but if you have any questions, feel free to ask for help here
Hi @AnnMarieW and thanks for the reply! My problem is a bit more specific as I’m trying to render a substring inside a cell. I am currently doing this with an if sentence:
// INPUT
dagcomponentfuncs.DBC_Input = function (props) {
const { type, value, placeholder } = props;
let string = props.data.check;
if (string.includes('INPUT')) {
// Replace 'INPUT' with dbc.Input component
string = string.replace(
'INPUT',
React.createElement(
window.dash_bootstrap_components.Input,
{
type: type || 'text',
value: value || '',
placeholder: placeholder || '0,00',
}
)
);
}
return string
};
which finds the substring INPUT and renders it but it returns [object Object]. I am still trying to find a remedy for that. Do you have any suggestions on how to render specific substrings into dbc components? Thanks alot!
EDIT:
Problem was in the types of data i was returning because it converted dbc.Input to string. After some struggle i managed to get it to work as wanted (code below). I am open to cleaner solutions Also, how would you capture updated grid to include the user inputs? I have created a button that reads the data: State(“ag-grid”, “rowData”), but it doesn’t include rendered cells. Is there a workaround to “scrape” the grid? Thanks!
// INPUT
dagcomponentfuncs.DBC_Input = function (props) {
const { type,handleInputChange,placeholder } = props;
let parts = props.data.check.split('INPUT');
let elements = [];
// Iterate over parts and add both strings and React elements to the array
parts.forEach((part, index) => {
elements.push(part);
if (index < parts.length - 1) {
// Insert the React element
elements.push(
React.createElement(
window.dash_bootstrap_components.Input,
{
type: type || 'text',
onChange: handleInputChange,
placeholder: placeholder || '0,00',
style: {
display: "inline-block",
width: "20%",
},
}
)
);
}
});
return React.createElement('div', null, elements);
};
For anyone with this problem: rendering part of ag-grid cell this is how i solved it for myself. I wanted to replace part of string in a cell with dbc.Input and keep the components functionality so I would be able to use the users entered data. I achived this with this function in a .js file:
dagcomponentfuncs.DBC_Input_With_String = function (props) {
const { setData, handleInputChange, data } = props;
const [inputValues, setInputValues] = React.useState(Array(props.data.check.split(/(%%.*?%%)/).length).fill(''));
const setProps = (index, inputValue) => {
const combinedValue = data.check.split(/(%%.*?%%)/).map((part, index2) => {
if (index2 % 2 === 0) {
return part;
} else if (index === Math.floor(index2)) {
return `%%${inputValue}%%`;
} else {
return part;
}
}).join('');
props.node.setDataValue(props.column.colId, combinedValue);
setData(prevData => ({
...prevData,
check: combinedValue,
}));
};
const handleChange = (index, event) => {
const newInputValues = [...inputValues];
newInputValues[index] = event.target.value;
setInputValues(newInputValues);
if (handleInputChange) {
handleInputChange(event);
}
};
return React.createElement(
'div',
null,
data.check.split(/(%%.*?%%)/).map((part, index) => {
if (part.match(/%%.*?%%/)) {
// If it matches the pattern, render Input element
return React.createElement(
window.dash_bootstrap_components.Input,
{
key: index,
type: props.type || 'text',
placeholder: '0,00',
setProps: () => setProps(index, inputValues[index]),
onChange: (event) => handleChange(index, event),
value: inputValues[index],
style: {
display: 'inline-block',
width: 'auto',
},
}
);
} else {
// Otherwise, render only Label element
return React.createElement(
window.dash_bootstrap_components.Label,
{
key: index,
children: part,
style: {
display: 'inline-block',
width: 'auto',
},
}
);
}
}),
);
};
Inside of the dash app you have to define ag-grid:
dag.AgGrid(
id="ag-grid",
rowData=[],
columnSize="autoSize",
dashGridOptions={
"rowHeight": 48,
"rowSelection": "multiple",
},
columnDefs=[
{
"headerName": "Check this column:",
"field": "check",
"cellRenderer": "DBC_Input_With_String",
},
],
),
Then i used a callback to populate the grid. The trick here is that you define a place where you want your input to be with this placeholder: %%INPUT%%. Javascript will look for it and render value inside %%*%%.
@callback(
[
Output("ag-grid", "rowData"),
Output("ag-grid", "defaultColDef"),
],
[
Input("interval-component", "n_intervals"),
],
)
def ag_grid_formation(n_intervals):
data = {
"check": [
"First input: %%INPUT%% Second input: %%INPUT%%",
],
}
df = pd.DataFrame(data)
defaultColDef = {
"resizable": False,
"sortable": False,
"editable": False,
}
return df.to_dict("records"), defaultColDef
Now the rowData is sorted. For data manipulation and further usage you can create another callback or use the previous one. I created a new one since I was creating a form and wanted to read the whole form once the user would click the button “SEND”. In this callback I also added some data rendering since the placeholder was written like this: %%INPUT%%.
@callback(
[
Output("dummy", "children"),
],
[Input("button-grid", "n_clicks")],
[State("ag-grid", "rowData")],
)
def ag_grid(click, data):
print(data)
updated_data_list = [
{
"check": item["check"]
.replace("%%", "")
.replace("%%INPUT%%", "No value entered"),
}
for item in data
]
print(updated_data_list)
return dash.no_update
That’s it