Nicolas Silva
Nicolas Silva

Reputation: 639

How do i set and get the different states and inputs from a flatlist with multiple objects

ok i got this flatlist contained within a flatlist, and the flatlist from inside, contains dropdowns, inputs, and buttons that i need to capture which data i'm getting from them, and of course save the new data based on what i selected, typed in or clicked, i'm not entirely sure how to do this, this is the code for flatlist

                <FlatList
              extraData = {this.state}
              data = {this.state.dataSource}
              renderItem = {({item, index}) => {
                return (
                  <View style={{marginTop: hp('2%')}}>
                    <TouchableOpacity style={{
                      alignSelf: 'center',
                      width: wp('95.7%'),
                      height: hp('10%'),
                      backgroundColor: "#ffffff",
                    }} onPress={() => this.toggleExpanded()}>
                      <View style={{flex: 1, flexDirection: 'row', justifyContent: 'space-between'}}>
                        <View style={{flexDirection: 'column', justifyContent: 'center'}}>
                          <Text numberOfLines={2} ellipsizeMode="tail" style={{
                            marginLeft: wp('5%'),
                            width: wp('55%'),//wp('38.2%'), //151
                            //height: hp('2%'), //19
                            fontSize: rfv(16),
                            fontWeight: "500",
                            fontStyle: "normal",
                            textAlign: "left",
                            color: "#707070"
                          }}>{item.Title}</Text>
                          <Text style={{
                            marginLeft: wp('5%'),
                            fontSize: rfv(14),
                            fontWeight: "normal",
                            fontStyle: "normal",
                            textAlign: "left",
                            color: "#c4c4c4"
                          }}>{`ID ${item.Id} - ${item.Cliente}`}</Text>
                        {
                          !item.IsFavorite ?
                          <Text style={{
                            marginLeft: wp('5%'),
                            fontSize: rfv(14),
                            fontWeight: "normal",
                            fontStyle: "italic",
                            textAlign: "left",
                            color: "#c4c4c4"
                          }}>No favorito</Text>
                          : null
                        }
                        </View>
                        <View style={{flexDirection: 'column', justifyContent: 'center'}}>
                          <View style={{flexDirection: 'row', marginRight: wp('3.4%')}}>
                            <Text style={{
                              fontSize: rfv(18),
                              fontWeight: "300",
                              fontStyle: "normal",
                              textAlign: "right",
                              color: "#707070"}}>{`${0}h`}</Text>
                            <Image style={{marginTop: hp('1%'), marginLeft: wp('3.7%')}} source={this.state.isCollapsed ? Images.expandible : Images.collapsible}/>
                          </View>
                        </View>
                      </View>
                    </TouchableOpacity>
                    <Collapsible style={{
                      alignSelf: 'center',
                      width: wp('95.7%'),
                      backgroundColor: "#ffffff",}} collapsed={this.state.isCollapsed}>

                    <FlatList
                      //extraData = {this.state}
                      data = {item.ListReportHistoryResponse}//{DataManager.FavoriteList[moment(this.state.selectedDate).format('YYYY-MM-DD')]}
                      renderItem = {({ item, index }) => {
                        return (
                          <View>
                          <View style={{flexDirection: 'row'}}>
                            <Text style={{
                              marginLeft: wp('5%'),
                              fontSize: rfv(14),
                              fontWeight: "normal",
                              fontStyle: "normal",
                              textAlign: "left",
                              color: "#717171"
                            }}>Etapa</Text>
                            <Text style={{
                              marginLeft: wp('42.5%'),
                              fontSize: rfv(14),
                              fontWeight: "normal",
                              fontStyle: "normal",
                              textAlign: "left",
                              color: "#717171"
                            }}>Horas</Text>
                          </View>
                          <View style={{flexDirection: 'row'}}>
                            <ModalDropdown
                              adjustFrame={style => {
                                style.top =(Platform.OS === 'ios' ? style.top : style.top - StatusBar.currentHeight);
                                return style;
                              }}
                              dropdownTextStyle={styles.dropdownTextStyle}
                              dropdownTextHighlightStyle={styles.dropdownTextHighlightStyle}
                              dropdownStyle={styles.dropdownStageStyle}
                              defaultValue={item.Etapa}
                              style={styles.dropStageStyle}
                              textStyle={{
                                padding: 0,
                                margin: 0,
                                fontSize: rfv(16),
                                paddingVertical: hp('1.2%'),
                                fontWeight: 'normal',
                                fontStyle: 'normal',
                                textAlign: 'left',
                                color: item.Etapa /*item.ListReportHistoryResponse[index2].Etapa*/ != 'Selecciona una etapa' ? '#1a1a1a' : '#c4c4c4',
                              }}
                              //onSelect={(index, value) => this.setState({SeleccionClientes: value})}
                              //options={Object.keys(this.state.items)}
                              onSelect={(index, value) => this.setState({SeleccionClientes: value})}
                              options={DataManager.ListEtapa}
                            />
                            <View style={styles.InputContainerHours}>
                              <Text style={styles.InputTextHours}>{item.HorasTrabajadas}</Text>
                            </View>
                            <TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('5.5%')}} onPress={() => this.props.onSubstract}>
                              <Image source={Images.menos_hora}/>
                            </TouchableOpacity>
                            <TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('2%')}} onPress={() => this.props.onAdd}>
                              <Image source={Images.mas_hora}/>
                            </TouchableOpacity>
                          </View>
                          <Text style={{
                            fontSize: rfv(14),
                            marginLeft: wp('5%'),
                            fontWeight: "normal",
                            fontStyle: "normal",
                            textAlign: "left",
                            color: "#717171"
                          }}>Observaciones</Text>
                          <Input
                            autoCapitalize="none"
                            maxLength={100}
                            inputContainerStyle={styles.InputContainerComentarioOnBlur}
                            containerStyle={styles.InputComentario}
                            inputStyle={styles.InputTextHoursRInput}
                            placeholderTextColor={'#c4c4c4'}
                            placeholder="(Opcional)"
                            onChangeText={value => this.setState({})}
                          />
                          <TouchableOpacity style={{alignItems: 'flex-end', alignSelf: 'flex-end'}}>
                            <Text style={{
                              marginRight: wp('3.4%'),
                              marginBottom: hp('3%'),
                              fontSize: rfv(14),
                              fontWeight: "normal",
                              fontStyle: "normal",
                              textAlign: "left",
                              color: "#1062cc"
                            }}>Agregar etapa</Text>
                          </TouchableOpacity>
                        </View>
                        )}}/>
                        </Collapsible>
                        </View>
                )
              }}
            />

EDIT: updated with screenshot of the object displayed in flatlist, i still need help getting this to work

<View style={styles.InputContainerHours}>
<Text style={styles.InputTextHours}>{item.HorasTrabajadas}</Text>
</View>
<TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('5.5%')}} onPress={() => this.props.onSubstract}>
<Image source={Images.menos_hora}/>
</TouchableOpacity>
<TouchableOpacity style={{marginTop: hp('0.5%'), marginLeft: wp('2%')}} onPress={() => this.props.onAdd}>
<Image source={Images.mas_hora}/>
</TouchableOpacity>

the onadd is supposed function that adds to item.HorasTrabajadas, 0.5 in addition to the current value, and the onsubstract is the same but substracts to the current value

and here is the object

enter image description here

edit 2: what if the api contains an object with data saved already, how do i edit that new data?

enter image description here

edit 3: i added a github project with the 3 most important parts of this project, https://github.com/Vasault/HourReg/tree/develop contains 3 files, the most important one HourRegistration.tsx

edit 4: unable to change data that already come from api

enter image description here

Upvotes: 2

Views: 935

Answers (3)

Nicolas Silva
Nicolas Silva

Reputation: 639

SOLVED, in a much better and easier way

on every input, dropdown, etc. set a function and pass 3 parameters onChangeText={value => this.onChangeTextObservaciones(parentIndex, childIndex, value)

parentIndex (the one from outside flatlist), childIndex (the one from inside), and the value you're editing (blank or not)

const onChangeTextObservaciones = (indexOutside, indexInside, value) => {
    this.dataList[indexOutside].ListReportHistoryResponse[indexInside].Title = value;
    this.setState({displayDay: this.dataList});
}

change the specific value from the specific element from that object, and change it with the new value, and lastly change the whole new object with the new value.

a friend of mine realize this

Upvotes: 1

Muhammad Numan
Muhammad Numan

Reputation: 25343

you can make dynamic state by append parentIndex and childIndex to state to uniquely identify of item of child flatlist

you can use onChangeValue for save data into newDataSave object and getDataFromNewSave for get data from newDataSave

Note: you all saving data is saving in newDataSave object. you can console to check it and save into database.

 onChangeValue = (key, value) => {
    this.setState((prevState) => {
      return {
        newDataSave: {
          ...prevState.newDataSave,
          [key]: value,
        },
      };
    });
  };

  getDataFromNewSave = (key) => {
    try {
      return this.state.newDataSave[key];
    } catch (error) {
      return "";
    }
  };
<Input
                            value={this.getDataFromNewSave(
                              `input${parentIndex}${childIndex}`
                            )}
                            autoCapitalize="none"
                            maxLength={100}
                            inputContainerStyle={
                              styles.InputContainerComentarioOnBlur
                            }
                            containerStyle={styles.InputComentario}
                            inputStyle={styles.InputTextHoursRInput}
                            placeholderTextColor={"#c4c4c4"}
                            placeholder="(Opcional)"
                            onChangeText={(value) => {
                              this.onChangeValue(
                                `input${parentIndex}${childIndex}`,
                                value
                              );
                            }}
                          />

Full Code:

import React, { Component } from "react";
import {
  Text,
  StyleSheet,
  View,
  FlatList,
  TouchableOpacity,
  Image,
  TextInput,
} from "react-native";
import {
  widthPercentageToDP as wp,
  heightPercentageToDP as hp,
} from "react-native-responsive-screen";
import Collapsible from "react-native-collapsible";
import ModalDropdown from "react-native-modal-dropdown";

const Input = TextInput;
const rfv = (value) => {
  return value;
};

const DataManager = {
  ListEtapa: ["a", "b", "c"],
};

const Images = {
  collapsed: require("./assets/icons/app-icon.png"),
  expandible: require("./assets/icons/app-icon.png"),
};

export default class App extends Component {
  state = {
    isCollapsed: false,
    dataSource: [
      {
        Id: "1",
        Title: "abc1",
        Cliente: "abc1",
        IsFavorite: false,
        ListReportHistoryResponse: [
          { Etapa: "abc1", HorasTrabajadas: "abcabc1" },
          { Etapa: "cde1", HorasTrabajadas: "cdecde1" },
        ],
      },
      {
        Id: "2",
        Title: "abc2",
        Cliente: "abc2",
        IsFavorite: false,
        ListReportHistoryResponse: [
          { Etapa: "abc2", HorasTrabajadas: "abcabc2" },
          { Etapa: "cde2", HorasTrabajadas: "cdecde2" },
        ],
      },
    ],
    newDataSave: {},
  };

  onChangeValue = (key, value) => {
    this.setState((prevState) => {
      return {
        newDataSave: {
          ...prevState.newDataSave,
          [key]: value,
        },
      };
    });
  };

  getDataFromNewSave = (key) => {
    try {
      return this.state.newDataSave[key];
    } catch (error) {
      return "";
    }
  };

  render() {
    return (
      <View>
        <FlatList
          extraData={this.state}
          data={this.state.dataSource}
          renderItem={({ item, index: parentIndex }) => {
            return (
              <View style={{ marginTop: hp("2%") }}>
                <TouchableOpacity
                  style={{
                    alignSelf: "center",
                    width: wp("95.7%"),
                    height: hp("10%"),
                    backgroundColor: "#ffffff",
                  }}
                  onPress={() => this.toggleExpanded()}
                >
                  <View
                    style={{
                      flex: 1,
                      flexDirection: "row",
                      justifyContent: "space-between",
                    }}
                  >
                    <View
                      style={{
                        flexDirection: "column",
                        justifyContent: "center",
                      }}
                    >
                      <Text
                        numberOfLines={2}
                        ellipsizeMode="tail"
                        style={{
                          marginLeft: wp("5%"),
                          width: wp("55%"), //wp('38.2%'), //151
                          //height: hp('2%'), //19
                          fontSize: rfv(16),
                          fontWeight: "500",
                          fontStyle: "normal",
                          textAlign: "left",
                          color: "#707070",
                        }}
                      >
                        {item.Title}
                      </Text>
                      <Text
                        style={{
                          marginLeft: wp("5%"),
                          fontSize: rfv(14),
                          fontWeight: "normal",
                          fontStyle: "normal",
                          textAlign: "left",
                          color: "#c4c4c4",
                        }}
                      >{`ID ${item.Id} - ${item.Cliente}`}</Text>
                      {!item.IsFavorite ? (
                        <Text
                          style={{
                            marginLeft: wp("5%"),
                            fontSize: rfv(14),
                            fontWeight: "normal",
                            fontStyle: "italic",
                            textAlign: "left",
                            color: "#c4c4c4",
                          }}
                        >
                          No favorito
                        </Text>
                      ) : null}
                    </View>
                    <View
                      style={{
                        flexDirection: "column",
                        justifyContent: "center",
                      }}
                    >
                      <View
                        style={{
                          flexDirection: "row",
                          marginRight: wp("3.4%"),
                        }}
                      >
                        <Text
                          style={{
                            fontSize: rfv(18),
                            fontWeight: "300",
                            fontStyle: "normal",
                            textAlign: "right",
                            color: "#707070",
                          }}
                        >{`${0}h`}</Text>
                        <Image
                          style={{
                            marginTop: hp("1%"),
                            marginLeft: wp("3.7%"),
                          }}
                          source={
                            this.state.isCollapsed
                              ? Images.expandible
                              : Images.collapsible
                          }
                        />
                      </View>
                    </View>
                  </View>
                </TouchableOpacity>
                <Collapsible
                  style={{
                    alignSelf: "center",
                    width: wp("95.7%"),
                    backgroundColor: "#ffffff",
                  }}
                  collapsed={this.state.isCollapsed}
                >
                  <FlatList
                    //extraData = {this.state}
                    data={item.ListReportHistoryResponse} //{DataManager.FavoriteList[moment(this.state.selectedDate).format('YYYY-MM-DD')]}
                    renderItem={({ item, index: childIndex }) => {
                      return (
                        <View>
                          <View style={{ flexDirection: "row" }}>
                            <Text
                              style={{
                                marginLeft: wp("5%"),
                                fontSize: rfv(14),
                                fontWeight: "normal",
                                fontStyle: "normal",
                                textAlign: "left",
                                color: "#717171",
                              }}
                            >
                              Etapa
                            </Text>
                            <Text
                              style={{
                                marginLeft: wp("42.5%"),
                                fontSize: rfv(14),
                                fontWeight: "normal",
                                fontStyle: "normal",
                                textAlign: "left",
                                color: "#717171",
                              }}
                            >
                              Horas
                            </Text>
                          </View>
                          <View style={{ flexDirection: "row" }}>
                            <ModalDropdown
                              adjustFrame={(style) => {
                                style.top =
                                  Platform.OS === "ios"
                                    ? style.top
                                    : style.top - StatusBar.currentHeight;
                                return style;
                              }}
                              dropdownTextStyle={styles.dropdownTextStyle}
                              dropdownTextHighlightStyle={
                                styles.dropdownTextHighlightStyle
                              }
                              dropdownStyle={styles.dropdownStageStyle}
                              defaultValue={this.getDataFromNewSave(
                                `SeleccionClientes${parentIndex}${childIndex}`
                              )}
                              style={styles.dropStageStyle}
                              textStyle={{
                                padding: 0,
                                margin: 0,
                                fontSize: rfv(16),
                                paddingVertical: hp("1.2%"),
                                fontWeight: "normal",
                                fontStyle: "normal",
                                textAlign: "left",
                                color:
                                  item.Etapa /*item.ListReportHistoryResponse[index2].Etapa*/ !=
                                  "Selecciona una etapa"
                                    ? "#1a1a1a"
                                    : "#c4c4c4",
                              }}
                              //onSelect={(index, value) => this.setState({SeleccionClientes: value})}
                              //options={Object.keys(this.state.items)}
                              onSelect={(i, value) =>
                                // this.setState({ SeleccionClientes: value })
                                this.onChangeValue(
                                  `SeleccionClientes${parentIndex}${childIndex}`,
                                  value
                                )
                              }
                              options={DataManager.ListEtapa}
                            />
                            <View style={styles.InputContainerHours}>
                              <Text style={styles.InputTextHours}>
                                {item.HorasTrabajadas}
                              </Text>
                            </View>
                            <TouchableOpacity
                              style={{
                                marginTop: hp("0.5%"),
                                marginLeft: wp("5.5%"),
                              }}
                              onPress={() => this.props.onSubstract}
                            >
                              <Image source={Images.menos_hora} />
                            </TouchableOpacity>
                            <TouchableOpacity
                              style={{
                                marginTop: hp("0.5%"),
                                marginLeft: wp("2%"),
                              }}
                              onPress={() => this.props.onAdd}
                            >
                              <Image source={Images.mas_hora} />
                            </TouchableOpacity>
                          </View>
                          <Text
                            style={{
                              fontSize: rfv(14),
                              marginLeft: wp("5%"),
                              fontWeight: "normal",
                              fontStyle: "normal",
                              textAlign: "left",
                              color: "#717171",
                            }}
                          >
                            Observaciones
                          </Text>
                          <Input
                            value={this.getDataFromNewSave(
                              `input${parentIndex}${childIndex}`
                            )}
                            autoCapitalize="none"
                            maxLength={100}
                            inputContainerStyle={
                              styles.InputContainerComentarioOnBlur
                            }
                            containerStyle={styles.InputComentario}
                            inputStyle={styles.InputTextHoursRInput}
                            placeholderTextColor={"#c4c4c4"}
                            placeholder="(Opcional)"
                            onChangeText={(value) => {
                              this.onChangeValue(
                                `input${parentIndex}${childIndex}`,
                                value
                              );
                            }}
                          />
                          <TouchableOpacity
                            style={{
                              alignItems: "flex-end",
                              alignSelf: "flex-end",
                            }}
                          >
                            <Text
                              style={{
                                marginRight: wp("3.4%"),
                                marginBottom: hp("3%"),
                                fontSize: rfv(14),
                                fontWeight: "normal",
                                fontStyle: "normal",
                                textAlign: "left",
                                color: "#1062cc",
                              }}
                            >
                              Agregar etapa
                            </Text>
                          </TouchableOpacity>
                        </View>
                      );
                    }}
                  />
                </Collapsible>
              </View>
            );
          }}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({});

enter image description here

Upvotes: 2

Waheed Akhtar
Waheed Akhtar

Reputation: 3187

You can use the index of your array to identify the selected item, and when you have an index of every time you can update the item on every action according to your need.

Let suppose you have 10 items and on every item, you have to update the state you can get the item and index of that row and can update the state easily.

Here is a simple example that can clear your confusion. And here is a snack with a working example

https://snack.expo.io/@waheed25/radarada

import React from 'react';
import { SafeAreaView, View, TextInput, FlatList, StyleSheet, Text } from 'react-native';
import Constants from 'expo-constants';

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 class  App extends React.Component {

  state={
    observacionesInput: []
  }
   onTextObservacionesChange = (text, index) => {
    var { observacionesInput } = this.state
    let myArray = observacionesInput
        myArray[index] = text
    this.setState({observacionesInput: myArray });
  }
  toggleExpanded = () => {
    this.setState({ isCollapsed: !this.state.isCollapsed });  
  };
  render(){
    console.log('state', this.state)
  return (
    <SafeAreaView>
    <Text>Testing</Text>
      <FlatList
        data={DATA}
        renderItem={({ item, index }) => { 
          return(
            <View style={{  marginTop: 20}}>
              <TextInput
               style={{borderColor: 'gray', borderWidth: 1, height: 50,}}
                autoCapitalize="none"
                maxLength={100}
                placeholderTextColor={'#c4c4c4'}
                placeholder="(Opcional)"
                onChangeText={value => this.onTextObservacionesChange(value, index)}
              />
            </View>
          )
        }}
      />
    </SafeAreaView>
  );
  }
}

Upvotes: 2

Related Questions