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>
Related
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
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.
In the console i am receiving back data from an API: https://github.com/SunDwarf/OWAPI/blob/master/api.md
but in the file where i am trying to render it to the page i am getting back an error : this.props.stats.map is not a function
previously i did it like this for a weather app and didn't have a problem so i am not sure where to look to figure this out.
*EDIT: added curly brackets to function mapStateToProps({ stats }) which now changes the error to "TypeError: Cannot read property 'achievements' of undefined"
does this mean the path to the info is incorrect?
Code:
import React, { Component } from 'react';
import { connect } from 'react-redux';
class OverwatchStats extends Component {
renderStats(achievementData) {
return (
<tr>
<td>{achievementData.data.eu.achievements.support}</td>
</tr>
);
}
render() {
return (
<table className="table table-hover">
<thead>
<tr>
<th>Hero Achievements</th>
<th>Got</th>
</tr>
</thead>
<tbody>
{this.props.stats.map(this.renderStats)}
</tbody>
</table>
);
}
}
function mapStateToProps({ stats }) {
return { stats };
}
export default connect(mapStateToProps)(OverwatchStats);
I have my code here: My Github
According to the api, stats is the object, not the array, so you can't map over it
Eldar G hit the nail right on the head.
Because stats is an object that outputs the following
var stats = {"stats": {
"typeofstat" : {},
"othertypeofstat": {}
...
}
You can do the following in order to iterate all keys of an object.
Object.keys(this.props.stats).map((key) => {
var currentStat = stats[key];
//do stuff with currentStat
});
Read https://github.com/SunDwarf/OWAPI/blob/master/api.md#get-apiv3ubattletagstats if you want more information on the type of keys that each stat contains. It seems your response will be a deeply nested object. Interpret and manipulate such an object according to your preferences and requirements.
Hope this helps. Remember, all iterator methods like map, forEach, reduce, etc... work only for arrays!
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.
I am using React.js to dynamically create a html table containing text boxes. I have rows that can be removed by a button click. I expect, when I click "remove" on the first row that the table re-renders with row 1 removed. However, when react re-draws the table, it looks like it always removes the last row of the table from the DOM instead of using the actual values from my state object. Perhaps I found a bug? Here's my code:
/** #jsx React.DOM */
var MyApp = React.createClass({
getInitialState: function () {
return {
col_one: ['c1r1', 'c1r2', 'c1r3'],
col_two: ['c2r1', 'c1r2', 'c1r3'],
col_three: ['c3r1', 'c3r2', 'c3r3']
}
},
handleCellChange: function (colName, index, e) {
console.log('onChange:', colName, index, e.target.value);
},
handleRemove: function (i) {
var that = this;
console.log('removing row:',i);
_.forEach(this.state, function (val, colName) {
that.state[colName].splice(i,1); // BUG???
//_.pullAt(that.state[key], i); // doesn't work either
});
console.log(this.state);
this.setState(this.state);
},
render: function() {
var that = this,
rows = [],
cols = _.keys(this.state);
rows.push(
<tr>
{cols.map(function (col) {
return (
<th>{col}</th>
)
})}
</tr>
)
for (var i = 0; i < this.state[cols[0]].length; i++) {
rows.push(
<tr>
{cols.map(function (col) {
return (
<td>
<input type="text" defaultValue={that.state[col][i]} onChange={that.handleCellChange.bind(that, col, i)} />
</td>
)
})}
<td>
<button onClick={this.handleRemove.bind(this, i)}>Remove</button>
</td>
</tr>
)
}
return (
<table>
<tbody>
{rows}
</tbody>
</table>
);
}
});
React.renderComponent(<MyApp />, document.body);
seen here as a JSBin
You're using defaultValue - that makes the input an uncontrolled component, which gets an initial value set but whose displayed value is never touched again by React unless you blow the whole component away (e.g. with a key change on it or an ancestor) and it has to recreate it from scratch.
That's why you don't see the new defaultValue being displayed - because there are no unique keys on each row, React finds there's one fewer row on re-render and removes the last row from the real DOM, but any new defaultValue for inputs in a retained row has no effect..
Here's the same code but using value, which makes it a controlled component, which reflects the new value it gets on re-render:
http://jsbin.com/hacitidaqe/1/