React Native: How can I put a pop-up Modal into flatlist - react-native

I've made a flatlist with a few data inside. I want to make a pop-up information for each item in the flatlist. So I tried putting Modal into the renderItem function but when it sets the modal state visible, it will show all of the information in my flatlist. I think it should be setting the modal visible state by id or something like that but I don't know how to do it. Any suggestion?
my renderItem:
function RenderItem({ item }) {
return (
<View>
<Modal
animationType='slide'
transparent={true}
visible={infoModal}>
<View style={styles.informationContainer}>
<View style={styles.informationBox}>
<Text>{item.file.displayName}</Text>
<Button title=' OK ' onPress={() => setInfoModal(false)} />
</View>
</View>
</Modal>
<TouchableOpacity style={styles.listBox} onPress={() => setInfoModal(true)}>
<View>
<Text numberOfLines={1} style={styles.listText}>{item.file.displayName}</Text>
<Text style={{ width: 200, color: 'rgba(0, 0, 0, 0.5)' }}>{item.certificateName}</Text>
</View>
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
<TouchableOpacity>
<Icon name='search' color='black' size={25} />
</TouchableOpacity>
<Text> </Text>
<TouchableOpacity onPress={() => handleDownload(item)}>
<Icon name='download' color='black' size={25} />
</TouchableOpacity>
<Text> </Text>
</View>
</TouchableOpacity>
</View>
)
}

Instead of setting a simple boolean value about whether the Modal should appear, you can set some sort of identifiable value that tells it what item to load (and otherwise leave it undefined).
Bare-bones example:
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
export default function App() {
const [modalInfo, setModalInfo] = React.useState(undefined);
const renderItem = ({ item }) => (
<TouchableOpacity onPress={() => setModalInfo(item.title)}><Text>{item.title}</Text></TouchableOpacity>
);
return (
<View style={styles.container}>
<Modal visible={modalInfo !== undefined}>
<View style={[{borderWidth: 1},styles.centeredView]}>
<Text>{modalInfo}</Text>
<TouchableOpacity onPress={() => setModalInfo(undefined)}><Text>Close</Text></TouchableOpacity>
</View>
</Modal>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</View>
);
}
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
});

Related

1st index hidden Item not hidding when swiping the another element - swiperFlatList React native

as you can see in the image, I have implemented adding Text inputs dynamically with the button press, everything is working perfectly only the 1st text input hidden item (Remove Button) not hiding when swiping the other text inputs.
const initialState = {
col1: '',
key: 0,
};
const [inputField, setInputField] = useState<Values[]>([initialState]);
<SwipeListView
data={inputField}
renderItem={data => renderItem(data)}
renderHiddenItem={data => renderHiddenItem(data)}
leftOpenValue={55}
rightOpenValue={-100}
disableRightSwipe={true}
ListHeaderComponent={
<View style={[styles.headingContainer]}>
<Text style={[styles.headingText]}>{Props.inputHeading}</Text>
</View>
}
ListFooterComponent={
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.addBtn}
activeOpacity={0.7}
onPress={onPressAddBtn}>
<Text style={styles.BtnText}>Add</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.submitBtn} activeOpacity={0.7}>
<Text style={styles.BtnText}>Submit</Text>
</TouchableOpacity>
</View>
}
style={{height: Dimensions.get('screen').height / 1.3}}
/>
const renderItem = (data: any) => {
return (
<TouchableHighlight key={data.item.key}>
<TextInput
placeholder="Hello"
onChangeText={e => handleChange(data.item.key, 'col1', e)}
value={data.item.col1}
style={[styles.textInput, Props.textInputStyle]}
// {...Props.textInputProps}
/>
</TouchableHighlight>
);
};
const renderHiddenItem = (rowData: any) => {
return (
<View
style={{
justifyContent: 'flex-end',
flexDirection: 'row',
alignItems: 'center',
}}>
<TouchableOpacity
activeOpacity={0.7}
style={{
backgroundColor: 'red',
justifyContent: 'center',
flexDirection: 'row',
width: 90,
height: 45,
alignItems: 'center',
borderRadius: 5,
}}>
<Text style={{color: 'white'}}>Remove</Text>
</TouchableOpacity>
</View>
);
};
but other all element's swipe is working as expected only the first element is not working as expected
found solution by adding keyExtractor={item => item.key.toString()} to swiper flatlist.

How to put a lot of numbers in an array and than use them in flatlist?

I got this bunch of buttnos and i need to make a horizontal flatlist in react native and i always get some error so can someone help me how to do that? I need to put these buttons in an array so i can put tham in that flatlist i need to make but i am stuck here :D i am new to reactnative so if someone can help me thanks <3
<View style={{flexDirection: 'row', paddingHorizontal: 10, paddingTop: 5}}>
<View style={{width: '15%', paddingRight: 5}}>
<TouchableOpacity
style={[styles.buttonText]}
activeOpacity = {.5}
onPress={ ()=>this.setState({...this.state, location: 'details'}) }>
<Text style={styles.buttonText}>Details</Text>
</TouchableOpacity>
</View>
<View style={{width: '15%', paddingRight: 5}}>
<TouchableOpacity
style={[styles.buttonText]}
activeOpacity = {.5}
onPress={ ()=>this.setState({...this.state, location: 'users'}) }>
<Text style={styles.buttonText}>Users</Text>
</TouchableOpacity>
</View>
<View style={{width: '15%', paddingRight: 5}}>
<TouchableOpacity
style={[styles.buttonText]}
activeOpacity = {.5}
onPress={ ()=>this.setState({...this.state, location: 'assets'}) }>
<Text style={styles.buttonText}>Assets</Text>
</TouchableOpacity>
</View>
<View style={{width: '15%', paddingRight: 5}}>
<TouchableOpacity
style={[styles.buttonText]}
activeOpacity = {.5}
onPress={ ()=>this.setState({...this.state, location: 'sites'}) }>
<Text style={styles.buttonText}>Sites</Text>
</TouchableOpacity>
</View>
<View style={{width: '15%', paddingRight: 5}}>
<TouchableOpacity
style={[styles.buttonText]}
activeOpacity = {.5}
onPress={ ()=>this.setState({...this.state, location: 'cards'}) }>
<Text style={styles.buttonText}>Cards</Text>
</TouchableOpacity>
</View>
</View>
I didn't make the full array, but this should give you the idea:
const buttons = [{title: "Users", location: "users"},{title: "Details", location: "details"}]
<View style={styles.container}>
<FlatList
horizontal
data={buttons}
keyExtractor={(item) => item.location}
renderItem={({item}) =>
<TouchableOpacity
style={[styles.buttonText]}
activeOpacity = {.5}
onPress={ ()=>this.setState({...this.state, location: item.location}) }>
<Text style={styles.buttonText}>{item.title}</Text>
</TouchableOpacity>
}
/>
</View>
If you titles and locations were always just capitalized versions of each other, you could simplify the array even further.
The exact code example is available directly on first load, on the flatlist documentation page.
import React from 'react';
import { SafeAreaView, View, FlatList, StyleSheet, Text, StatusBar } from 'react-native';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const renderItem = ({ item }) => (
<Item title={item.title} />
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: StatusBar.currentHeight || 0,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});
export default App;
You just need to add the props horizontal in the Flatlist component to make it horizontal.

Last odd flatlist item stretches along screen

I'm displaying some data items with Flatlist in two columns. But when there is an odd item at the last place, it stretches all along the screen. I don't want that, how can I make it to take only %50 of screen space like even items? Thanks a lot.
CategoryGridTile Component:
return (
<View style={styles.PlaceItem}>
<TouchableCmp onPress={props.onSelect}>
<View>
<View style={{ ...styles.placeRow, ...styles.placeHeader }}>
<ImageBackground
source={{ uri: props.image }}
style={styles.bgImage}
>
<View style={styles.titleContainer}>
<Text style={styles.title} numberOfLines={2}>
{props.title}
</Text>
</View>
</ImageBackground>
</View>
</View>
</TouchableCmp>
</View>
)
}
const styles = StyleSheet.create({
PlaceItem: {
flex: 1,
height: 125,
width: '80%',
backgroundColor: '#f5f5f5',
borderRadius: 5,
overflow: 'hidden',
margin: 6
},
placeRow: {
flexDirection: 'row'
}
})
Screen:
const renderGridItem = itemData => {
return (
<CategoryGridTile
image={itemData.item.image}
title={itemData.item.title}
onSelect={() => {
props.navigation.navigate({
routeName: 'CategoryPlaces',
params: {
categoryId: itemData.item.title,
locationId: locations
}
})
}}
/>
)
}
return (
<FlatList
keyExtractor={(item, index) => item._id}
data={displayedCategories}
renderItem={renderGridItem}
numColumns={2}
/>
)
Changing PlaceItem flex: 1 to flex: 1/2 at CategoryGridTile component solved the problem.

undefined is not a function(evaluating '_this2.AlertButton()')?

I create touchableopacity for every item in map. it works well but when I give function to TouchableOpacity like below, it gives me error which is on title. How can I fix this ?
it gives error when I write this.AlertButton()
{section.subcategory.map((item, key) => (
<View key={key} style={styles.item}>
<TouchableOpacity
onPress={() =>this.AlertButton()}>
</TouchableOpacity>
<View style={styles.separator} />
</View>
))}
This is my alert function :
AlertButton() {
const number = 'TelNo';
Alert.alert(
'',
'Test',
[
{text: 'NO'},
{text: 'Yes', onPress: () => Linking.openURL(`tel:${number}`)},
],
);
}
Here is render. And my map function which is above is in renderContent
render() {
CONTENT2 =[];
CONTENT2 = this.state.fromPage1;
return (
<View style={styles.container}>
<View style={{height: this.state.yuksek, width: this.state.genis, justifyContent: 'center', alignItems: 'center',position:'absolute'}}>
<Text style={{fontWeight: 'bold', color:'#856F6F'}}>Yukarıdaki menü butonlarına tıklayınız.</Text>
</View>
<View style={{height: this.state.yuksek2, width: this.state.genis2, justifyContent: 'center', alignItems: 'center'}}>
<Text style={{fontWeight: 'bold', color:'#856F6F'}}>String</Text>
</View>
<ScrollView contentContainerStyle={{}}>
<Accordion
activeSections={this.state.activeSections}
sections={CONTENT2}
touchableComponent={TouchableOpacity}
expandMultiple={false}
renderHeader={this.renderHeader}
renderContent={this.renderContent}
duration={400}
onChange={this.setSections}
/>
</ScrollView>
<View style={{height:85, width:85,position:'absolute',bottom:5,right:5}}>
<TouchableOpacity style={{flex:1}} onPress={() => this.AlertButton()}>
<ImageBackground source={require('../../image/phoneCall.png')} style={{flex:1}}>
</ImageBackground>
</TouchableOpacity>
</View>
</View>
);
}
}
just change the following line
renderContent={this.renderContent}
to
renderContent={this.renderContent.bind(this)}
because when you are using the class method directly as callback then its not definitely bound to its class when called from inside the component

Like functionality like Facebook react native

I am using a list of image.Below every image,there is a like button. When i click on the Like button, likes should be increases which is working fine. But it should work on the image I click. Currently it is increasing like count of all the images.I am new to react native.Any help would be appreciated.
Here, this is my code
export default class Art extends Component {
constructor(props) {
super(props)
this.state = {
value: null,
liked:false
}
}
_increaseValue(){
console.log(this.state.liked)
if (this.state.liked==false)
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value +1;
this.setState({value:newvalue})
}
else
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value -1;
this.setState({value:newvalue}
}
}
render() {
const datas = [
{
img: images[0]
},
{
img: images[1]
},
{
img: images[2]
},
{
img: images[3]
},
];
const { navigate } = this.props.navigation;
// eslint-disable-line
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data =>
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.value} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
/>
</Content>
);
}
}
You need to convert your Cards into separate components or store the like counts separately in state. You can approach this problem several ways. I'll give you an example of how you can achieve this behavior and you can implement it the way you like.
Example
export default class CutomListItem extends React.Component {
constructor(props) {
this.state = {
likes: 0
};
}
_increaseValue = () => {
this.setState((prevState) => {
return {
likes: prevState.likes++
};
});
}
render() {
const { data, navigate, share } = this.props; // send data with props
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.likes} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
}
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data => (<CutomListItem data={data} navigate={navigate} share={Share} />}
/>
</Content>
);
}