abbob1
abbob1

Reputation: 143

React native card (native base) onPress doesn't work

I want to display cards with news from a JSON file. Getting the JSON works fine, but I want to add a onPress event, so I can click the card and navigate to the article.

My card view:

<Card>
  <CardItem button onPress={this._OnButtonPress(news.id)}>
    <Left>
      <Body>
        <Text style={styles.cardText}>{news.title}</Text>
      </Body>
    </Left>
  </CardItem>
  <CardItem>
    <Left>
        <Icon style={styles.icon} name="chatbubbles" />
        <Text>{news.comments} comments</Text>
    </Left>
    <Right>
      <Text>{news.published}</Text>
    </Right>
  </CardItem>
</Card>

I am trying to pass a variable to the onButtonPress() function

_OnButtonPress(newsID) {
  Alert.alert(newsID.toString());
}

To test the onPress event, all I did is alert the parameter.

I don't see anything wrong, but still I got this error

Does anyone know how I can fix this and what Im doing wrong here. Thanks in advance.

Update

My updated class:

import React, { Component } from "react";
import {
  Image,
  ListView,
  StyleSheet,
  Text,
  View,
  Alert
} from 'react-native';

import {
  Container,
  Header,
  Left,
  Right,
  Button,
  Card,
  CardItem,
  Icon,
  Body,
  Content,
  Logo
} from 'native-base';

import styles from "./styles";

const logo = require("../../../img/f1today.png");

var REQUEST_URL = 'http://v2.first-place.nl/test/news.json';

class News extends Component {
  constructor(props) {
    super(props);

    this._OnButtonPress = this._OnButtonPress.bind(this);

    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  }

  _OnButtonPress(newsID) {
    Alert.alert(newsID.toString());
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    fetch(REQUEST_URL)
      .then((response) => response.json())
      .then((responseData) => {
        this.setState({
          dataSource: this.state.dataSource.cloneWithRows(responseData.articles),
          loaded: true,
        });
      })
      .done();
  }

  render() {

    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <Container style={styles.container}>
        <Header
          style={{ backgroundColor: "#fff" }}
          androidStatusBarColor="#f05423"
          iosBarStyle="light-content">

        <Left>
          <Button
            transparent
            onPress={() => this.props.navigation.navigate("DrawerOpen")}
          >
            <Icon name="ios-menu" style={{color: 'black'}} />
          </Button>
        </Left>
        <Body> 
          <Image source={logo} style={styles.headerLogo} />
        </Body>
        <Right />

      </Header>

      <Content padder>

        <ListView
          dataSource={this.state.dataSource}
          renderRow={this.renderNews}
          style={styles.listView}
        />

      </Content>
    </Container>
    );
  }

  renderLoadingView() {
    return (
      <View style={styles.loading}>
        <Text>
          Loading news...
        </Text>
      </View>
    );
  }

  renderNews(news) {
    return (
      <Card>
        <CardItem button onPress={()=> this._OnButtonPress(news.id)}>
          <Left>
            <Body>
              <Text style={styles.cardText}>{news.title}</Text>
            </Body>
          </Left>
        </CardItem>
        <CardItem>
          <Left>
              <Icon style={styles.icon} name="chatbubbles" />
              <Text>{news.comments} comments</Text>
          </Left>
          <Right>
            <Text>{news.published}</Text>
          </Right>
        </CardItem>
      </Card>
    );
  }
}

export default News;

Upvotes: 7

Views: 16348

Answers (4)

burakkesepara
burakkesepara

Reputation: 316

You should wrap your CardItem with TouchableOpacity or any other Touchable item. And give onPress function to that Touchable item.

<TouchableOpacity onPress={() => //your function}
    <CardItem>
    </CardItem>
</TouchableOpacity>

Note: Make sure you use the <TouchableOpacity> component associated with the react-native package rather than the react-native-gesture-handler package. Visual Studio Code editor may auto-import from react-native-gesture-handler which does not work in this particular use case.

Correct Package:

import { TouchableOpacity } from 'react-native';

Incorrect Package:

import { TouchableOpacity } from 'react-native-gesture-handler';

Upvotes: 12

sonic_ninja
sonic_ninja

Reputation: 728

For me i left the button={true} prop off, when i added it works. See example below.

  <CardItem 
       button={true}
       onPress={() => {this.cardSelected(item.name)}}
       style={{paddingTop:0,paddingBottom:0,paddingLeft:0,paddingRight:0}}>
      <Image  source={item.img} style={{flex:1,resizeMode: 'cover',height: 175}} />
      <Text style={styles.cardheading}>{item.name}</Text>
        <Image source={cardline} style={styles.cardline}/>
        <Text style={styles.cardtext}> {item.text}</Text>

      </CardItem>

Upvotes: 4

EnriqueDev
EnriqueDev

Reputation: 1247

The problem you are having is that the method cannot access the scope of the view. Right now you have your renderNews method defined this way:

renderNews(news) { }

If you declare your method this way you will not have this available on your method and as "this" is undefined, all the methods will trigger an error because you are trying to access to "undefined.methodName()". Having said that, you should "tie" the context to your method declaring it this way:

renderNews = (news) => { }

Now you have the context attached to the method and "this" is accesible inside.

Upvotes: 1

Rohan Kangale
Rohan Kangale

Reputation: 971

You need to bind this function. Write the following code inside your constructor function:

this._OnButtonPress = this._OnButtonPress.bind(this);

Also, changed the onPress as following:

onPress={()=> this._OnButtonPress(news.title)}

Finally, i could see the onPress been written on the component. Rather you should define/write it inside that container.

Upvotes: 1

Related Questions