Open zzossig opened 3 years ago
@zzossig thanks for raising this. I guess what you are looking for is a new column type of textarea
, or <TextField multiline />
, correct?
To unblock you for now you can check how to create a custom column type here https://mui.com/components/data-grid/columns/#custom-column-types.
@DanailH Hi. I guess you may misunderstood what I'm asking. Introducing a new column type is just what I'm suggesting. What I'm asking is How to edit a cell that has very long text
But when you create a new column type you can provide renderEditCell
where you can handle that case. Granted because of the fixed height of the rows some additional logic needs to be added.
Thank you for the answer.
I have tried renderEditCell
with multiline TextField
.
But there are some problems when editing a long text
I'm pretty sure renderEditCell
is not the best option to handle long text.
Why not provide more handy option for that?
I created a CodeSandbox showing how to create a custom edit component with a textarea. You need to use a Portal to allow the input to exceed the cell boundaries. It should fix most of the issues you mentioned. The example can be further improved by debouncing api.setEditCellValue
.
import InputBase from "@mui/material/InputBase";
import Popper from "@mui/material/Popper";
import Paper from "@mui/material/Paper";
const EditTextarea = (props) => {
const { id, field, value, colDef, api } = props;
const [valueState, setValueState] = React.useState(value);
const [anchorEl, setAnchorEl] = React.useState<HTMLDivElement | null>();
const handleRef = (el) => {
setAnchorEl(el);
};
const handleChange = React.useCallback(
(event) => {
const newValue = event.target.value;
setValueState(newValue);
api.setEditCellValue({ id, field, value: newValue }, event);
},
[api, field, id]
);
return (
<div>
<div
ref={handleRef}
style={{
height: 1,
width: colDef.computedWidth,
display: "block",
position: "absolute",
top: 0
}}
/>
{anchorEl && (
<Popper open anchorEl={anchorEl} placement="top-start">
<Paper elevation={1} sx={{ p: 1, minWidth: colDef.computedWidth }}>
<InputBase
multiline
rows={4}
value={valueState}
sx={{ textarea: { resize: "both" }, width: "100%" }}
onChange={handleChange}
/>
</Paper>
</Popper>
)}
</div>
);
};
const renderEditTextarea = (params) => <EditTextarea {...params} />;
@m4theushw Yes, the example works. Thank you.
Anyway, is there any chance to support this features natively?
For future readers, this is the debounced version. This fixes input lagging
...
import { debounce } from "lodash";
const EditTextarea = (props: GridRenderCellParams) => {
const { id, field, value, colDef, api } = props;
const [valueState, setValueState] = React.useState(value);
const [anchorEl, setAnchorEl] = React.useState<HTMLDivElement | null>();
const minWidth = React.useMemo(() => {
if (colDef.computedWidth) {
return colDef.computedWidth + 400;
}
return 0;
}, [colDef.computedWidth]);
const setEditCellValue = React.useCallback(
(event: React.ChangeEvent<HTMLInputElement>, newValue: string) => {
api.setEditCellValue({ id, field, value: newValue }, event);
},
[api, field, id]
);
const debouncedSetEditCellValue = React.useMemo(
() => debounce(setEditCellValue, 60),
[setEditCellValue]
);
const handleRef = (el: HTMLDivElement) => {
setAnchorEl(el);
};
const handleChange = React.useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
const newValue = event.target.value;
setValueState(newValue);
debouncedSetEditCellValue(event, newValue);
},
[debouncedSetEditCellValue]
);
return (
<div>
<div
ref={handleRef}
style={{
height: 1,
width: minWidth,
display: "block",
position: "absolute",
}}
/>
{anchorEl && (
<Popper open anchorEl={anchorEl} placement="bottom-end">
<Paper elevation={1} sx={{ p: 1, width: minWidth }}>
<InputBase
multiline
rows={10}
value={valueState}
sx={{ textarea: { resize: "both" }, width: "100%" }}
onChange={handleChange}
/>
</Paper>
</Popper>
)}
</div>
);
};
const renderEditTextarea = (params: any) => <EditTextarea {...params} />;
We can look at having this column type out of the box. The tricky part is how do you know when to do the normal text input and when to do the text area.
@m2mathew maybe we can update the docks for now with this example now.
I also have another question. How can I bind Escape(esc) key to close Popper component? I have tried this.
<Popper open={Boolean(anchorEl)} ...>
...
<InputBase
onKeyDown={(e) => {
if (e.key === "Escape") {
setAnchorEl(null);
}
}}
/>
</Popper>
Unfortunately, this is not working. Then, How can I close the Popper component with esc key?
@m4theushw Also, there is another problem.
When there are many EditTextarea in grid columns and editMode="row"
say
<DataGridPro
editMode="row"
rows=[...]
columns=[
{ ..., renderEditCell: EditTextarea },
{ ..., renderEditCell: EditTextarea },
{ ..., renderEditCell: EditTextarea },
...
]
/>
Then, edit mode looks like this. I used EditTextarea component 20 times so the 20 components overlap each other.
for sure this is not what I wanted.
The custom EditTextarea
is not fit well with editMode="row"
prop.
With this problem, I decide not to use editMode="row"
with the custom EditTextarea
component.
But while I followed the full-featured CRUD example, this happened again.
If I click the ADD RECORD
button, new row is inserted to the grid,
and the row is set to editMode="rows"
as default even though I didn't set it in my grid component.
So, I'm considering to move CRUD feature outside of the grid component.
So, What's the problem?: I'm just telling you what I'm struggling with now.
In my example, the Popper is immediately open when the custom edit component is rendered. You could instead control its open
prop and only set it to true when the user clicks the cell. It would work like this: user double clicks a cell to enter into edit mode -> all cells become editable -> user clicks in one cell with long-text -> open the Popper for that cell. You could also use a Modal
so only one Popper can be active at the same time.
Here's an updated demo: https://mui.com/x/react-data-grid/recipes-editing/#multiline-editing
The custom EditTextarea is not fit well with editMode="row" prop.
You can utilize the onBlur
and onFocus
event handlers to determine when to open or close the multi-line text editor.
Demo: https://codesandbox.io/s/heuristic-booth-2bi5xs?file=/demo.tsx:3861-3876
Duplicates
Latest version
Summary π‘
As far as I know, data-grid-pro doesn't have a feature to edit a cell with a very long text. The text size could be few KB to MB and enter key should be preserved for a line feed(\n).
MUI document provide [Expand cell renderer] example for a long text that will allow seeing the full content of the cell in the grid. So to say you guys already knows that a long text is a common use case for grid component, right? Then, why not provide a way to edit a cell with a long text?
And I wonder what is the best way to edit a cell with a long text within current version? Can you please document for it?
Examples π
I expect a new type(text) for a long text
Motivation π¦
One of the use case for the mui-x grid is to display my database tables. The database tables can have a very long text column so I need this feature.
Benchmark
Order ID π³ (optional)
27772