tk003
tk003

Reputation: 31

Material-ui & TouchTap: Getting key of ListItem

I have a list of items using material-ui. I would like to call _handleTouchTap() when the item is clicked and pass the key of the ListItem to the handler.

Adding

onTouchTap={this._handleTouchTap}

to is not working as 'this' seems the be the wrong scope

var React = require('react');
var Mui = require('material-ui');
var ThemeManager = new Mui.Styles.ThemeManager();
ThemeManager.setTheme(ThemeManager.types.LIGHT);
var injectTapEventPlugin = require('react-tap-event-plugin');
injectTapEventPlugin();
var List = Mui.List
var ListItem = Mui.ListItem

var Main = React.createClass({
  childContextTypes: {
    muiTheme: React.PropTypes.object
  },
  getChildContext: function () {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    }
  },
  render: function() {
    var items = [
      {id: 1, title: 'Item 1'},
      {id: 2, title: 'Item 2'},
      {id: 3, title: 'Item 3'}
    ]
    return (
        <List>
          {items.map(function(item){
            return <ListItem key={item.id} primaryText={item.title} />
          })}
        </List>
    )
  },

  _handleTouchTap: function() {
    // the key of the item should be passed though here
  }
});

React.render(<Main />, document.body);

Upvotes: 3

Views: 14642

Answers (4)

A.V.D. Kishore
A.V.D. Kishore

Reputation: 180

If you want to use the newer ES6 class syntax and arrow function, this could be the answer. You need to explicitly bind the this keyword if you are using class syntax to correctly specify the this context. onTouchTap expects a method, so I'm returning a function using ES6 arrow function.

import { Component, React } from 'react';
import { List, ListItem } from 'material-ui/List';
class Main extends Component {

   constructor() {
      super(...arguments);
      this._handleTouchTap = this._handleTouchTap.bind(this);
   }

   _handleTouchTap(id) {
       return () => console.log(id) // Logs item id
   }

   render () {        
      var items = [
         {id: 1, title: 'Item 1'},
         {id: 2, title: 'Item 2'},
         {id: 3, title: 'Item 3'}
       ];

       return (
           <List>
             {items.map(function(item){
               return (
                  <ListItem 
                     key={item.id} 
                     primaryText={item.title} 
                     onTouchTap={this._handleTouchTap(item.id)}
                   />
                )
             })}
           </List>
       );
    }
}

Upvotes: 1

CaseyC
CaseyC

Reputation: 1482

If event.target.id isn't working due to concerns that Tim Welch pointed out above, you can simply pass the item ID as a parameter to your handler function

render: function() {
        var items = [
          {id: 1, title: 'Item 1'},
          {id: 2, title: 'Item 2'},
          {id: 3, title: 'Item 3'}
        ]
        return (
            <List>
              {items.map(function(item){
                return <ListItem key={item.id} 
                                 primaryText={item.title} 
                                 onTouchTap={this._handleTouchTap.bind(this, item.id)}/>
              })}
            </List>
        )
      },

      _handleTouchTap: function(id) {
        console.log(id) // Logs item id
      }
});

Instead of using onTouchTap={this._handleTouchTap.bind(this, item.id)}, if you're using es6 you can instead use an es6 fat arrow function which will automatically bind this for you. It can be done like this: onTouchTap={() => this._handleTouchTap(item.id)}

Upvotes: 7

Tim Welch
Tim Welch

Reputation: 41

Sharing what I learned. Take a look at the MakeSelectable higher-order component that Material-UI offers for creating a selectable List that gives you the index of the currently selected item onChange. This might be new since the question was asked. Note the value attribute on the ListItem's below and the onChange event on the SelectableList.

import {List, ListItem, MakeSelectable} from 'material-ui/List'
SelectableList = MakeSelectable(List)

const siteItems = Object.keys(sites || {}).map((index) => {
  const site = sites[index]
  return (<ListItem
    key={index + 1}
    value={site.id}
    leftAvatar={<Avatar icon={<PinDrop />} />}
    primaryText={site.name}
    secondaryText={site.description}
    style={styles.list}
  />)
})
CurList = (
  <div style={styles.listcontainer}>
    <SelectableList onChange={this.siteSelected}>
      {siteItems}
    </SelectableList>
  </div>
)

The problem I found with pattern of setting the id of the listitem and trying to access it via event.target.id is that event.target will vary if you have sub-elements in your List item like icons, labels, etc. which most of the List examples have.

Upvotes: 1

gaga
gaga

Reputation: 1

you have to set the listitem onTouchTap prop and set event to handleTouchTap parameter

<ListItem onTouchTap={this._handleTouchTap} />

_handleTouchTap: function(event){
  var clickedID = event.target.id
}

Upvotes: 0

Related Questions