react use Link on entire tr failed - reactjs

<tbody>
{map(items, item =>
<Link to={routeUrl(ROUTES.SOMEWHERE, item.id)}>
<tr key={item.id}>
<td>
{item.name}
</td>
<td>
{item.country}
</td>
</tr>
</Link>
)}
</tbody>
This won't work, any clue why? I can put the Link component within the td but I want the entire row to be clickable.

According to JSX rules, a Link component should contain only a string and not another component. Instead of using Link you can add onClick method on tr component and then you can define the route where you want to go in the body of onClick.

Related

unique key prop error even with unique key on table row

I am not sure how to correct this issue. I am using a unique ID but react still isn't happy. I tried to do it on each but then it complains about duplicates.
<table>
<tbody>
{!loading &&
products &&
products.map((product) => (
<>
<tr>
<td key={product._id}>{product.name}</td>
<td>
<span>
<strong>{product.desc}</strong>
</span>
</td>
</tr>
</>
))}
</tbody>
</table>
You must put the key in the upper most component: the Fragment. So instead of <> use <React.Fragment key={...}>
or instead of handling the key by yourself, maybe let React handle it for you. I find it pretty handy:
<table>
<tbody>
{
!loading && products && React.Children.toArray(
products.map((product) => (
<tr>
<td>{product.name}</td>
<td>
<span>
<strong>{product.desc}</strong>
</span>
</td>
</tr>
))
)
}
</tbody>
</table>
so you'll never have to worry about assigning keys anymore!
React.Children.toArray
Returns the children opaque data structure as a flat array with keys assigned to each child. Useful if you want to manipulate collections of children in your render methods, especially if you want to reorder or slice this.props.children before passing it down.
Official documentation: https://reactjs.org/docs/react-api.html#reactchildrentoarray

Can't Pass A Parameter for Datatable in Modal React JS

I have a datatable where it pops up a modal window if you select a row. I would like the modal window to display only a datatable of the selected row with additional details. However, passing in the selected row's ID for the modal window seems to not work and I don't know why? Or I'm not sure what is a better way to display information in a modal window?
**EDIT: I have discovered that if I replace this.state.TicketID with t and have t=0 then it also works so it must be something to do with calling this.state.TicketID within the x[]?
const {id, created} = t
})
return (
<div>
<Modal isOpen={this.state.modal} toggle={this.toggleModal} className={this.props.className}>
<ModalHeader toggle={this.toggleModal}>Selected Item </ModalHeader>
<ModalBody>
<Datatable>
<table className="table table-striped my-4 w-100">
<thead>
<tr>
<td>Ticket ID</td>
<td>Created On</td>
</tr>
</thead>
<tbody>
<tr key={this.state.TicketID}>
<td>{this.state.x[this.state.TicketID].id}</td>
<td>{this.state.x[this.state.TicketID].created}</td>
</tr>
</tbody>
</table>
</Datatable>
</ModalBody>
</Modal>
</div>
);
}
TicketID is set in an outer function and is kept in the state object. It is updating as expected. I noticed if I do console.log({this.state.x[0].id}) then it works. However, if I do console.log({this.state.x[this.state.TicketID].id}), it gives an Cannot read property 'id' of undefined. Any help or new suggestions would be appreciated!
actually for the current use case you don't even need a modal level state, so you just make the modal component as pure component(normal js function) and pass the values as props!
// pass these form the parent components
const {isOpend , onToggle, ticket:{id,created} ={}}= props // or from `currentActiveTicket` as described below
// if you mounting the modal element on the same datatable level
// and you only change the state of the parent component
// when a row is clicked you can add the `currentActiveTicket` as an object
// value of what you want to display on the modal(make sense)
})
return (
<div>
<Modal isOpen={isOpend} toggle={onToggle} className={this.props.className}>
<ModalHeader toggle={this.toggleModal}>Selected Item </ModalHeader>
<ModalBody>
<Datatable>
<table className="table table-striped my-4 w-100">
<thead>
<tr>
<td>Ticket ID</td>
<td>Created On</td>
</tr>
</thead>
<tbody>
<tr key={id}>
<td>{id}</td>
<td>{created}</td>
</tr>
</tbody>
</table>
</Datatable>
</ModalBody>
</Modal>
</div>
);
}
or you have to maintain the props changing and reflect that on the modal state
for Example I have fallen into this kind of issues because I wasn't understanding these concepts well enough - componentDidUpdate check the references on this

Links to external resource are empty in React

In a React app I have a Table tbody of which looks the following way:
<tbody>
{
this.state.datasets.map((datasetName, idx) => {
return (<tr>
<td>
<div className={"pretty p-default p-curve"}>
<input id = {"datasetCheckBox" + idx}
checked = {this.state.checkBoxSelected === datasetName}
type="radio" name="datasetName"
onChange={(e) => this.checkBoxSelected(datasetName, e)}/>
<div className={"state p-primary"}>
<label>{idx}</label>
</div>
</div>
</td>
<td>{datasetName}</td>
<td>{datasetsJSON["datasets"][datasetName]["region"]}</td>
<td>{datasetsJSON["datasets"][datasetName]["authors"]}</td>
<td>
<a href={datasetsJSON["datasets"][datasetName]["link"]}>{datasetName}</a>
</td>
</tr>)
}, this)
}
</tbody>
The link is shown with an empty href even though other parameters of the table from datasetsJSON["datasets"][datasetName] are set correctly. I tried using React Router and the only piece of code that redirected to links is in the answer here:
React-Router External link
But in the answer to the question above if I set path="/", when the table loads, it is just redirecting me straight away to the first link. I would expect then that for each link the path should be different, but supplying datasetsJSON["datasets"][datasetName]["link"] as a path does not work either. Why is the simple link a empty? How could I fix it?
I solved it by using onClick method instead of href link attribute. In the table I have:
<td onClick = {() => this.articleClicked(datasetName)}>
<span role="button"><a>{datasetName}</a></span>
</td>
Then, onClick method:
articleClicked = (datasetName) => {
let url = datasetsJSON["datasets"][datasetName]["link"];
window.open(url);
}
<span role="button"> is needed for the cursor to show hand when the user is hovering over the link. It is bootstrap thing.

Ng-repeat - What is the right syntax to send the user to its dynamic id?

So, in my object index I'm working inside a ng-repeat.
Now, when I click on an object, it should go to its matching id.
How would I do this with Angular?
I got something like this now:
<tr ng-repeat="dossier in dossiers">
<td>
#{{dossier.license_plate}}
</td>
</tr>
Why don't you try ngHref directive
<tr ng-repeat="dossier in dossiers">
<td>
<a ng-href="/dossiers/{{dossier.id}}">#{{dossier.license_plate}}</a>
</td>
<a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
https://docs.angularjs.org/api/ng/directive/ngHref

How to correctly wrap few TD tags for JSXTransformer?

I have an array with items and I want to make something like this:
<tr>
(until have items in array
<td></td><td></td>)
</tr>
But if I do that, I get an JSXTransformer error :
Adjacent XJS elements must be wrapped in an enclosing tag
Working version:
{rows.map(function (rowElement){
return (<tr key={trKey++}>
<td className='info' key={td1stKey++}>{rowElement.row[0].value}</td><td key={td2ndKey++}>{rowElement.row[0].count}</td>
<td className='info' key={td1stKey++}>{rowElement.row[1].value}</td><td key={td2ndKey++}>{rowElement.row[1].count}</td>
<td className='info' key={td1stKey++}>{rowElement.row[2].value}</td><td key={td2ndKey++}>{rowElement.row[2].count}</td>
<td className='info' key={td1stKey++}>{rowElement.row[3].value}</td><td key={td2ndKey++}>{rowElement.row[3].count}</td>
<td className='info' key={td1stKey++}>{rowElement.row[4].value}</td><td key={td2ndKey++}>{rowElement.row[4].count}</td>
.......
</tr>);
})}
I tried this one. But with <div> enclosing tag it doesn't work fine.
Answer here:
Uncaught Error: Invariant Violation: findComponentRoot(..., ...$110): Unable to find element. This probably means the DOM was unexpectedly mutated
<tbody>
{rows.map(function (rowElement){
return (<tr key={trKey++}>
{rowElement.row.map(function(ball){
console.log('trKey:'+trKey+' td1stKey'+td1stKey+' ball.value:'+ball.value+' td2ndKey:'+td2ndKey+' ball.count:'+ball.count);
return(<div key={divKey++}>
<td className='info' key={td1stKey++}>{ball.value}</td><td key={td2ndKey++}>{ball.count}</td>
</div>);
})}
</tr>);
})}
</tbody>
Please, advise me how to properly wrap few TD tags!
I tried use a guide Dynamic Children, but JSXTransformer doesn't allow me do that.
The following error usually occurs when you are returning multiple elements without a wrapping element
Adjacent XJS elements must be wrapped in an enclosing tag
Like
return (
<li></li>
<li></li>
);
This doesn't work because you are effectively returning two results, you need to only ever be returning one DOM node (with or without children) like
return (
<ul>
<li></li>
<li></li>
</ul>
);
// or
return (<ul>
{items.map(function (item) {
return [<li></li>, <li></li>];
})}
</ul>);
For me to properly answer your question could you please provide a JSFiddle? I tried to guess what you're trying to do and heres a JSFiddle of it working.
When using the div as a wrapper its actually never rendered to the DOM (not sure why).
<tr data-reactid=".0.0.$1">
<td class="info" data-reactid=".0.0.$1.$0.0">1</td>
<td data-reactid=".0.0.$1.$0.1">2</td>
<td class="info" data-reactid=".0.0.$1.$1.0">1</td>
<td data-reactid=".0.0.$1.$1.1">2</td>
<td class="info" data-reactid=".0.0.$1.$2.0">1</td>
<td data-reactid=".0.0.$1.$2.1">2</td>
<td class="info" data-reactid=".0.0.$1.$3.0">1</td>
<td data-reactid=".0.0.$1.$3.1">2</td>
</tr>
EDIT: React 16+
Since React 16 you can now use fragments.
You would do it like this now
return <>
<li></li>
<li></li>
<>;
Or you can use <React.Fragment>, <> is shorthand for a HTML fragment, which basically is just a temporary parent element that acts as a container, once its appended to the document it no longer exists.
https://reactjs.org/docs/fragments.html
https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
So you have pairs of <td> elements which you want to return from a .map. The easiest way to do this is to just wrap them in an array.
<tr>
{data.map(function(x, i){
return [
<td>{x[0]}</td>,
<td>{x[1]}</td>
];
})}
</tr>
Don't forget the comma after the first </td>.
With the release of React 16, there is a new component called Fragment.
If are would like to return a collection of elements/components without having to wrap them in an enclosing element, you can use a Fragment like so:
import { Component, Fragment } from 'react';
class Foo extends Component {
render() {
return (
<Fragment>
<div>Hello</div
<div>Stack</div>
<div>Overflow</div>
</Fragment>
);
}
}
Here is how you will do it
<tbody>
{this.props.rows.map((row, i) =>
<tr key={i}>
{row.map((col, j) =>
<td key={j}>{col}</td>
)}
</tr>
)}
</tbody>

Resources