Reputation: 639
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
edit 2: what if the api contains an object with data saved already, how do i edit that new data?
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
Upvotes: 2
Views: 935
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
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
);
}}
/>
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({});
Upvotes: 2
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