React make table clickable and edit details - reactjs

How do I make a table row clickable to edit and update details? I'm retrieving these details from pouchdb.
I'm pasting portion of my code below for your evaluation:
this.state = {docs: []}
this.db = this.props.db
componentDidMount () {
this.updateDocs()
this.db.changes({
since: 'now',
live: true
}).on('change', (change) => {
this.updateDocs()
}).on('error', (err) => {
console.error(err)
})
}
updateDocs () {
this.db.allDocs({include_docs: true}).then((res) => {
var docs = res.rows.map((row) => row.doc)
this.setState({docs})
})
}
And the table below:
<div className='table-list'>
<table>
<thead>
<tr>
<th>Registration Type</th>
<th>First Name</th>
<th>Middle Name</th>
</tr>
</thead>
<tbody>
{this.state.docs.map((doc) => <DataRow key={doc._id} doc={doc} {...this.props} />)}
</tbody>
</table>
</div>
class DataRow extends React.Component {
render () {
let {doc} = this.props
return (
<tr>
<td>{doc.RegistrationInfo['registrationtype']}</td>
<td>{doc.RegistrationInfo['firstname']}</td>
<td>{doc.RegistrationInfo['middlename']}</td>
</tr>
)
}
}
I want to be able to click and edit each of the rows.

My first suggestion - do not do this. Editable grids are quite tough components to implement on your own.
Therefore you have some options to choose from:
Use existing frameworks with editable grids: KendoUI, Wijmo, etc. Although they are quite pricely and most of them have quite pure support for react as for now.
There are some standalone grids with editing functionality: ag-grid, react data grid etc. Some of them are free, other paid.
You can develop your own editable grid based on powerfull components like fixed-data-table, react-virtualized, etc. This approach will still will require some coding to be done but will save you a lot of time.
Make your own components as you are trying now.
If you still would like to go with #4 you can do it this way:
4.1. In state store column of the currently edited cell: editingColumn.
4.2. Assign onClick handler on your <td> tags: <td onClick={(ev) => this.onCellClick(ev))}>. In the handler set editingColumn
4.3. In your render replace
<td>{doc.RegistrationInfo['registrationtype']}</td>
with
<td>{this.renderCell('columnName')}</td>.
And renderCell will look something like this:
private renderCell(colName)
{
if(this.state.editingColumn >= 0 && this.state.editingRow >= 0)
{
// Render your editing control here
// Assign to its 'onChange' like event and save changes to this.props.RegistrationInfo[colName];
}
else
{
return this.props.RegistrationInfo[colName];
}
}
This is very rough description but I hope it will help you get on going.

Related

Django REST Framework Render a result from an hyperlink in API response

I am building an application with a DRF/React stack, and I have a bit of an issue.
I am using a HyperlinkedModelSerializer to be able to easily make a GET request with the link given. On a less optimistic note, I am not able to query my result that easily.
Here is an example of my json object I get from my API
[
{
"url": "http://localhost:8000/session/3/",
"session_start": "01:00:17.234060",
"nb_person": 1,
[...]
"client": "http://localhost:8000/client/1/"
}
]
There is an array I want to render in my template. Althought, I wanted to show the client firstname and lastname I get from my client link.
function GetContactFromAPI(url)
{
var name = ""
axios.get(url).then(response => {
const data = response.data
name = `${data.firstname} ${data.lastnom}`
return name
})
return name
}
return (
<div>
<table>
<thead>
<tr>
<th>Client</th>
<th>Nb Pers.</th>
<th>Starting time</th>
</tr>
</thead>
<tbody>
{sessions.map((session, index) => {
return (
<tr key={index}>
<td>{GetContactFromAPI(session.client)}</td>
<td>{session.nb_person}</td>
<td>{session.session_start}</td>
</tr>
)
})}
</tbody>
</table>
</div>
);
I think I have some misunderstanding on sync/async in order to render the result I need. Do you have an idea to resolve this need?
I was thinking to get an client list and to get client I need. But I wanted to avoid this request that may bigger than needed (I have more than 40K clients).
Thanks in advance
I may need to see your serializer where the client field is located, but what you need to do is create a Nested Relationship for the client field. Try to do this:
client = ClientSerializer()
Refer to the documentation here

Copy the HTML table to clipboard in reactjs

I have an HTML table in my react project. I want to copy the table to clipboard.
<table id="sample">
<thead>
<th>Amount</th>
<th>Charges</th>
</thead>
<tbody>
<tr>{item.Amount}</tr>
<tr>{item.Charges}</tr>
</tbody>
</table>
This is the table structure . I haven't included any react code.
I referred this sample code https://stackblitz.com/edit/js-copy-element?file=index.js . But it's not in react.
Using react code how can I copy the table to clipboard?
might be too late to answer this, but here's how I did it.
I had element rendered in my component's render function.
render(){
return(
<table id="table">
.... your table content
</table>
)
}
and simply build a copy function by referring to the sample code shared above.
copyTable = () => {
const elTable = document.querySelector('table');
let range, sel;
// Ensure that range and selection are supported by the browsers
if (document.createRange && window.getSelection) {
range = document.createRange();
sel = window.getSelection();
// unselect any element in the page
sel.removeAllRanges();
try {
range.selectNodeContents(elTable);
sel.addRange(range);
} catch (e) {
range.selectNode(elTable);
sel.addRange(range);
}
document.execCommand('copy');
}
sel.removeAllRanges();
console.log('Element Copied! Paste it in a file')
}
then, call this function by building an element like this
<h1 onClick={()=>{this.copyTable()}}>Copy to table</h1>

Read public gists from Github and storing values in Reactapp

I am creating a webapp on react where when you search for a user you can view that users public gists, files and people who have forked their projects.
I was previously able to get values from https://api.github.com/users?since=1234 by looping through the values:
<div>
{
users.map((user, i) => {
return <Usercard
key={users[i].id}
//Virtual DOM needs key prop to keep track of cards
username={users[i].login}
avatar={users[i].avatar_url}
profile={users[i].html_url}
/>
})
}
</div>
However when I use https://api.github.com/gists/public I am a bit lost with the function to read the data from these group of arrays such as files, forks_url, owner properties and so on as I am unable to get the values.
I am calling the data like so:
componentDidMount() {
fetch('https://api.github.com/users')
.then(response => response.json())
.then(users => this.setState({users: users}));
}
In gist URL https://api.github.com/gists/public
The user info is under owner object, if thats what you are looking for.
Pseudo code for rendering gists info in a table:
const renderUserInfo = data.map((value, key) => {
return <tr key={key}>
<td>
{value.owner.login}
</td>
<td>
{value.owner.url}
</td>
</tr>
});
Hope this helps. Let me know if you are still having trouble :D

Update a specific table row based on unique id

I have two components, the parent is called Layout and the child Report. In Report I have a table that loops through and renders a list of car accidents. I have a handler - handleIncidentReport in Report that calls a function in Layout to update this.state.obds (car messages) which then obviously updates the child Report.
My question is what is the proper ReactJS way to have it so only the row clicked has its {this.props.incident_report} updated, and not the other dynamically created rows with the same yield statement (not sure of the correct terminology).
I'm less than a week into ReactJS and I know I could hack it together but I want to know the proper way.
Here is a chunk of the two files -
Report
handleIncidentReport: function(e) {
var accident_id = $(e.target).closest('tr').data('accident-id')
this.props.changeIncidentReport(e, accident_id)
},
render: function() {
var self = this;
var accidents = [];
for (var i = 0; i < this.props.accidents.length; i++) {
var incident = this.props.accidents[i];
accidents.push([
<tr key={i} onClick={self.handleIncidentReport} data-accident-id={incident.id} >
<td>{incident.owner.first_name} {incident.owner.last_name}</td>
<td>{incident.car.title}</td>
<td>{moment(incident.created_at).format("MMM D, YYYY - hh:mm A")}</td>
</tr>,
<tr className="incident-report">
<td colSpan="3">
<Obds obds={this.props.incident_report} />
</td>
</tr>
]);
};
return (
<div className="report">
<table className="table">
<thead>
<tr>
<th>Name</th>
<th>Car</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{accidents}
</tbody>
</table>
</div>
);
}
Layout
changeIncidentReport: function(e, accident_id) {
var $tr = $(e.target).closest('tr');
$.ajax({
method: "GET",
data: {accident_id},
url: "/superadmin/emergency_analysis/get_incident",
datatype: 'jsonp'
}).success(function(incident){
this.setState({
incident_report: incident
});
}.bind(this));
},
You should make it so that handleIncidentReport returns a function that is configured (through closures) with the index of each of the rows, something like:
handleIncidentReport: function(accident_id) {
return function(e) {
this.props.changeIncidentReport(e, accident_id)
}
},
(If you aren't sure how closures work you should check out this excellent post: How do JavaScript closures work?)
Then update your render to use
<tr key={i} onClick={self.handleIncidentReport(i)} data-accident-id={incident.id} >
and each of the rows will have a unique handler all of their own that will be called when they're clicked on.
This should also get rid of some of that jQuery which figures out which accident_id was clicked on too.

how to fix ngtable pagination?

I have developed a ngtable with a filter. The pagination on the table does not work anymore though? When I select the show 10 rows on the bottom of the table it still shows 14 rows? How can i fix the pagination/indexing?
This is my table definition:
<table ng-table="tableParams" class="table">
<tr ng-repeat="account in $parent.filtered =(data | filter:search.accountName | filter:search.id)">
<td data-title="'id'">
{{account.account.accountId.id}}
</td>
<td data-title="'name'">
{{account.account.accountName}}
</td>
</tr>
</table>
plunkr:http://plnkr.co/edit/Rqt6px?p=preview
You need to figure pagination function by yourself. You may see ng-table's example in here.
var Api = $resource("/data");
this.tableParams = new NgTableParams({}, {
getData: function(params) {
// ajax request to api
return Api.get(params.url()).$promise.then(function(data) {
params.total(data.inlineCount); // recal. page nav controls
return data.results;
});
}
});
It first load all the data into Api. The params.url() contains current page and page count. It then use these two variable to return part of dataset. So you may need to figure out how to return this part of data.

Resources