0

While looping over an object using map() React can't find its own classes property!

Here is the class of the component,

import React, { Component } from 'react';
import './videolists.css';

export default class VideoLists extends Component {

  constructor() {
    super();
  }

  getDefaultLists() {
    return [
      {
        title: 'Iridescent (Official Video) - Linkin Park',
        url: 'https://www.youtube.com/watch?v=xLYiIBCN9ec',
        id: 'xLYiIBCN9ec' 
      },
      {
        title: 'Ed Sheeran - I\'m A Mess (x Acoustic Sessions)',
        url: 'https://www.youtube.com/watch?v=-t2CR9qZRj0',
        id: '-t2CR9qZRj0' 
      },
      {
        title: 'Ed Sheeran - Lego House [Official Video]',
        url: 'https://www.youtube.com/watch?v=c4BLVznuWnU',
        id: 'c4BLVznuWnU' 
      }
    ]
  }

  itemSelected(itemObject) {
    console.log(itemObject);
  }

  render() {
    return (
      <div>
        <div className='panel panel-default'>
          <div className='panel-heading'>

            <ul className='list-group'>
              {this.getDefaultLists().map(function(item, index){
                return <li 
                          key = { index } 
                          className='list-group-item'
                          onClick={ this.itemSelected.bind(this) }>
                          { item.title } <br/>
                          <small className='listurl'>{ item.url }</small>
                      </li>; 
              })}
            </ul>

          </div>
        </div>
      </div>
    );
  }

}

When a user would click on an item it should call the function called itemSelected and also binding the current this element with this.

But when the application is throughing and error.

Here is the error message:

Uncaught TypeError: Cannot read property 'itemSelected' of undefined(…)

How I can call this function in this case from the loop?

rakibtg
  • 5,521
  • 11
  • 50
  • 73

1 Answers1

2

you are losing the this context because of your map function. not only do you need to bind that, to get the data object sent though you need to actually tell it to do that. like this.

<ul className='list-group'>
    {this.getDefaultLists().map( (item, index) => {
        return (
            <li key ={index} className='list-group-item' onClick={() => this.itemSelected(item)}>
                { item.title }
                <br/>
                <small className='listurl'>{ item.url }</small>
            </li>
         ); 
    })}
</ul>

you can try shadowing your this context, shouldn't be necessary, but worth a shot.

const self = this;
...
<ul className='list-group'>
    {self.getDefaultLists().map( (item, index) => {
        return (
            <li key ={index} className='list-group-item' onClick={() => self.itemSelected(item)}>
                { item.title }
                <br/>
                <small className='listurl'>{ item.url }</small>
            </li>
         ); 
    })}
</ul>
John Ruddell
  • 25,283
  • 6
  • 57
  • 86
  • Thanks, but when i click same error occurs: `VideoLists.js:100 Uncaught TypeError: Cannot read property 'itemSelected' of undefined(…)` – rakibtg Nov 17 '16 at 09:16
  • how're you building this? fat arrow functions bind your this context. so you shouldn't need to shadow your this – John Ruddell Nov 17 '16 at 09:18