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

Time:06-24

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,
  },
});```

CodePudding user response:

You'll need to keep track of the radio button state for each index. Right now you only have one piece of "global" state that each component in the list relies on. You could set up that state as an object instead:

  state = { 
    selectedIndex: 0,
    radioButtonValues: {},     
  };
  ...

  onRadiochange = (index, value) => {
    this.setState({ 
      radioButtonValues: {
        ...this.state.radioButtonValues,
        [index]: value,
      }       
    });
  };
  ...
  // in render
  <RadioButton.Group onValueChange={value => this.onRadiochange(index, value)}>

If nothing at this (parent) level needs to know about the ascending/descending of the internal list, consider moving the component defined inline in your renderItem out to its own component with its own state. Then you wouldn't need to know the index of the item to set the sort order, since each item would only affect itself. You would have to pass in the setter for the selected index to the new component. If this doesn't make sense and an example would help let me know.

  • Related