Creating a dynamic inline editable table in React — Part 2

Vanu Protap Verma
3 min readMar 28, 2020

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:

screenshot 3: email is still rendered as plain text

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:

screenshot 4: hurray, email is now a link :)

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

--

--