Material-UI DataGrid: How do I add a tooltip to each row cell? - datagrid

I could not find anything related to this in the react material ui datagrid documentation here. I noticed you can add tooltips to columns via a "description" field, but can not find any documentation or examples related to rows.

modify columns to add renderCell attribute
const columns: Columns = [
{
field: 'id',
headerName: 'ID',
sortable: false,
renderCell: (params: any) => (
<Tooltip title={params.data.id} >
<span className="table-cell-trucate">{params.data.id}</span>
</Tooltip>
),
}
]
css changes :
.table-cell-trucate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

I modified the columns like this:
const editColumns = columns.map((column) => ({
field: column,
headerName: column,
width:75,
flex: 1,
renderCell: (params: any) => (
<Tooltip title={params.value}>
<span>{params.value}</span>
</Tooltip>
),
}));

Just debug your code on rendercell and check what data you are getting in params, according to that filter your code.
renderCell: (params) => (
<Tooltip title={params.value} >
<span className="csutable-cell-trucate">{params.value}</span>
</Tooltip>
),
this worked for me.

You might want to use the GridCellParams type if you use TypeScript:
renderCell: (params: GridCellParams) => (
<Tooltip title={params.value}>
<span className="table-cell-trucate">{params.value}</span>
</Tooltip>
)

Related

How to specify column width for first column using react-table

When using useRowSelect and useTable how can I specify column width for the first column so that it never exceeds the width of the checkboxes? I don't want to use useFlex as I want to preserve column widths based on the header width.
You'll notice when the table is set to 100% width the first column starts to grow if you expand your browser window.
Here's an example:
https://codesandbox.io/s/youthful-hamilton-j0rev?file=/src/App.js
I'm also open to just grabbing the Header and Cell from where I'm pushing into the columns array and adding a className, but wasn't able to find a way to do that. How can I add a className so that the table cell that surrounds this column data has a className to attach to:
(hooks) => {
isRowSelectable &&
hooks.allColumns.push((columns) => [
{
id: 'selection',
minWidth: 35,
width: '35px',
maxWidth: 35,
Header: ({ getToggleAllRowsSelectedProps }) => (
<Checkbox alignSelf="center" {...getToggleAllRowsSelectedProps()} />
),
Cell: ({ row }: any) => {
row.className = '123';
return <Checkbox alignSelf="center" {...row.getToggleRowSelectedProps()} />;
}
},
...columns
]);
}
Since Array.map can pass the index of the element, it's fairly simple to conditionally add a className to the cell if the row index is 0:
{
rows.map((row, i) => {
prepareRow(row);
return (
<td className={i === 0 ? "class-name" : ""} {...cell.getCellProps()>
{cell.render("Cell")}
</td>
) ​
}
If you want the same class to apply to the headers, you can do the same thing on the <th> or <tr> elements, since those are also rendered with Array.map. You don't actually need to touch the columns object at all for this change.

How to upgrade column hiding from react-table 6 to react-table 7

Previous in react-table 6, one just added a show: false to the column spec to hide a column.
How can this be implemented in react-table 7?
You can access getToggleHiddenProps property from the column.
According to the docs
You can check the demo:
https://codesandbox.io/s/xenodochial-pasteur-dzk3k?file=/src/components/ColumnHiding.js
Also, if you want to hide some columns by default, add the accessors for the columns you want to hide and pass it as an array of strings to initialState.hiddenColumns
function Table({ columns, data }) {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
allColumns,
getToggleHideAllColumnsProps,
prepareRow
} = useTable({
initialState: {
hiddenColumns: ["firstName"]
},
columns,
data
});
// usual table markup from here on
}
There is more than one way to do this, but one way is to respond to the show property in from your column spec.
In your react-table 7 code that outputs the header:
eg.
headerGroup.headers.map(column => {
return ( <TableCell> column.render('Header') </TableCell> )
})
add a filter:
eg.
headerGroup.headers..filter(column => column.show !== false).map(column => {
return ( <TableCell> column.render('Header') </TableCell> )
})
And you your react-table 7 code that outputs your rows:
eg.
{row.cells.map(cell =>
{
return (
<TableCell {...cell.getCellProps({ className: cell.column.className })}>
{cell.render('Cell')}
</TableCell>
);
})}
add a filter:
eg.
{row.cells.filter(cell => cell.column.show !== false).map(cell =>
{
return (
<TableCell {...cell.getCellProps({ className: cell.column.className })}>
{cell.render('Cell')}
</TableCell>
);
})}

react-table : Add a select (checkboxes) column with a headergroup

For aesthetic reasons I'm trying to add a HeaderGroup to the "select" (checkboxes) column solution provided in react-teable examples.
hooks => {
hooks.visibleColumns.push(columns => {
return [
{
id: 'selection',
// Make this column a groupByBoundary. This ensures that groupBy columns
// are placed after it
groupByBoundary: true,
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
...columns,
]
})
Source:
https://codesandbox.io/s/github/tannerlinsley/react-table/tree/master/examples/kitchen-sink
I've tried many ways using hooks object but none of them worked (for example nested calls to hooks.headerGroups.push and then hooks.visibleColumns.push).
Here is my last attempt which makes sense but doesn't work either (TypeError: Cannot read property 'forEach' of undefined) :
hooks => {
hooks.headerGroups.push(headerGroups => {
return [
{
Header: 'X',
columns: [
{
id: 'selection',
// Make this column a groupByBoundary. This ensures that groupBy columns
// are placed after it
groupByBoundary: true,
// The header can use the table's getToggleAllRowsSelectedProps method
// to render a checkbox
Header: ({ getToggleAllRowsSelectedProps }) => (
<div>
<IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} />
</div>
),
// The cell can use the individual row's getToggleRowSelectedProps method
// to the render a checkbox
Cell: ({ row }) => (
<div>
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
}
]
},
...headerGroups
]
})
})
Thank you for your help ^^

Text formating with CSS

I am using the ant-design library with the Table and Tooltip component
I am trying to format the tooltip so that each element inside of my array is on it's own line instead of 1 big paragraph like how it is here.
The code that generates the above UI looks like this
const generateTableColumns = () => {
if (survey) {
const selectedSurvey = `${survey}`.toLowerCase()
const columnHeaders = SurveyArray[selectedSurvey].questions.map(item => ({
title: item.id,
dataIndex: item.id,
key: item.id,
ellipsis: {
showTitle: false,
},
render: dataIndex => (
<Tooltip placement="topLeft" title={dataIndex}>
{dataIndex}
</Tooltip>
),
}))
setTableColumns(columnHeaders)
}
}
I have tried doing
render: dataIndex => (
<Tooltip placement="topLeft" title={dataIndex}>
{ {_.isArray(dataIndex) ? dataIndex.map(item => <p className="test">{item}</p>) : null} }
</Tooltip>
),
Which formats the elements in the table, not the tooltip.
Does anyone have any idea on how I can style the elements inside of the span like I did on the table?
I believe you need to use "\n" to break line.
"Hi, my name is Emir." => "Hi, my name is Emir."
"Hi, \n my name is Emir." =>
"Hi,
my name is Emir."
Note: I'm not sure about the answer I wish I could add this as a comment but my reputation is not enough to comment. Have a nice day!
render: dataIndex => (
<Tooltip
placement="topLeft"
title={
_.isArray(dataIndex) ? dataIndex.map(item => <p className="test">{item}</p>) : null
}
>
{dataIndex}
</Tooltip>
),
From reading the docs, looks like title is what is being used to render the elements inside of the tooltip. This gave me what I was after

Wordpress Gutenberg autocomplete - saving attributes

I want to develop a custom block that will let the user pick some information from autocomplete. I manage to create the autocomplete component on edit function.
A user can select an item but i don't know how to handle the attribute save.
I'm trying to save the selected item as attribute package_name. I created the onChange function on Autocomplete component but event.target.value is undefined.
Here is my code from block.js
const { __ } = wp.i18n; // Import __() from wp.i18n
const { AlignmentToolbar,
BlockControls,
registerBlockType } = wp.blocks;
const { RichText } = wp.editor;
const { Autocomplete, } =wp.components;
const MyAutocomplete = () => {
const autocompleters = [
{
name: 'fruit',
triggerPrefix: '#',
options: [
{ name: 'Apple', id: 1 },
{ name: 'Orange', id: 2 },
{ name: 'Grapes', id: 3 },
{ name: 'test', id: 4 },
],
getOptionLabel: option => (
<span>
{ option.name }
</span>
),
getOptionKeywords: option => [ option.name ],
isOptionDisabled: option => option.name === 'Grapes',
getOptionCompletion: option => (
<abbr title={ option.name }>{ option.name }</abbr>
),
}
];
function onChangeAuto(newContent){
console.log('autocompletexx '+newContent);
}
function onSelectAuto(event){
console.log(event.target);
console.log( event.target.value);
}
return (
<div>
<Autocomplete completers={ autocompleters }>
{ ( { isExpanded, listBoxId, activeId } ) => (
<div
contentEditable
suppressContentEditableWarning
aria-autocomplete="list"
aria-expanded={ isExpanded }
aria-owns={ listBoxId }
aria-activedescendant={ activeId }
onChange={onChangeAuto }
onSelect={onSelectAuto}
>
</div>
) }
</Autocomplete>
<p class="autocomplete_p">Type # for triggering the autocomplete.</p>
</div>
);
};
registerBlockType( 'residence-gutenberg-block/membership-package-settings', {
title: __( 'Residence - Membership Package Settings' ), // Block title.
icon: 'shield',
category: 'common',
keywords: [
__( 'membership-package-settings' ),
],
attributes:{
package_id:{
type:'string',
select:'p'
},
package_name:{
type:'string',
},
},
edit: function( props ) {
const { attributes: {package_name}, className,setAttributes,isSelected } = props;
return (
<div className={ props.className }>
<form>
<label className="wpresidence_editor_label">Current Package: {package_name}</label>
<MyAutocomplete></MyAutocomplete>
</form>
</div>
);
},
save: function( props ) {
// Rendering in PHP
return null;
},
} );
Passing down onChange, onSelect to the div element won't work, because these attributes are only applicable to the form field elements (as input, select, etc.).
I checked the documentation and the source code and didn't find any details or official approaches for dealing with the case.
However, I'm seeing two possible approaches for getting the selected value:
1. Using Autocomplete onReplace prop
Looking into the Autocomplete's source code, I noticed that onSelect callback invokes onReplace prop with the selected option as array. It may not fit all the cases, but you can give it a try! It may be enough for your case! You can try to add your handler to the onReplace as follows:
<Autocomplete
onReplace={ option => { console.log(option) } }
completers={ autocompleters }>
{ ( { isExpanded, listBoxId, activeId } ) => (
<div
contentEditable
suppressContentEditableWarning
aria-autocomplete="list"
aria-expanded={ isExpanded }
aria-owns={ listBoxId }
aria-activedescendant={ activeId }
/>
) }
</Autocomplete>
2. Listen for <div /> changes manually
You can add onInput, onBlur listeners to the <div />, having an uncontrolled react div component and when the div's value is changed then we can keep the changed value in your parent component's state.
Here's a great discussion, which describes these technique: React.js: onChange event for contentEditable
The good think is that there's already a plugin (based on this discussion) that can do it for you: react-contenteditable.
Firstly you have to convert your <MyAutocomplete /> component to be a statefull (not functional) and then:
import ContentEditable from 'react-contenteditable'
// Boilerplate ...
<Autocomplete completers={ autocompleters }>
{ ( { isExpanded, listBoxId, activeId } ) => (
<ContentEditable
html={this.state.html}
onChange={this.handleChange}
contentEditable
suppressContentEditableWarning
aria-autocomplete="list"
aria-expanded={ isExpanded }
aria-owns={ listBoxId }
aria-activedescendant={ activeId }
/>
) }
</Autocomplete>
Conclusion
I'm surprised that in the Autocomplete's documentation there aren't any details for this case. I guess it's because of the following statement (27.08.2018):
Gutenberg is being developed on GitHub, and you can try an early beta
version today from the plugin repository. Though keep in mind it’s not
fully functional, feature complete, or production ready.
However, one of both mentioned approaches above will help you, until they provide a complete API to work with their components.
I would suggest you to keep wrapping the Wordpress's <Autocomplete /> with your own component - in order to easily refactor your code later, when they release the complete API.
If you have questions, feel free to comment below.

Resources