I have a Modal that displays a list of contacts. onPress, contacts are dynamically added to a View. If a contact has already been added, on second onPress I would like to remove it from the View. For that I'm amending the state/array containing the contacts, using splice but it removes all the contacts at once.
I'm also trying to update the state of the 'Add' icon. If a contact has been added the Add icon Image should become the active one.
Not sure what I'm doing wrong?
Here's the Modal opened up:
My code:
import React, {Component} from 'react'
import {
Text,
View,
ListView,
ScrollView,
StyleSheet,
Image,
TouchableHighlight,
TextInput,
Modal,
} from 'react-native'
const friends = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
}).cloneWithRows([
{
id: 1,
firstname: 'name1',
surname: 'surname1',
image: require('../images/friends/avatar-friend-01.png')
},
{
id: 2,
firstname: 'name2',
surname: 'surname2',
image: require('../images/friends/avatar-friend-02.png')
},
{
id: 3,
firstname: 'name3',
surname: 'surname3',
image: require('../images/friends/avatar-friend-03.png')
},
])
class AppView extends Component {
state = {
isModalVisible: false,
contactsPicked: [],
friendsState: {},
}
setModalVisible = visible => {
this.setState({isModalVisible: visible})
}
pickContact = (friend) => {
if(this.state.contactsPicked.indexOf(friend) < 0){
var tempFriendsState = this.state.friendsState
tempFriendsState[friend.id] = true
this.setState({
contactsPicked: [ ...this.state.contactsPicked, friend],
friendsState: tempFriendsState,
})
}
else{
let index = this.state.contactsPicked.indexOf(friend)
let nextContacts = this.state.contactsPicked
nextContacts.splice(index,1)
let tempFriendsState = this.state.friendsState
tempFriendsState[friend.id] = false
this.setState({
contactsPicked: nextContacts,
friendsState: tempFriendsState,
})
}
}
removeContact = (friend) => {
let index = this.state.contactsPicked.indexOf(friend)
let nextContacts = this.state.contactsPicked
nextContacts.splice(index,1)
this.setState({
contactsPicked: nextContacts,
})
}
_renderAddFriendTile = () => {
return(
<View style={[styles.step, styles.stepThree]}>
<View style={{flex:1}}>
<Text style={styles.heading}>Friend tile</Text>
</View>
{this.state.contactsPicked.length > 0 && (
<TouchableHighlight onPress={() => {this.removeContact(this.state.contactsPicked)}}>
<View>
{this.state.contactsPicked.map((contact,index) => (
<View key={index} style={[styles.row, styles.friendRow]}>
<Image source={contact.image} style={styles.friendIcon}></Image>
<Text style={styles.name}>{contact.firstname} </Text>
<Text style={styles.name}>{contact.surname}</Text>
<View style={styles.roundIconContainer}>
<View style={styles.roundIcon}>
<View style={[styles.removeButton, styles.buttonSmall]}>
<Image source={require('../images/button-cross-small.png')} style={styles.crossIconSmall}></Image>
</View>
</View>
</View>
</View>
))}
</View>
</TouchableHighlight>
)}
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add friends</Text>
</View>
</TouchableHighlight>
</View>
)
}
render(){
return (
<ScrollView style={styles.container}>
<Modal
animationType={'fade'}
transparent={true}
visible={this.state.isModalVisible}
>
<View style={styles.addFriendModalContainer}>
<View style={styles.addFriendModal}>
<TouchableHighlight onPress={() => {this.setModalVisible(false)}}>
<View>
<Text>Close</Text>
</View>
</TouchableHighlight>
<ListView
dataSource={friends}
renderRow={(friend) => {
return (
<FriendRow
friend={friend}
pickContact={this.pickContact}
isSelected={this.state.friendsState[friend.id]}
/>
)
}}
/>
</View>
</View>
</Modal>
{this._renderAddFriendTile()}
</ScrollView>
)
}
}
class FriendRow extends Component {
render(){
return(
<TouchableHighlight onPress={() => {this.props.pickContact(this.props.friend)}}>
<View style={[styles.row, styles.friendRow]}>
<Image source={this.props.friend.image} style={styles.friendIcon}></Image>
<Text style={styles.name}>{this.props.friend.firstname} </Text>
<Text style={styles.name}>{this.props.friend.surname}</Text>
<View style={styles.roundIconContainer}>
<View style={styles.roundIcon}>
<View style={this.props.isSelected ? [styles.buttonActive, styles.buttonSmall]: [styles.modalButtonInactive, styles.buttonSmall]}>
<Image source={this.props.isSelected && require('../images/button-tick-small-on.png')} style={styles.buttonTickSmall}></Image>
</View>
</View>
</View>
</View>
</TouchableHighlight>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#e1e1e1'
},
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
step: {
backgroundColor: '#ffffff',
borderRadius: 4,
borderLeftWidth: 5,
flex: 1,
marginLeft: 10,
marginRight: 10,
marginBottom: 10,
paddingLeft: 15,
paddingRight: 10,
paddingTop: 15,
paddingBottom: 20,
shadowOffset: {
width: 0,
height: 2,
},
shadowRadius: 2,
shadowOpacity: 0.2,
shadowColor: '#000000',
},
stepThree: {
borderLeftColor: '#ffbd18',
},
heading: {
textAlign: 'center',
fontWeight: 'bold',
fontSize: 15,
color: '#333333',
},
addFriendButtonContainer: {
marginTop:15,
flex:1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
addFriendButton: {
backgroundColor: '#ffbd18',
width: 270,
borderRadius: 4,
paddingTop: 15,
paddingBottom: 15,
},
addFriendButtonText: {
color: '#ffffff',
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
pickContainer: {
flex:1,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
borderRightWidth: 1,
},
pickWrapper: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-around',
alignItems: 'center',
marginTop: 10,
},
buttonBig: {
height: 60,
width: 60,
borderRadius: 30,
},
buttonSmall: {
height: 20,
width: 20,
borderRadius: 10,
},
buttonActive: {
backgroundColor: '#fd6769',
alignItems: 'center',
justifyContent: 'center',
},
buttonInactive: {
backgroundColor: '#eeeeee',
alignItems: 'center',
justifyContent: 'center',
},
removeButton:{
backgroundColor: '#cccbcb',
alignItems: 'center',
justifyContent: 'center',
},
modalButtonInactive: {
backgroundColor: '#ffffff',
borderWidth: 1,
borderColor: '#eeeeee',
},
buttonTickBig: {
width: 34,
height: 28,
},
buttonTickMinusBig: {
width: 18,
height: 8,
},
buttonTickSmall: {
width: 12,
height: 10,
},
crossIconSmall: {
width: 12,
height: 10,
},
pickText: {
color: '#c7c7c7',
fontWeight: 'bold',
},
addFriendModalContainer: {
flex: 1,
},
addFriendModal: {
flex: 1,
backgroundColor: '#ffffff',
borderRadius: 4,
paddingLeft: 15,
paddingRight: 10,
paddingTop: 20,
paddingBottom: 20,
shadowOffset: {
width: 0,
height: 2,
},
shadowRadius: 2,
shadowOpacity: 0.2,
shadowColor: '#000000',
textAlign: 'center',
},
nextButtonContainer: {
marginBottom: 20,
},
nextButton: {
textAlign:'right',
},
friendRow: {
height: 60,
borderBottomWidth: 1,
borderBottomColor: '#eeeeee',
justifyContent: 'flex-start',
},
friendIcon: {
width: 50,
height: 50,
marginRight: 25,
},
roundIconContainer:{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'flex-end',
},
roundIcon: {
height: 20,
width: 20,
borderRadius: 10,
backgroundColor: '#fd6769',
justifyContent: 'center',
alignItems: 'center',
marginRight: 20,
},
})
export default AppView
'using splice but it removes all the contacts at once.'
Because you're using splice method wrong. Check the parameters the method gets. http://www.w3schools.com/jsref/jsref_splice.asp
[ ...this.state.contactsPicked, this.state.contactsPicked.splice(friend)]
this doesn't work as you expected as well. It merges two arrays.
var parts = ['shoulders', 'knees'];
var parts2 = ['shoulders'];
var lyrics = [ ...parts, ...parts2 ];
console.log(lyrics)
It seems you don't have to use spread operator([...arr,.arr2]), you can simply do that
class AppView extends Component {
constructor(props) {
super(props);
this.state = {
isModalVisible: false,
contactsPicked: [],
friendsState: {},
}
}
setModalVisible = visible => {
this.setState({isModalVisible: visible})
}
pickContact = (friend) => {
if(this.state.contactsPicked.indexOf(friend) < 0){
var tempFriendsState = this.state.friendsState
tempFriendsState[friend.id] = true
this.setState({
contactsPicked: [ ...this.state.contactsPicked, friend],
friendsState: tempFriendsState,
})
}
else{
let index = this.state.contactsPicked.indexOf(friend)
let nextContacts = this.state.contactsPicked
nextContacts.splice(index,1)
let tempFriendsState = this.state.friendsState
tempFriendsState[friend.id] = false
this.setState({
contactsPicked: nextContacts,
friendsState: tempFriendsState,
})
}
}
removeContact = (friend) => {
let index = this.state.contactsPicked.indexOf(friend)
let nextContacts = this.state.contactsPicked
let tempFriendsState = this.state.friendsState
tempFriendsState[friend.id] = false
nextContacts.splice(index,1)
console.log('removeContact'+friend.id);
this.setState({
contactsPicked: nextContacts,
friendsState: tempFriendsState,
})
}
_renderAddFriendTile = () => {
return(
<View style={[styles.step, styles.stepThree]}>
<View style={{flex:1}}>
<Text style={styles.heading}>Friend tile</Text>
</View>
{ (this.state.contactsPicked.length) > 0 ?
this.state.contactsPicked.map((contact,index) => (
<TouchableHighlight onPress={() => {this.removeContact(contact)}}>
<View>
<View key={index} style={[styles.row, styles.friendRow]}>
<Image source={contact.image} style={styles.friendIcon}></Image>
<Text style={styles.name}>{contact.firstname} </Text>
<Text style={styles.name}>{contact.surname}</Text>
<View style={styles.roundIconContainer}>
<View style={styles.roundIcon}>
<View style={[styles.removeButton, styles.buttonSmall]}>
<Image source={require('./images/redtree.jpg')} style={styles.crossIconSmall}></Image>
</View>
</View>
</View>
</View>
</View>
</TouchableHighlight>
))
: null
}
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add friends</Text>
</View>
</TouchableHighlight>
</View>
)
}
render(){
return (
<ScrollView style={styles.container}>
<Modal
animationType={'fade'}
transparent={true}
visible={this.state.isModalVisible}
>
<View style={styles.addFriendModalContainer}>
<View style={styles.addFriendModal}>
<TouchableHighlight onPress={() => {this.setModalVisible(false)}}>
<View>
<Text>Close</Text>
</View>
</TouchableHighlight>
<ListView
dataSource={friends}
renderRow={(friend) => {
return (
<FriendRow
friend={friend}
pickContact={this.pickContact}
isSelected={this.state.friendsState[friend.id]}
/>
)
}}
/>
</View>
</View>
</Modal>
{this._renderAddFriendTile()}
</ScrollView>
)
}
}
class FriendRow extends Component {
constructor(props) {
super(props);
this.state = {
isSelected:this.props.isSelected,
}
}
componentDidMount(){
console.log('didmount');
}
render(){
var imageSource = (this.state.isSelected==true) ? require('./images/tree.jpg') : ''
console.log('friend'+!this.props.isSelected)
return(
<TouchableHighlight onPress={() => {this.props.pickContact(this.props.friend);this.setState({isSelected:!this.state.isSelected})}}>
<View style={[styles.row, styles.friendRow]}>
<Image source={this.props.friend.image} style={styles.friendIcon}></Image>
<Text style={styles.name}>{this.props.friend.firstname} </Text>
<Text style={styles.name}>{this.props.friend.surname}</Text>
<View style={styles.roundIconContainer}>
<View style={styles.roundIcon}>
<View style={this.state.isSelected ? [styles.buttonActive, styles.buttonSmall]: [styles.modalButtonInactive, styles.buttonSmall]}>
<Image source={imageSource} style={styles.buttonTickSmall}></Image>
</View>
</View>
</View>
</View>
</TouchableHighlight>
)
}
}