How to copy HTML to clipboard using react hooks? - javascript

I have a section that has a table now I want the user to be able to copy the HTML code of the table to the clipboard.
Here is my solution on code sandbox : live demo
Js code below
import React, { useState, useRef } from "react";
export default function App() {
const tableRef = useRef(null);
const [copySuccess, setCopySuccess] = useState("");
const copyToClipboard = (e) => {
const code =tableRef.current.innerHTML;
console.log('code', code);
document.execCommand("copy");
e.target.focus();
setCopySuccess("Copied!");
};
return (
<div className="App">
<div ref={tableRef} className="table">
<table>
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
</tbody>
</table>
</div>
{document.queryCommandSupported("copy") && (
<div>
<button onClick={copyToClipboard}>Copy</button>
{copySuccess}
</div>
)}
</div>
);
}
Unfortunately, this is not copying the HTML code.
What do I need to change to be able to copy HTML to the clipboard.?
What is wrong here?

The problem is it copies selected/highlighted text to the clipboard so you just need to do that programmatically before running execCommand.
Add a hidden input (set invisible and position absolute/off-screen)
In copy function, set the value of that input to the html
select the hidden input with the select event
execCommand(‘copy’);
EDIT
It might work with an input type of hidden or setting display: none; but I vaguely remember this blocking the select event when I did this a few years back.

Related

How to create a table with user input?

I'm a newbie in development, so any help is welcome :)
Here's my Problem:
I'm using next.js - this might be important, because f.ex. document.createElement seem only work with useEffect.
I created a text area, where users add words separated with a comma (f.ex. "Nike, Adidas, New Balance"). I want to rewrite the existing code below, so that:
table is only visible/appears, when a user adds something in the inputbox
each word from the inputbox (f.ex. Nike, Adidas) creates a new row in the table (in table head "Brand").
By now, I was trying to use the .split and .forEach method to create a new Element(table). But I just can't make it work - maybe it's just not the right solution. Any help is welcome!
function Analyzer() {
const [brand, setBrand] = React.useState('');
const handleChange = (event) => {
setBrand(event.target.value.split(','))};
return(
<div>
<textarea type="text"
placeholder="Example:
Nike, Adidas, New Balance ..."
onChange={handleChange}></textarea>
<table className={styles.table}>
<thead>
<tr>
<th>No.</th>
<th>Brand</th>
<th>Also known as</th>
<th>Avg. price</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>{brand}</td>
<td></td>
<td><input type= "number"></input>%</td>
</tr>
</tbody>
</table>
</div>);
}
Try something like the following. What I did was extract the Table component out and put any conditions for its rendering within it. You can even create a separate file for this component and pass any relevant props to it.
Secondly, I am putting the list of brands into state as brands within the handleChange function. This state variable is then iterated over using .map to render each row in the table.
function Analyzer() {
const [brands, setBrands] = React.useState([]);
const handleChange = ({ target }) => {
const { value } = target;
setBrands(value.split(','));
};
const Table = () => {
if (!brands || brands.length === 0) return null;
return (
<table className={styles.table}>
<thead>
<tr>
<th>No.</th>
<th>Brand</th>
<th>Also known as</th>
<th>Avg. price</th>
</tr>
</thead>
<tbody>
{brands.map((brand) => (
<tr>
<td>1</td>
<td>{brand}</td>
<td></td>
<td><input type= "number"></input>%</td>
</tr>
)}
</tbody>
</table>
);
};
return(
<div>
<input
onChange={handleChange}
placeholder="Example: Nike, Adidas, New Balance ..."
type="text"
value={brands}
/>
<Table />
</div>
);
};

How to get the change text of <th> of the html the table React js

I want to change the value of table at the runtime, means user can change table header or table rows value manually.
I used contentEditable to change the table data directly by the user from the table, by I am unable to get the change input by the user, and always get old text which shown in the table,how can I get the updated value of table in ReactJs
<table
id="mytable"
className="table table-striped table-nowrap dataTable"
cellSpacing="0"
width="100%"
>
<thead>
<tr>
{this.state.colarray.map((coldata, ind) => {
return (
<th key={ind} onChange={this.colchange}>
<div contentEditable>{coldata}</div>
</th>
);
})}
</tr>
</thead>
<tbody>
{console.log("rows", this.state.rowarray)}
{this.state.rowarray.map((rowdata, ind) => {
return (
<tr id="somerow">
{this.state.colarray.map((col, index) => {
return (
<td>
<div contentEditable>{rowdata["item" + index]}</div>
</td>
);
})}
</tr>
);
})}
</tbody>
</table>
<button onClick={this.show}>button</button>
When the user clicks the button.show() function works, where I am trying to get the updated value but it always show old data of table,I have also used onChange event table header <th> trying to get the value but it also not works even the colchange is not called when I change in <th>.I want updated input which is entered by user on table how can I get?

Why the key is not shown in the HTML rendered page?

I've written the following code:
const TableRow = ({row, i}) => (
<tr key={row.barcode}>
<td>{i}</td>
<td>{row.name}</td>
<td>{row.description}</td>
<td>{row.brand}</td>
<td>{row.barcode}</td>
</tr>
);
that is called in another component render() function that is
var table = (<Table striped bordered condensed hover>
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
{
this.state.products.map((row, i) =>
<TableRow row={row} id={i}/>
)
}
</tbody>
</Table>);
return table;
The problem is that in the rendered HTML all the <td> tags don't have any key property so
<tr>
<td></td>
<td>NAME</td>
<td>DESCR</td>
<td>NDARB</td>
<td>800800800</td>
</tr>
without any key property.
Keys help React identify which items have changed, are added, or are removed.
Keys are used internally and are never rendered in DOM. If you want to use it as an identifier, use id attribute in addition.
Ref: https://reactjs.org/docs/lists-and-keys.html#keys
That's because Key is a React property.
From the React docs:
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity
They are not rendered into the actual DOM, they are only used internally.

My table isn't working correctly between two communicating files

I have two files that make a table, one file is the table header, one is the table body. The table body isn't displaying correctly. The table header is fine, but I'm trying to import the code from the second file into the table header. It appears but it is not appearing in the table format, it only shows up as a single string.
Note: These two component files are children to a separate container file as well, but I don't think the problem stems from that so I left it out.
Second Note: Also, as an intern with not too much experience, I apologize if this is simple ignorance. I tried googling it and the like, but couldn't find anything similar to my particular issue.
Here is my code.
File 1 (The Table Header):
import React, { Component } from 'react';
import Body from '../../components/prior-auth/Body';
class OrderHistory extends Component {
render() {
return (
<div>
<h1>Order History</h1>
<div>
<table className="table table-hover table-responsive">
<thead>
<tr>
<th>#</th>
<th>Service</th>
<th>Provider</th>
<th>Client Preference</th>
<th>Max Units</th>
<th>Max Cost</th>
<th>Brokered Date</th>
<th>Begin Date</th>
<th>End Date</th>
<th>Reason</th>
</tr>
</thead>
<Body/>
</table>
</div>
</div>
)
}
}
export default OrderHistory;
File 2 (The Table Body):
import React, { Component } from 'react';
class Body extends Component {
render () {
return(
<table class="table table-hover table-responsive">
<tbody>
<tr>
<th scope="row">1</th>
<td>a</td>
<td>b</td>
<td>c</td>
<td>d</td>
<td>e</td>
<td>f</td>
<td>g</td>
<td>h</td>
<td>i</td>
</tr>
</tbody>
</table>
)
}
}
export default Body;
I don't know how to show the whole output, so here's the part that's wrong:
The "1" describing the row, and the letters being example placeholders for the data going into each column.
1abcdefghi

React-router: Using <Link> as clickable data table row

I'm new to using ReactJS and react-router. I want a clickable table row and something like the following setup:
<Link to=“#”>
<tr>
<td>{this.props.whatever1}</td>
<td>{this.props.whatever2}</td>
<td>{this.props.whatever3}</td>
</tr>
</Link>
but I know you can't put <a> tags between the <tbody> and <tr> tags. How else can I accomplish this?
PS: I prefer not to use jQuery if possible.
onClick works, but sometimes you need an actual <a> tag for various reasons:
Accessibility
Progressive enhancement (if script is throwing an error, links still work)
Ability to open a link in new tab
Ability to copy the link
Here's an example of a Td component that accepts to prop:
import React from 'react';
import { Link } from 'react-router-dom';
export default function Td({ children, to }) {
// Conditionally wrapping content into a link
const ContentTag = to ? Link : 'div';
return (
<td>
<ContentTag to={to}>{children}</ContentTag>
</td>
);
}
Then use the component like this:
const users = this.props.users.map((user) =>
<tr key={user.id}>
<Td to={`/users/${user.id}/edit`}>{user.name}</Td>
<Td to={`/users/${user.id}/edit`}>{user.email}</Td>
<Td to={`/users/${user.id}/edit`}>{user.username}</Td>
</tr>
);
Yes, you'll have to pass to prop multiple times, but at the same you have more control over the clickable areas and you may have other interactive elements in the table, like checkboxes.
Why don't you just use onClick?
var ReactTable = React.createClass({
handleClick: function(e) {
this.router.transitionTo('index');
},
render: function() {
return(
<div>
<table>
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Full Detail</th>
</tr>
</thead>
<tbody>
<tr onClick={this.handleClick.bind(this)}>
<td>{user.name}</td>
<td>{user.age}</td>
<td>{details}</td>
</tr>
</tbody>
</table>
</div>
);
}
});
This answers is based on #Igor Barbasin suggestion. This will add the link to the whole row instead of just the content and we also don't need to wrap all the individual 'td' element with 'Link'.
.table-row {
display: table-row
}
export default function Table() {
return (
<table>
<thead>
<tr>
<th>Name</th>
</tr>
</thead>
<tbody>
{/* treats the link element as a table row element */}
<Link className="table-row">
<td>Noname</td>
</Link>
</tbody>
</table>
)
}
You can use useHistory() hook:
Declare:
const history = useHistory();
and use it with <tr> or <td> tag:
<tr onClick={() => history.push("/yoururl")}>
<td>{this.props.whatever1}</td>
<td>{this.props.whatever2}</td>
<td>{this.props.whatever3}</td>
</tr>
{shipment.assets.map((i, index) => (
<tr
style={{ cursor: "pointer" }}
onClick={(e) => e.preventDefault()}
>
<td>{index + 1}</td>
<td>{i._id}</td>
<td>{i.status}</td>
<td></td>
</tr>
))}

Categories

Resources