I have a list in which I want to add an image. Basically my code worked fine and the API database I use has unfortunately changed ... Some products in my database don't have an image so it gives me an error when I call the line in question... So, I want to create a condition: If there is an image for the product in question in the database, I want it to be displayed
Image source={{uri: URL + item.photo.1.url}}
Otherwise I want it to be a preset logo. <Image source={require('../../../assets/images/logo.png')}
I did it this way:
<ListItem.Content style={{flexDirection: 'row', justifyContent: 'space-between'}}>
{item.photo !== null && item.photo > 0 ? (
<Image
source={{uri: URL + item.photo._1_.url}}
style={{ width: 25, height: 25}}/>
) : (
<Image
source={require('../../../assets/images/logo.png')}
style={{ width: 25, height: 25}}
/>
)};
<ListItem.Title style={{width: '65%', fontSize: 16}}>{ ( item.name.length > 20 ) ? item.name.substring(0, 20) + ' ...' : item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400', position: "absolute", bottom: 0, right: 0 }}>{item.cost}{i18n.t("products.money")}</ListItem.Subtitle>
</ListItem.Content>
But I have 2 errors:
undefined is not an object (evaluating 'item.photo.1.url')
[Unhandled promise rejection: Error: Text strings must be rendered within a component.]
To show you how the data looks :
And the full code of that screen :
export default class Products extends Component {
constructor(props) {
super(props);
this.state = {
productId: (props.route.params && props.route.params.productId ? props.route.params.productId : -1),
listData: '',
selectedId: '',
setSelectedId: '',
currentPage: 1,
loadMoreVisible: true,
loadMoreVisibleAtEnd: false,
displayArray: []
}
};
initListData = async () => {
let list = await getProducts(1);
if (list) {
this.setState({
displayArray: list,
loadMoreVisible: (list.length >= 10 ? true : false),
currentPage: 2
});
}
};
setNewData = async (page) => {
let list = await getProducts(parseInt(page));
if (list) {
this.setState({
displayArray: this.state.displayArray.concat(list),
loadMoreVisible: (list.length >= 10 ? true : false),
loadMoreVisibleAtEnd: false,
currentPage: parseInt(page)+1
});
}
};
loadMore() {
this.setNewData(this.state.currentPage);
}
displayBtnLoadMore() {
this.setState({
loadMoreVisibleAtEnd: true
});
}
async componentDidMount() {
this.initListData();
}
render() {
//console.log('url', URL );
//console.log('displayArray', this.state.displayArray);
//console.log('name', this.state.displayArray.name);
//console.log('photo', this.state.displayArray.photo);
return (
<View style={{flex: 1}}>
{this.state.displayArray !== null && this.state.displayArray.length > 0 ? (
<View style={{ flex: 1}}>
<SafeAreaView>
<FlatList
data={this.state.displayArray}
extraData={this.selectedId}
style={{width: '98%'}}
onEndReached={() => this.displayBtnLoadMore()}
renderItem={({item, index, separators })=>
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<ListItem
style={{width:'100%'}}
containerStyle= {{backgroundColor: index % 2 === 0 ? '#fde3a7' : '#FFF'}}
bottomDivider
onPress={() => this.props.navigation.navigate('ProductDetails', {productId:parseInt(item.id)})}>
<ListItem.Content style={{flexDirection: 'row', justifyContent: 'space-between'}}>
{item.photo !== null && item.photo > 0 ? (
<Image
source={{uri: URL + item.photo._1_.url}}
style={{ width: 25, height: 25}}/>
) : (
<Image
source={require('../../../assets/images/logo.png')}
style={{ width: 25, height: 25}}
/>
)};
<ListItem.Title style={{width: '65%', fontSize: 16}}>{ ( item.name.length > 20 ) ? item.name.substring(0, 20) + ' ...' : item.name}</ListItem.Title>
<ListItem.Subtitle style={{ color: '#F78400', position: "absolute", bottom: 0, right: 0 }}>{item.cost}{i18n.t("products.money")}</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
</View>
}
keyExtractor={(item,index)=>index.toString()}
style={{width:"100%"}}
/>
{this.state.loadMoreVisible === true && this.state.loadMoreVisibleAtEnd === true ? (
<Button title=" + " onPress={()=>{this.loadMore()}}></Button>
) : null
}
<View style={styles.container}>
<Text>{"\n"}</Text>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.container}>
<Button
color="#F78400"
title= 'Back'
onPress={() => this.props.navigation.goBack()}>BACK
</Button>
</View>
</TouchableOpacity>
</View>
<Text>{"\n\n"}</Text>
</SafeAreaView>
</View>
) : (
<View style={styles.container}>
<Text>{"\n\n" + (this.state.displayArray === null ? i18n.t("products.searching") : i18n.t("products.nodata")) + "\n\n\n"}</Text>
<Button
color="#F78400"
title= 'Back'
onPress={() => this.props.navigation.goBack()}>BACK
</Button>
</View>
)}
</View>
);
};
}
I'm a little lost in how to do it, so if you have any clue to help me, any lead it would be great. Thanks a lot
This test:
item.photo !== null && item.photo > 0
Will not return what you expect. The reason is that when there is no photo, the property is set to an empty string. So the first part of that test should be:
item.photo !== ''
Next, when there is a photo, the photo
property is an object. So the second part should be:
item.photo.constructor === 'Object'
But, that will be compounded if there are more than one photos. Your code suggests you only want the first photo (regardless of how many there may be).
So if you make the changes I've suggested, it should work as you expect.
If I were you, I would skip the first test altogether as it isn't necessary now that the second test covers both cases. I recommend just doing this:
{item.photo.constructor === 'Object' ? (