Reputation: 157
I'm trying to make onClick effect on every item of .map method like this:
this.props.products.map(function(item, i) {
return (
<tr key={ i } onClick={ function() {
console.log(arrayForOnClick)
arrayForOnClick = [item['id'], item['name'], item['price']]
this.handleTableString(item['id'], item['name'], item['price'])
// Нужно передать айди, имя и цену в модальное окно при клике на этот <tr>.
} }>
<td>{ item['id'] }</td>
<td>{ item['name'] }</td>
<td>{ item['price'] }</td>
</tr>
)
}, this)
And I'm trying to access this.handleTableString which is
handleTableString(id, name, price) {
this.setState({
editProductModal: true,
selectedId: id,
selectedName: name,
selectedPrice: price
})
console.log('triggered')
}
But I get error Uncaught TypeError: Cannot read property 'handleTableString' of null
Is there another way to make that onClick or something is wrong with my code?
Upvotes: 0
Views: 858
Reputation: 3199
In JavaScript this
inside function can be bound to god-know-what, depending on how it was called. In your code this
in line this.handleTableString(item['id'], ...
is not pointing to the component.
Use ES6 arrow functions as your handlers both for map
and onClick
or use this-that trick in case you forced to use ES5 syntax and can't/don't want to use transpilers (Babel, obviously).
Upvotes: 0
Reputation: 8055
The problem is that this
is null inside your onClick
inline function. So you need to assign onClick
to a function that this
has been explicitly set using javascript bind
method.
<tr key={ i } onClick={
function() {
console.log(arrayForOnClick)
arrayForOnClick = [item['id'], item['name'], item['price']]
this.handleTableString(item['id'], item['name'], item['price'])
}.bind(this)
}>
...
</tr>
Upvotes: 0
Reputation: 3883
The problem is that this
is different for each function
(it is not preserved for your nested function). You may.
this
..
this.props.products.map(function(item, i) {
const self = this;
return (
<tr key={ i } onClick={ function() {
console.log(arrayForOnClick)
arrayForOnClick = [item['id'], item['name'], item['price']]
self.handleTableString(item['id'], item['name'], item['price'])
// Нужно передать айди, имя и цену в модальное окно при клике на этот <tr>.
} }>
<td>{ item['id'] }</td>
<td>{ item['name'] }</td>
<td>{ item['price'] }</td>
</tr>
)
}, this)
this
, so it is looked up in parent context..
this.props.products.map(function(item, i) {
return (
<tr key={ i } onClick={ () => {
console.log(arrayForOnClick)
arrayForOnClick = [item['id'], item['name'], item['price']]
this.handleTableString(item['id'], item['name'], item['price'])
// Нужно передать айди, имя и цену в модальное окно при клике на этот <tr>.
} }>
<td>{ item['id'] }</td>
<td>{ item['name'] }</td>
<td>{ item['price'] }</td>
</tr>
)
}, this)
Upvotes: 1
Reputation: 193261
Don't create anonymous function like you are doing without binding context properly. It's cleaner to use arrow function in this case too:
this.props.products.map(function(item, i) {
return (
<tr key={ i } onClick={() => {
const arrayForOnClick = [item['id'], item['name'], item['price']]
this.handleTableString(item['id'], item['name'], item['price'])
} }>
<td>{ item['id'] }</td>
<td>{ item['name'] }</td>
<td>{ item['price'] }</td>
</tr>
)
}, this)
Upvotes: 0