Creating a dynamic inline editable table in React — Part 2
This post is a continuation of my previous post on creating a dynamic table in React. The link to the first part of this series is here. Before you continue reading this, I would request you to go through the part 1 of this post.
Goal:
In this post, we will make our dynamic table to render cell values in custom way.
Let’s start
We know that our sample data looks like below:
[
{
"id":1,
"first_name":"Shara",
"last_name":"Weeds",
"email":"sweeds0@barnesandnoble.com",
"gender":"Female"
},
{
"id":2,
"first_name":"Conant",
"last_name":"Puddan",
"email":"cpuddan1@ihg.com",
"gender":"Male"
},
{
"id":3,
"first_name":"Mehetabel",
"last_name":"Mawtus",
"email":"mmawtus2@sakura.ne.jp",
"gender":"Female"
}
]
Assume that we want the emails to be rendered as google search links. We can do it by adding a new emailRenderer
function in our Users
component and assign it to a new prop named renderer
inside email
column settings in our getDisplayColumns
function. The updated email
column settings inside getDisplayColumns
function will look like below:
Users component (Users.js)
...
{
fieldName: 'email',
displayText: 'Email',
visible: true,
columnSize: 4,
renderer: this.emailRenderer
},
...
and the newly added emailRenderer
function will look like this:
...
emailRenderer() {
const url = `https://www.google.com`;
return (
<a href={url}>
{url}
</a>
);
}
...
please remember to bind this function inside constructor of Users component.
Now, if we run our code now, we will see this:

Question: You may be thinking why are we rendering a hard-coded url instead of the email?
Answer: as of now, we don’t know from where the email will be coming to this function. And we haven’t used the newly added renderer
prop yet in our GenericCustomTable.
Let’s do that now:
GenericCustomTable component (GenericCustomTable.js)
So far, our renderIndividualRow
function looks like this:
...
renderIndividualRow(data, dataKeys) {
return dataKeys.map((item, index) => {
let columnWidth = `col-md-${this.state.columnsToDisplay[index].columnSize}`;
if (item.visible) {
return (
<div className={columnWidth} key={index}>
{data[item.fieldName]}
</div>
);
} else {
return null;
}
});
}
...
and we will update it as below:
...
renderIndividualRow(data, dataKeys) {
return dataKeys.map((item, index) => {
let columnWidth = `col-
md-${this.state.columnsToDisplay[index].columnSize}`;
if (item.visible) {
if (item.renderer) {
return (
<div className={columnWidth} key={index}>
{item.renderer(data, item.fieldName)}
</div>
);
} else {
return (
<div className={columnWidth} key={index}>
{data[item.fieldName]}
</div>
);
}
} else {
return null;
}
});
}
...
Also, update the props
declaration for GenericCustomTable
as below:
...
GenericCustomTable.propTypes = {
data: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.shape({
fieldName: PropTypes.string,
displayText: PropTypes.string,
visible: PropTypes.bool.isRequired,
columnSize: PropTypes.number.isRequired,
renderer: PropTypes.func
})).isRequired
};
...
Note the lines in bold above. We are now checking if any item contains a renderer
property, and if it is, then we are calling the renderer
property (which should be a function) of that item. And we are passing in the data and fieldName to that renderer
function as input. This is very important as passing in these inputs will allow us to display individual field value for that corresponding line item.
Now, if you remember from above, our emailRenderer
function still not accepting any input (and still returning a hard-coded url as link). Let’s update that as follows:
...
emailRenderer(data, fieldName) {
const fieldValue = data[fieldName];
const url = `https://www.google.com?search=${fieldValue}`;
return (
<a href={url}>
{fieldValue}
</a>
);
}
...
Let’s check our changes in browser:

That’s it, we have updated our GenericCustomTable
component to render a field value in our preferred way :)
Great job and thank you for sticking with me.
Links:
Part 1 of this series can be found here.
Part 3 of this series is here