Cannot extract any attribute from JSON array - react-native

export default class Home extends Component{
constructor(){
super();
const ds = new ListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2})
this.state={
userDataSource:ds,
}
}
componentDidMount(){
fetch('http://192.168.0.102/giftbaenew/rest/V1/products?searchCriteria[filter_groups][0][filters][0][field]=category_id&searchCriteria[filter_groups][0][filters][0][value]=10',{
headers:{
'Authorization':'Bearer 7dmc9lprh5b1t07hkadyhmtb6etm1jaj'
}
})
.then((response)=>{return response.json()})
.then((responseData)=>{
alert(responseData) // i get the alert message.
this.setState({
userDataSource:this.state.userDataSource.cloneWithRows(responseData)
})
})
}
renderRow(user,sectionId,rowId,highlightRow){
const data=this.state.userDataSource
return(
<View >
<Text style={{color:'black'}}>
{data.items[0].name} //error
</Text>
</View>
)
}
render(){
return(
<ScrollView>
<View>
<View style={styles.container}>
<TouchableOpacity onPress={()=>{this.props.navigation.navigate('Login')}}>
{/* <Text style={{textAlign:'right',marginTop:5,color:'white',fontSize:16}}>Logout</Text> */}
<Image source={require('../Images/logout.png')} style={{width:30,height:30,marginLeft:325}}/>
</TouchableOpacity>
<Text style={styles.text}>
ShakeHands
</Text>
<TextInput placeholder='Search' placeholderTextColor='black' style={{backgroundColor:'white',marginTop:13,height:35,width:320,marginLeft:20,marginRight:20,padding:10}}/>
</View>
<View style={{marginTop:10}}>
<ListView dataSource={this.state.userDataSource} renderRow={this.renderRow.bind(this)}/>
</View>
</View>
</ScrollView>
)
}
}
const styles = StyleSheet.create({
container:{
backgroundColor:'#455a64',
height:125
},
text:{
textAlign:'left',
fontSize:25,
color:'white',
marginTop:0,
marginLeft:18
}
})
I am not able to see anything on my app.
Please help me out.
items[] is an array of JSON data each item has its attributes like name,etc
I m trying to display name but nothing is displayed.
Error is undefined is not an object evaluating data.items[0]

Please try my code it will defenatily resolve your issue
import React, { Component } from 'react';
import { FlatList, ActivityIndicator, Text, View } from 'react-native';
export default class FetchExample extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true}
}
componentDidMount(){
return fetch('https://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.movies,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render(){
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return(
<View style={{flex: 1, paddingTop:20}}>
<FlatList
data={this.state.dataSource}
renderItem={({item}) => <Text>{item.title}, {item.releaseYear}</Text>}
keyExtractor={(item, index) => index}
/>
</View>
);
}
}

Related

Not able to get restaurant collection in react native using zomato API

I am trying to display the zomato restaurant collection of a city on react native page. I am using zomato API. On zomato API documentation, I am using request URL given under "get zomato collections in a city"
Below is my code:
import React from 'react';
import { StyleSheet, Text, View, FlatList, Image, ActivityIndicator } from 'react-native';
import { Card, CardItem } from "native-base"
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
}
}
getUserFromApi = () => {
return (
fetch("https://developers.zomato.com/api/v2.1/collections?city_id=1", {
headers: {
'Content-Type': 'application/json',
'user-key': '2bf4669cad5a8230fd2b220a2d4a37b9'
}
})
.then(response => response.json())
.then(responseJson => {
this.setState({
isLoading: false,
dataSource: responseJson.collections.collection
})
})
.catch(error => console.log(error))
)
}
componentDidMount() {
this.getUserFromApi();
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.progress}>
<ActivityIndicator
size="large"
color="#01CBC6"
/>
</View>
)
}
return (
<View style={{marginTop: 50}}>
<FlatList
data={this.state.dataSource}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Card>
<CardItem>
<View style={styles.container}>
</View>
<View style={styles.userInfo}>
<Text> collections_id: {item.collections_id}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}>
</View>
<View style={styles.userInfo}>
<Text>title: {item.title}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}>
</View>
<View style={styles.userInfo}>
<Text>description: {item.description}</Text>
</View>
</CardItem>
</Card>
)}
/>
</View>
);
}
}
I am not getting any error, but my screen is blank. There is no output on my screen. I am not able to understand where in my code I am making mistake
//----------------set state like this 👇-----------------------//
this.setState({
isLoading: false,
dataSource: responseJson.collections,
});
//-------------------------------------☝-----------------------//
// Also look FlatList for how the data is rendered //
Working App : Expo Snack
import React from 'react';
import {
StyleSheet,
Text,
View,
FlatList,
Image,
ActivityIndicator,
} from 'react-native';
import { Card, CardItem } from 'native-base';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: [],
};
}
getUserFromApi = () => {
return fetch(
'https://developers.zomato.com/api/v2.1/collections?city_id=1',
{
headers: {
'Content-Type': 'application/json',
'user-key': '2bf4669cad5a8230fd2b220a2d4a37b9',
},
}
)
.then((response) => response.json())
.then((responseJson) => {
console.log('data:', responseJson);
//----------------set state like this------------------------//
this.setState({
isLoading: false,
dataSource: responseJson.collections,
});
//------------------------------------------------------------//
//Also look FlatList for how the data is rendered //
})
.catch((error) => console.log(error));
};
componentDidMount() {
this.getUserFromApi();
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.progress}>
<ActivityIndicator size="large" color="#01CBC6" />
</View>
);
}
return (
<View style={{ marginTop: 50 }}>
<FlatList
data={this.state.dataSource}
keyExtractor={({ id }, index) => id}
renderItem={({ item }) => (
<Card>
<CardItem>
<View style={styles.container}></View>
<View style={styles.userInfo}>
{/**access data of for rendering like below 👇 */}
<Text> collections_id: {item.collection.collection_id}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}></View>
<View style={styles.userInfo}>
{/**access data of for rendering like below 👇 */}
<Text>title: {item.collection.title}</Text>
</View>
</CardItem>
<CardItem>
<View style={styles.container}></View>
<View style={styles.userInfo}>
{/**access data of for rendering like below 👇 */}
<Text>description: {item.collection.description}</Text>
</View>
</CardItem>
</Card>
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: { padding: 10 },
userInfo: { padding: 10 },
});

Implement onPress on Flatlist item

I am trying to send the data of the flatlist items when clicked and set to another class.The ontouch is working but I am having the error below in the image. Also how can I send the data of api to the other class and get from another class? I have implemented as follows:
export default class FlatSpeakers extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [],selectedItem: null, }
const { navigate } = this.props.navigation;
}
onPressItem = () => {
navigate('SpeakersClick')
};
componentDidMount() {
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then(res => {
this.setState({
isLoading: false,
data: res.data,
})
})
}
renderItem({ item }) {
return (
<TouchableOpacity onPress={()=>this.onPressItem(item)} >
<Card>
<CardSection>
<View style={styles.thumbnailContainerStyle}>
<Image
style={styles.thumbnailStyle}
source={{ uri: item.image }}
/>
</View>
<View style={styles.headerContentStyle}>
<Text style={styles.headerTextStyle}>{item.title}</Text>
<Text>{item.artist}</Text>
</View>
</CardSection>
</Card>
</TouchableOpacity>
)
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={(item, index) => index}
onPress={this.onPressItem}
/>
</View>
);
}
}
Problem in your code is, that you are calling same method from two sides - on one side you are passing arguments in it on another side you are not passing arguments. If you wan't to have both cases covered you should change you onPressFunction, to accept arguments - in your case item:
onPressItem = (item) => {
navigate('SpeakersClick')
};
try to put this.onPressItem = this.onPressItem.bind(this) on constructor(props)

React Native FlatList Touchable Opacity

I used FlatList to display the title that is in the data. I added in TouchableOpacity for the FlatList. So for example, when I click 'First', I want to show the the data from 'mood' and it will show the list of passionate,rousing and confident. I want to show the list on a new file/screen and show purely the mood of list.
This is my data:
const Mock =
[
{ title: 'First',
mood:
[
{name: 'passionate'},
{name: 'rousing'},
{name: 'confident'},
],
},
{ title: 'Second',
mood:
[
{name: 'rollicking'},
{name: 'cheerful'},
{name: 'fun'},
{name: 'sweet'},
{name: 'amiable'},
{name: 'natured'}
],
This is my FlatList code:
export default class Cluster1 extends Component{
render() {
return (
<View>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
What should I do with the TouchableOpacity when I want to show the mood name when I click the title?
This is my style code
const styles = StyleSheet.create({
itemTitle:{
fontSize: 25,
fontWeight: 'bold',
color: 'white',
margin: 20,
},
},
list:{
flex: 1,
backgroundColor: '#00BCD4',
alignItems: 'center',
justifyContent: 'space-between',
flexDirection: 'row',
},
});
You should modify your code as below to do this:
export default class Cluster1 extends Component {
render() {
return (
<View style={{ margin: 30, backgroundColor: '#ddd' }}>
<FlatList
data={Mock}
renderItem={({ item, index }) => {
return <FlatListItem item={item} index={index} />;
}}
/>
</View>
);
}
}
class FlatListItem extends Component {
state = { showItemIndex: [false, false] };
_onPress = index => () => {
let showItemIndex = this.state.showItemIndex;
showItemIndex[index] = !this.state.showItemIndex[index];
this.setState({ showItemIndex });
};
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={this._onPress(this.props.index)}>
<Text style={styles.itemTitle}>{this.props.item.title}</Text>
</TouchableOpacity>
{this.state.showItemIndex[this.props.index] && (
<FlatList
data={this.props.item.mood}
extraData={this.state.showItemIndex}
renderItem={({ item, index }) => {
return (
<Text item={item} index={index}>
{item.name}
</Text>
);
}}
/>
)}
</View>
</View>
);
}
}
Use this, it's should be work fine for you:
Link: https://github.com/oblador/react-native-collapsible
Link: https://github.com/naoufal/react-native-accordion
Link: https://github.com/cuiyueshuai/react-native-expandable-section-flatlist
You could set a state variable which gets updated whenever your TouchableOpacity gets pressed. And then you conditionally render the title or the list of mood names:
class FlatListItem extends Component {
constructor(props) {
super(props);
this.state = {collapsed: true}
}
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity
onPress={this.onPress}
>
<Text style={styles.itemTitle}>
{this.props.item.title}
</Text>
</TouchableOpacity>
{this.state.collapsed ?
<View /> :
<View>
{this.props.item.mood.map(mood => <Text>{mood.name}</Text>)}
</View>}
</View>
</View>
);
}
onPress = () => {
this.setState({collapsed: !this.state.collapsed})
}
}
You can do this by separating out the datasource that is required to show in the list.
First to display title: you can do something like this
export default class Cluster1 extends Component {
state = {
data: []
};
componentWillMount() {
const titles = Mock.forEach(data => data.title);
this.setState({
data: titles
});
}
onItemClick = item => {
const itemIndex = Mock.findIndex(data => (
data.title === item
));
const values = Mock[itemIndex].mood;
this.setState({
data: values
});
};
render() {
return (
<View>
<FlatList
data={this.state.data}
renderItem={({ item, index }) => {
return (
<FlatListItem
item={item}
index={index}
onItemClick={this.itemClick}
/>
);
}}
/>
</View>
);
}
}
and then in your FlatlistItem code:
class FlatListItem extends Component {
render() {
return (
<View style={styles.list}>
<View>
<TouchableOpacity onPress={() =>
this.props.onItemClick(this.props.item)
}>
<Text style={styles.itemTitle}>
{
this.props.item.name ?
this.props.item.name : this.props.item
}
</Text>
</TouchableOpacity>
</View>
</View>
);
}
}

React Native can't find variable: navigate

I am doing stack navigation but I can't seem to be able to navigate I will get this error "Can't find variable: navigate" Here is the screenshot of my android emulator
This is my App class(main)
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Header/>
<AppNavigator/>
</View>
);
}
}
const AppNavigator = StackNavigator({
Cluster1: {
screen: Cluster1,
},
Play: {
screen: Play,
},
});
This is my Cluster1 class
export default class Cluster1 extends Component{
render(){
return(
<View>
<SectionList
renderSectionHeader={({ section }) => {
return (<SectionHeader section={section} />);
}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}
>
</SectionList>
</View>
);
}
}
class SectionHeader extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headertext}>
{this.props.section.title}
</Text>
<TouchableOpacity onPress={() => { navigate("Play");}}>
<Text style ={styles.Play}>Play
</Text>
</TouchableOpacity>
</View>
);
}
}
navigation object only exist in the screen component. (not exist in the nested components). you can pass it into the nested component using props
export default class Cluster1 extends Component{
render(){
return(
<View>
<SectionList
renderSectionHeader={({ section }) => {
return (<SectionHeader navigation={this.props.navigation} section={section} />);
}}
sections={ClusterData}
keyExtractor={(item, index) => item.name}
>
</SectionList>
</View>
);
}
}
class SectionHeader extends Component {
render() {
return (
<View style={styles.header}>
<Text style={styles.headertext}>
{this.props.section.title}
</Text>
<TouchableOpacity onPress={() => { this.props.navigation.navigate("Play");}}>
<Text style ={styles.Play}>Play
</Text>
</TouchableOpacity>
</View>
);
}
}
Include on your SectionHeader the this.props.navigation something like this:
<SectionHeader navigation={this.props.navigation}/>
because the props.navigation are by default on your parent component
and on SectionHeader component you will access to navition like:
..
goToSignUp() {
this.props.navigation.navigate('SignUp');
}
..
For me also was confusing before. Cheers!
You can use this rather than navigate :
this.props.navigation.navigate('Play')
Hope this is helpful.

React navigation state.params not working

It is not working. I tried everything. Nothing works. state.params is simply not there if you make an advanced app.
I have this problem with the react "navigation". It says in the manual that the params object should be there https://reactnavigation.org/docs/navigation-prop.html#state-the-screen-s-current-state-route But it isn't.
I set an id parameter like this in screen 1 when I link to screen 2:
<TouchableWithoutFeedback onPress={ ()=> this.props.navigation.navigate('FontsTab', { id: item.id }) } style={styles.listHeader} >
<View style={styles.listRowContainer}>
<View style={styles.listinside1Container}>
<Image style={styles.listImage} source={item.icon} />
<View style={styles.listContainer} onPress={(event) => this._selectedItem(item.text)} >
<Text style={styles.listHeader} >
{item.title}
</Text>
<Text style={styles.listValue} >{item.value}</Text>
<Image
style={{width: 50, height: 50}}
source={{uri: item.img}}
/>
</View>
</View>
</View>
</TouchableWithoutFeedback>
But it's not working. In screen 2 I can't use the state.params :
<ScrollView style={styles.container}>
<Text>{ JSON.stringify(this.props.navigation)}</Text>
<Text>TEST{ state.params }</Text>
<Image
style={{width: 150, height: 150}}
source={{uri: this.state.dataSource.img}}
/>
<Text style={styles.textStyle} >{this.state.dataSource.text}</Text>
</ScrollView>
state.params just returns nothing. What can I do about it?
The full class for screen2:
class Fonts extends Component {
constructor(props) {
super(props);
this.state = {
params: null,
selectedIndex: 0,
value: 0.5,
dataSource: null,
isLoading: true
};
this.componentDidMount = this.componentDidMount.bind(this);
}
getNavigationParams() {
return this.props.navigation.state.params || {}
}
componentDidMount(){
return fetch('http://www.koolbusiness.com/newvi/4580715507220480.json')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
...this.state,
isLoading: false,
dataSource: responseJson,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render() {
if(this.state.isLoading){
return(
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<ScrollView style={styles.container}>
<Text>{ JSON.stringify(this.props)}</Text>
<Text>TEST{ this.state.params }</Text>
<Image
style={{width: 150, height: 150}}
source={{uri: this.state.dataSource.img}}
/>
<Text style={styles.textStyle} >{this.state.dataSource.text}</Text>
</ScrollView>
);
}
}
In my app this pain is reproducible by a simple button in screen1:
<Button
onPress={() => navigate('FontsTab', { name: 'Brent' })}
title="Go to Brent's profile"
/>
Then switching to the FontsTab works but the params are not in the state object:
I also have this code for the tabview
import React, { Component } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { StackNavigator } from 'react-navigation';
import { Icon } from 'react-native-elements';
import FontsHome from '../views/fonts_home';
import FontsDetails from '../views/fonts_detail';
const FontsTabView = ({ navigation }) => (
<FontsHome banner="Fonts" navigation={navigation} />
);
const FontsDetailTabView = ({ navigation }) => (
<FontsDetails banner="Fonts Detail" navigation={navigation} />
);
const FontsTab = StackNavigator({
Home: {
screen: FontsTabView,
path: '/',
navigationOptions: ({ navigation }) => ({
title: '',
headerLeft: (
<Icon
name="menu"
size={30}
type="entypo"
style={{ paddingLeft: 10 }}
onPress={() => navigation.navigate('DrawerOpen')}
/>
),
}),
},
Detail: {
screen: FontsDetailTabView,
path: 'fonts_detail',
navigationOptions: {
title: 'Fonts Detail',
},
},
});
export default FontsTab;
this.props.navigation.state.params.id will give you the value of param id passed from screen1.
I put my screen in the right StackNavigator and then it worked.