1

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:

enter image description here

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

2 Answers 2

1

'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

  1. Since it re creates subs every time modal's visiblity changes and even if you change state of parent component's state it does not re render subs so you need to keep internal state for you sub components
  2. Also your _renderAddFriendTile method was working wrong too. When you take a look at it carefully you will realize your mistake.
  3. Don't forget to change your icons with my test icons

  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>
        )
    }
}
Sign up to request clarification or add additional context in comments.

18 Comments

Hey, thanks for your reply. I tried your solution but it removes all the contacts and keep the one that should be deleted from the added ones. As for the second question, I'm trying to update the Image of the added icon whether or not a contact has been added.
Great, it works fine now :) Any suggestions regarding my second question?
I went with the subcomponent approach and updated my code. When the Modal is opened, onPress the icons change fine but when closing and opening the Modal again they go back to their default state (inactive). Looks like the state is not kept.
It is probably recreating friends row instead of refreshing. Can you post log results in componentdidmount when closing opening modal. I also edited your question with didmount method and a constructor
Right, I added componentDidMount() and a console.log('didmount'). It returns 'didmount' 8 times when closing opening modal.
|
0

You can use filter method to filter out contacts if it's already there in view.

To remove contacts from view if already added:

this.setState({
  ...state,
  contactsPicked: this.state.contactsPicked.filter((contactsPicked,index)=> index != pickedContactsIndex)          
})

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.