mui-datatables
mui-datatables copied to clipboard
customBodyRender a cell with multiple links from an array
Hello!
This isn't a bug but me trying to figure out how to do something, if it's possible.
I am creating an app with a lot of relationships and I want to create links to different profiles within the cells. Sometimes a single cell may need to contain more than one link.
An example of this use case might be Pet owners and their pets. Say I create a table of Owners and then in one cell is a list of the pet names
| Owners | Pet Names |
|---|---|
| Paige | Sally, Sage, Ember |
I've gotten it to where I can push all the names of the animals related to a specific owner to a new array and then join that array to create a string that shows up properly with all the pets listed. When I click on the row I get taken to the owner profile with the onRowClick function which is exactly how I want it
Code Example
const [data, setData] = useState([]);
const [petColumns, setPetColumns] = useState([]);
const [columnData, setColumnData] = useState([]);
const [options, setOptions] = useState({
filter: true,
filterType: 'dropdown',
responsive: 'standard',
rowsPerPage: 10,
resizableColumns: true,
enableNestedDataAccess: '.',
selectableRows: 'none',
onRowClick: (rowData) => {
handleClick(rowData);
}
})
setPetColumns = [
{
name: "id",
label: "Id",
options: {
display: 'excluded',
}
},
{
name: "name",
label: "Owner Name",
},
{
name: "pet",
label: "Pets",
},
]
useEffect(() => {
API.getOwnerData(ownerId)
.then(res => setData(res.data))
.catch(err => console.log(err))
}, [ownerId])
useEffect(() => {
const ownerData = data.map((owner) => {
const petList = []
owner.Pets.forEach((pet) => {
petList.push({
name: pet.name,
})
})
const petObject = {
id: owner.id,
name: `${owner.User.firstName} ${owner.User.lastName}`,
pet: petList.map(p => p.name).join(', '),
}
return petObject
})
setColumnData(ownerData)
}, [data])
const handleClick = (rowData) => {
navigate(`${rowData[0]}`)
}
<MUIDataTable
className={styles.innerTable}
data={columnData}
columns={petColumns}
options={options}
>
</MUIDataTable>
Where I'm running into trouble is that I want to turn each of the pet names that are being listed into a link that will navigate to the pets respective profile when clicked on. I will show some of my attempts to do this and explain what the results were.
ATTEMPT 1
Here I added pet.id to the petList object. This id is used with react-router-dom and Link to travel to the proper profile page for the pet. I then set up a customBodyRender (I tried both customBodyRender and customBodyRenderLite) which is supposed to map through the pet list and create a link with the pet name for each entry and then join together the new link divs.
I'm actually fairly stumped on this because I keep getting "Uncaught TypeError: value.map is not a function". Which makes me think that the value of property is not being recognized as an array. However, I found several StackOverFlow posts where value is treated properly as an array and can be joined together such as here.
I also recognize though that the array in that stack overflow is flat which mine is not but I even added the "enableNestedDataAccess: '.'," to that specific set of options (even though it's already in the general options for the table) just to make sure. I tried some variations of metadata as well but couldn't get that to stick either, I honestly think I'm probably incorporating it wrong.
CODE EXAMPLE - I didn't include the code that remained unchanged
setPetColumns = [
{
name: "id",
label: "Id",
options: {
display: 'excluded',
}
},
{
name: "name",
label: "Owner Name",
},
{
name: "pet",
label: "Pets",
options: {
customBodyRenderLite: (value) => { ****ATTEMPTED customBodyRender TO RENDER THE LINK AND THEN JOIN ****
return (
<>
{value.map((e) => {
<Link to={`/pets/id=${e.id}`} >{e.name}</Link>
}).join(', ')}
</>
)
}
}
},
]
useEffect(() => {
const ownerData = data.map((owner) => {
const petList = []
owner.Pets.forEach((pet) => {
petList.push({
name: pet.name,
id: pet.id ****ID IS ADDED FOR NAVIGATION PURPOSES****
})
})
const petObject = {
id: owner.id,
name: `${owner.User.firstName} ${owner.User.lastName}`,
pet: petList
}
return petObject
})
setColumnData(ownerData)
}, [data])
When I console log columnData I get exactly what I'm expecting DATA EXAMPLE
0:
id: "30c9"
name: "Paige"
property: Array(3)
0:
id: "df43"
name: "Sally"
1:
id: "dea4"
name: "Sage"
2:
id: "ger7"
name: "Ember"
ATTEMPT 2
My attempt here was kind of a hail mary, I'd been working trying to get the custom render to work for a long while so I thought I'd go at it from a different direction. I trying to include Link within the petObject that initially worked in providing the plain joined names.
My result of this attempt was that my data table rendered but I got [ object Object ] within the pet Columns if I included return in the .map function or an empty string if there was no return. I honestly didn't really expect this to work but was at a loss of what else to try. When I consoled the columnData it was either [ object Object ] or ""
setPetColumns = [
{
name: "id",
label: "Id",
options: {
display: 'excluded',
}
},
{
name: "name",
label: "Owner Name",
},
{
name: "pet",
label: "Pets",
},
]
useEffect(() => {
const ownerData = data.map((owner) => {
const petList = []
owner.Pets.forEach((pet) => {
petList.push({
name: pet.name,
id: pet.id ****ID IS ADDED FOR NAVIGATION PURPOSES****
})
})
const petObject = {
id: owner.id,
name: `${owner.User.firstName} ${owner.User.lastName}`,
*****TRIED TO INCLUDE LINK WITHIN OBJECT****
pet: petList.map((p) => {
return <Link to=`/pet/id=${p.id} >p.name </Link> ****If return isn't included a blank string is returned****
}).join(', '),
}
return petObject
})
setColumnData(ownerData)
}, [data])
RESULT
| Owners | Pet Names |
|---|---|
| Paige | [object Object] |
| Tech | Version |
|---|---|
| Material-UI | 4.12.3 |
| MUI-datatables | 4.1.2 |
| React | 17.0.2 |
| browser | Google Chrome |