Search code examples
react-nativeradio-buttonflatlist

How to get 2 radio buttons per list item to be selectable for every item in the list. React Native


I have a FlatList, and each item in the List has two radio buttons - one for ascending and one for descending. My code currently allows a user to select either ascending or descending for the first list item, but it will not allow any of the radio buttons to be selected for the other list items (note: only ONE radio button should be selected at any one time). This is because when a radio button is pressed, the state is only being updated with the value of the button ('asc' or 'desc') but not the index of the list item as well. I am struggling to figure out how to update both of these using either onPress (on the RadioButton), or onValueChange (on RadioButton.Group).

How can I update both of these states when a radio button is selected, so that the buttons will work on the other list items and not just the first one?

Link to Snack is here: https://snack.expo.dev/@steph510/multiple-react-radio-buttons

Code is below:

import {View, Text, Modal, StyleSheet, Button, FlatList,} from "react-native";
import { RadioButton } from "react-native-paper";

export default class Sortby extends React.Component {
  constructor(props) {
    super(props);
  }

  state = { 
    selectedIndex: 0,
    radioButtonValue: 'asc',     
  };

  onPress = (index) => {
    this.setState({ 
      selectedIndex: index,       
    });
  }

  onRadiochange = value => {
    this.setState({ 
      radioButtonValue: value,       
    });
  };

  datalist = () => {
    const gridFieldArray = [
      {"text":"Organization","key":"0.6722908010549572"},
      {"text":"Document No","key":"0.13707867638770266"},
      {"text":"Warehouse","key":"0.5240454674464342"},
      {"text":"Business Partner","key":"0.09679684535706568"},
      {"text":"Partner Address","key":"0.5778522746749319"},
      {"text":"Movement Date","key":"0.40039870656646404"}
      ]
    return gridFieldArray;
  };

  render() {
    return (
      <Modal visible={this.props.visible} transparent={true}>
        <View style={styles.modalStyles}>        

          <View style={styles.fieldsContainer}>
            <FlatList
              data={this.datalist()}
              extraData={this.state}
              renderItem={(itemData) => {
                const index = itemData.index;   
                
                return (
                  <View style={styles.fieldItem}>
                    <Text style={styles.fieldText}>{itemData.item.text}</Text>
                    <View style={styles.radioButtonContainer}>
                    <RadioButton.Group onValueChange={this.onRadiochange}>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Asc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="asc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'asc' ? 'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Desc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="desc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'desc' ?  'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      </RadioButton.Group>
                    </View>
                  </View>
                );
              }}
              alwaysBounceVertical={false}
            />
          </View>
          <View style={styles.buttonContainer}>
            <View style={styles.button}>
              <Button title="OK" color={"#5d86d7"}></Button>
            </View>
            <View style={styles.button}>
              <Button
                title="Cancel"
                color={"#5d86d7"}
                onPress={this.props.onCancel}
              ></Button>
            </View>
          </View>
        </View>
      </Modal>
    );
  }
}

const styles = StyleSheet.create({
  modalStyles: {
    height: "auto",
    width: "90%",
    flexDirection: "column",
    justifyContent: "flex-start",
    alignItems: "center",
    backgroundColor: "#fff",
    borderColor: "#777",
    borderWidth: 1,
    paddingTop: 15,
    marginLeft: 20,
    marginTop: 50,
  },
  fieldsContainer: {
    width: "100%",
  },
  fieldItem: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    paddingLeft: 12,
    borderBottomWidth: 1,        
    borderBottomColor: "#ebebeb",
  },
  fieldText: {
    color: "#444",
  },
  radioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
  },
  singleRadioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
    marginRight: 10,
  }, 
  buttonContainer: {
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "center",
    marginTop: 20,
    marginBottom: 20,
  },
  button: {
    width: "20%",
    marginHorizontal: 8,
  },
});

I am adding my now working solution here:

import {View, Text, Modal, StyleSheet, Button, FlatList,} from "react-native";
import { RadioButton } from "react-native-paper";

export default class Sortby extends React.Component {
  constructor(props) {
    super(props);
  }

  state = { 
    selectedIndex: 0,
    radioButtonValue: 'asc',     
  };

  onPress = (index) => {
    this.setState({ 
      selectedIndex: index,       
    });
  }

 onRadiochange = (index, value) => {
    this.setState({ 
      radioButtonValue: value,   
      selectedIndex: index   
    });
  };

  datalist = () => {
    const gridFieldArray = [
      {"text":"Organization","key":"0.6722908010549572"},
      {"text":"Document No","key":"0.13707867638770266"},
      {"text":"Warehouse","key":"0.5240454674464342"},
      {"text":"Business Partner","key":"0.09679684535706568"},
      {"text":"Partner Address","key":"0.5778522746749319"},
      {"text":"Movement Date","key":"0.40039870656646404"}
      ]
    return gridFieldArray;
  };

  render() {
    return (
      <Modal visible={this.props.visible} transparent={true}>
        <View style={styles.modalStyles}>        

          <View style={styles.fieldsContainer}>
            <FlatList
              data={this.datalist()}
              extraData={this.state}
              renderItem={(itemData) => {
                const index = itemData.index;   
                
                return (
                  <View style={styles.fieldItem}>
                    <Text style={styles.fieldText}>{itemData.item.text}</Text>
                    <View style={styles.radioButtonContainer}>
                    <RadioButton.Group onValueChange={value => this.onRadiochange(index, value)}>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Asc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="asc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'asc' ? 'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      <View style={styles.singleRadioButtonContainer}>
                        <Text>Desc</Text>
                        <RadioButton
                          color='#5d86d7'                        
                          value="desc"                      
                          status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'desc' ?  'checked' : 'unchecked'}
                          onPress={() => {this.onPress(index)}}
                        />
                      </View>
                      </RadioButton.Group>
                    </View>
                  </View>
                );
              }}
              alwaysBounceVertical={false}
            />
          </View>
          <View style={styles.buttonContainer}>
            <View style={styles.button}>
              <Button title="OK" color={"#5d86d7"}></Button>
            </View>
            <View style={styles.button}>
              <Button
                title="Cancel"
                color={"#5d86d7"}
                onPress={this.props.onCancel}
              ></Button>
            </View>
          </View>
        </View>
      </Modal>
    );
  }
}

const styles = StyleSheet.create({
  modalStyles: {
    height: "auto",
    width: "90%",
    flexDirection: "column",
    justifyContent: "flex-start",
    alignItems: "center",
    backgroundColor: "#fff",
    borderColor: "#777",
    borderWidth: 1,
    paddingTop: 15,
    marginLeft: 20,
    marginTop: 50,
  },
  fieldsContainer: {
    width: "100%",
  },
  fieldItem: {
    flexDirection: "row",
    alignItems: "center",
    justifyContent: "space-between",
    paddingLeft: 12,
    borderBottomWidth: 1,        
    borderBottomColor: "#ebebeb",
  },
  fieldText: {
    color: "#444",
  },
  radioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
  },
  singleRadioButtonContainer: {
    flexDirection: "row",
    justifyContent: "flex-start",
    alignItems: "center",
    marginRight: 10,
  }, 
  buttonContainer: {
    flexDirection: "row",
    justifyContent: "center",
    alignItems: "center",
    marginTop: 20,
    marginBottom: 20,
  },
  button: {
    width: "20%",
    marginHorizontal: 8,
  },
});```

Solution

  • This is the solution that I came up with. Thanks to all who assisted:

    import {View, Text, Modal, StyleSheet, Button, FlatList,} from "react-native";
    import { RadioButton } from "react-native-paper";
    
    export default class Sortby extends React.Component {
      constructor(props) {
        super(props);
      }
    
      state = { 
        selectedIndex: 0,
        radioButtonValue: 'asc',     
      };
    
      onPress = (index) => {
        this.setState({ 
          selectedIndex: index,       
        });
      }
    
     onRadiochange = (index, value) => {
        this.setState({ 
          radioButtonValue: value,   
          selectedIndex: index   
        });
      };
    
      datalist = () => {
        const gridFieldArray = [
          {"text":"Organization","key":"0.6722908010549572"},
          {"text":"Document No","key":"0.13707867638770266"},
          {"text":"Warehouse","key":"0.5240454674464342"},
          {"text":"Business Partner","key":"0.09679684535706568"},
          {"text":"Partner Address","key":"0.5778522746749319"},
          {"text":"Movement Date","key":"0.40039870656646404"}
          ]
        return gridFieldArray;
      };
    
      render() {
        return (
          <Modal visible={this.props.visible} transparent={true}>
            <View style={styles.modalStyles}>        
    
              <View style={styles.fieldsContainer}>
                <FlatList
                  data={this.datalist()}
                  extraData={this.state}
                  renderItem={(itemData) => {
                    const index = itemData.index;   
                    
                    return (
                      <View style={styles.fieldItem}>
                        <Text style={styles.fieldText}>{itemData.item.text}</Text>
                        <View style={styles.radioButtonContainer}>
                        <RadioButton.Group onValueChange={value => this.onRadiochange(index, value)}>
                          <View style={styles.singleRadioButtonContainer}>
                            <Text>Asc</Text>
                            <RadioButton
                              color='#5d86d7'                        
                              value="asc"                      
                              status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'asc' ? 'checked' : 'unchecked'}
                              onPress={() => {this.onPress(index)}}
                            />
                          </View>
                          <View style={styles.singleRadioButtonContainer}>
                            <Text>Desc</Text>
                            <RadioButton
                              color='#5d86d7'                        
                              value="desc"                      
                              status={ this.state.selectedIndex === index && this.state.radioButtonValue === 'desc' ?  'checked' : 'unchecked'}
                              onPress={() => {this.onPress(index)}}
                            />
                          </View>
                          </RadioButton.Group>
                        </View>
                      </View>
                    );
                  }}
                  alwaysBounceVertical={false}
                />
              </View>
              <View style={styles.buttonContainer}>
                <View style={styles.button}>
                  <Button title="OK" color={"#5d86d7"}></Button>
                </View>
                <View style={styles.button}>
                  <Button
                    title="Cancel"
                    color={"#5d86d7"}
                    onPress={this.props.onCancel}
                  ></Button>
                </View>
              </View>
            </View>
          </Modal>
        );
      }
    }
    
    const styles = StyleSheet.create({
      modalStyles: {
        height: "auto",
        width: "90%",
        flexDirection: "column",
        justifyContent: "flex-start",
        alignItems: "center",
        backgroundColor: "#fff",
        borderColor: "#777",
        borderWidth: 1,
        paddingTop: 15,
        marginLeft: 20,
        marginTop: 50,
      },
      fieldsContainer: {
        width: "100%",
      },
      fieldItem: {
        flexDirection: "row",
        alignItems: "center",
        justifyContent: "space-between",
        paddingLeft: 12,
        borderBottomWidth: 1,        
        borderBottomColor: "#ebebeb",
      },
      fieldText: {
        color: "#444",
      },
      radioButtonContainer: {
        flexDirection: "row",
        justifyContent: "flex-start",
        alignItems: "center",
      },
      singleRadioButtonContainer: {
        flexDirection: "row",
        justifyContent: "flex-start",
        alignItems: "center",
        marginRight: 10,
      }, 
      buttonContainer: {
        flexDirection: "row",
        justifyContent: "center",
        alignItems: "center",
        marginTop: 20,
        marginBottom: 20,
      },
      button: {
        width: "20%",
        marginHorizontal: 8,
      },
    });```