Select and unselect component when one is selected - react-native

I've to display three components (cards) from which the user can select one. I've placed those three components inside a ScrollView as:
...
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
<LocationAndPriceCard
price={'100'}
title={'Choice 3'} />
<LocationAndPriceCard
price={'200'}
title={'Choice 2'} />
<LocationAndPriceCard
price={'300'}
title={'Choice 1'}} />
</ScrollView>
...
Here is how LocationAndPriceCard is coded:
...
function LocationAndPriceCard({ price, title }) {
const [selectedLocation, setSelectedLocation] = useState("red")
const styles = getStyles(selectedLocation);
const selected = () => {
if (selectedLocation == "red") {
setSelectedLocation("green")
} else {
setSelectedLocation("red")
}
}
return (
<TouchableOpacity style={styles.frame} onPress={selected}>
<Text style={styles.priceTxt}>RM {price}</Text>
<Text style={styles.title} numberOfLines={2}>{title}</Text>
</TouchableOpacity>
);
}
const getStyles = (borderC) => StyleSheet.create({
frame: {
borderWidth: 1,
borderColor: borderC,
width: 180,
backgroundColor: '#fff',
borderRadius: 8,
margin: 5,
padding: 10,
},
...
In the code above when the cad has selected it successfully change the border color to green but I can change the color of all the components. I want to make it like if one is selected all others should go back to red color.

Create two new props for LocationAndPriceCard, value and onPress.
Use value to determine which card is selected and based on that change the border color.
Use the onPress function to set the state which will have the title of the selected card, which we will be used to determine which card is selected.
Full Working Example: Expo Snack
import React, { useState } from 'react';
import {
Text,
View,
StyleSheet,
ScrollView,
TouchableOpacity,
} from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default function App() {
const [selected, setSelected] = useState(null);
const handleSelected = (value) => {
setSelected(value);
};
return (
<View style={styles.container}>
<ScrollView horizontal={true} showsHorizontalScrollIndicator={false}>
<LocationAndPriceCard
price={'100'}
title={'Choice 3'}
onPress={handleSelected}
value={selected}
/>
<LocationAndPriceCard
price={'200'}
title={'Choice 2'}
onPress={handleSelected}
value={selected}
/>
<LocationAndPriceCard
price={'300'}
title={'Choice 1'}
onPress={handleSelected}
value={selected}
/>
</ScrollView>
</View>
);
}
function LocationAndPriceCard({ price, title, onPress, value }) {
return (
<TouchableOpacity
style={[styles.frame, { borderColor: value === title?"green":"red" }]}
onPress={()=>onPress(title)}>
<Text style={styles.priceTxt}>RM {price}</Text>
<Text style={styles.title} numberOfLines={2}>
{title}
</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
frame: {
borderWidth: 1,
width: 50,
height: 50,
backgroundColor: '#fff',
borderRadius: 8,
margin: 5,
padding: 10,
},
});

Related

How to expand card onPress - React Native

I am trying to make a ticket app that allows for people to create tickets based on work that needs done. Right now, I need help with the expandable view for each ticket card. What I'm wanting is when a user presses on a specific card, it will expand the view and provide more details for only that card. What it is currently doing is expanding the view for every ticket card in the list. I'm new to React Native and trying my best, but nothing has worked so far.
Here is my parent which is called Home:
import React, {useState, useEffect} from 'react';
import {styles, Colors} from '../components/styles';
import { SafeAreaView } from 'react-native';
import Ticket from '../components/Ticket';
const data = [
{
name: 'Josh Groban',
subject: 'U-Joint',
desc: 'The bolt that is meant to hold the u-joint in place has the head broken off from it. See attached picture.',
assignee: 'John Doe',
assigneeConfirmedComplete: 'NA',
dateReported: 'Tue Mar 8, 2022',
vehicle: 'Truck 1',
media: '',
key: '1',
isShowing: false
},
// code removed for brevity
];
const Home = ({navigation}) => {
const [ticketList, setTicketList] = useState(data);
const getTickets = () => {
setTicketList(data);
}
useEffect(() => {
getTickets();
}, []);
return (
<SafeAreaView style={styles.HomeContainer}>
<Ticket
ticketList={ticketList}
setTicketList={setTicketList}
/>
</SafeAreaView>
)
};
export default Home;
And here is the main component that has all of the ticket card configurations:
import React, {useState, useEffect} from 'react';
import {Text, FlatList, View, SafeAreaView, Button, Image, TouchableOpacity } from 'react-native';
import {styles, Colors} from './styles';
import {Ionicons} from '#expo/vector-icons';
const Ticket = ({ticketList, setTicketList}) => {
const defaultImage = 'https://airbnb-clone-prexel-images.s3.amazonaws.com/genericAvatar.png';
const [isComplete, setIsComplete] = useState(false);
const [show, setShow] = useState(false);
const showContent = (data) => {
const isShowing = {...data, isShowing}
if (isShowing)
setShow(!show);
}
const completeTask = () => {
setIsComplete(!isComplete);
}
return (
<SafeAreaView style={{flex: 1}}>
<FlatList showsVerticalScrollIndicator={false}
data={ticketList}
renderItem={(data) => {
return (
<>
<TouchableOpacity key={data.item.key} onPress={() => showContent(data.item.isShowing = true)}>
<View style={styles.TicketCard}>
<Image
style={styles.TicketCardImage}
source={{uri: defaultImage}}
/>
<View style={styles.TicketCardInner}>
<Text style={styles.TicketCardName}>{data.item.vehicle}</Text>
<Text style={styles.TicketCardSubject}>
{data.item.subject}
</Text>
</View>
<TouchableOpacity>
<Ionicons
name='ellipsis-horizontal-circle'
color={Colors.brand}
size={50}
style={styles.TicketCardImage}
/>
</TouchableOpacity>
<TouchableOpacity onPress={completeTask}>
<Ionicons
name={isComplete ? 'checkbox-outline' : 'square-outline'}
color={Colors.brand}
size={50}
style={styles.TicketCardButton}
/>
</TouchableOpacity>
</View>
<View style={styles.TicketCardExpand}>
<Text>
{show &&
(<View style={{padding: 10}}>
<Text style={styles.TicketCardDesc}>
{data.item.desc}
</Text>
<Text style={{padding: 5}}>
Reported by: {data.item.name}
</Text>
<Text style={{padding: 5}}>
Reported: {data.item.dateReported}
</Text>
{isComplete && (
<Text style={{padding: 5}}>
Confirmed Completion: {data.item.assigneeConfirmedComplete}
</Text>
)}
</View>
)}
</Text>
</View>
</TouchableOpacity>
</>
)}}
/>
</SafeAreaView>
)
};
export default Ticket;
Lastly, here are the styles that i'm using:
import {StyleSheet } from "react-native";
import { backgroundColor } from "react-native/Libraries/Components/View/ReactNativeStyleAttributes";
// colors
export const Colors = {
bg: '#eee',
primary: '#fff',
secondary: '#e5e7eb',
tertiary: '#1f2937',
darkLight: '#9ca3f9',
brand: '#1d48f9',
green: '#10b981',
red: '#ff2222',
black: '#000',
dark: '#222',
darkFont: '#bbb',
gray: '#888'
}
export const styles = StyleSheet.create({
HomeContainer: {
flex: 1,
paddingBottom: 0,
backgroundColor: Colors.bg,
},
TicketCard : {
padding: 10,
justifyContent: 'space-between',
borderColor: Colors.red,
backgroundColor: Colors.primary,
marginTop: 15,
flexDirection: 'row',
},
TicketCardExpand: {
justifyContent: 'space-between',
backgroundColor: Colors.primary,
},
TicketCardImage: {
width: 60,
height: 60,
borderRadius: 30
},
TicketCardName:{
fontSize: 17,
fontWeight: 'bold'
},
TicketCardSubject: {
fontSize: 16,
paddingBottom: 5
},
TicketCardDesc: {
fontSize: 14,
flexWrap: 'wrap',
},
TicketCardInner: {
flexDirection: "column",
width: 100
},
TicketCardButton: {
height: 50,
}
});
Any help is greatly appreciated!
Create a Ticket component with its own useState.
const Ticket = (data) => {
const [isOpen, setIsOpen] = useState(false);
const handlePress = () => {
setIsOpen(!isOpen);
}
return (
<TouchableOpacity
onPress={handlePress}
>
// data.item if you use a list, otherwise just data
<YourBasicInformation data={data.item} />
{isOpen && <YourDetailedInformation data={data.item} />}
</TouchableOpacity>
)
}
Render one Ticket for every dataset you have.
<List
style={styles.list}
data={yourDataArray}
renderItem={Ticket}
/>
If you don't want to use a List, map will do the job.
{yourDataArray.map((data) => <Ticket data={data} />)}
instead of setting show to true or false you can set it to something unique to each card like
setShow(card.key or card.id or smth)
and then you can conditionally render details based on that like
{show == card.key && <CardDetails>}
or you can make an array to keep track of open cards
setShow([...show,card.id])
{show.includes(card.id) && <CardDetails>}
//to remove
setShow(show.filter((id)=>id!=card.id))

How do I manage multiple user inputs with only one onChange in React Native?

How do I handle multiple text inputs with only one onChange on React Native?
For example:
Name, age, nationality, eye color.
Additionally, how do I save all of the inputs with only one button? (I want to output a list with all of these inputs in the same "item")
Here's my code with what I did so far, I want to make a sort of movie diary where the user can register new movies they want to watch: (I'm a total beginner btw, so I'm not sure about how to do most things. I'm doing this project to learn)
import React, { useState } from 'react';
import { Button, StyleSheet, View, Text, TextInput, ScrollView } from 'react-native';
import AsyncStorage from '#react-native-async-storage/async-storage';
const Registration = props => {
const [enteredMovieName, setMovieName] = useState("");
const [enteredSynopsis, setSynopsis] = useState("");
const [enteredComments, setComments] = useState("");
const [enteredSource, setSource] = useState("");
const movieData = {
Name: enteredMovieName,
Synopsis: enteredSynopsis,
Comments: enteredComments,
Source: enteredSource,
};
const movieDataHandler = () => {
console.log(movieData);
};
return (
<ScrollView>
<View>
<View>
<Text style={styles.bodyHighlight}>Add new movie</Text>
</View>
<ScrollView>
<View>
<Text style={styles.addMovie} >Movie name:</Text>
<TextInput
placeholder='Cool Movie Name'
style={styles.inputContainer}
onChangeText={enteredText => setMovieName(enteredText)}
value={enteredMovieName}
/>
<Text style={styles.addMovie} >Sinopsis:</Text>
<TextInput
placeholder='Amazing Synopsis'
style={styles.inputContainer}
onChangeText={enteredText => setSynopsis(enteredText)}
value={enteredSynopsis}
/>
<Text style={styles.addMovie} >Comments (optional):</Text>
<TextInput
placeholder='Awesome Thoughts'
style={styles.inputContainer}
onChangeText={enteredText => setComments(enteredText)}
value={enteredComments}
/>
<Text style={styles.addMovie} >Where to watch (optional):</Text>
<TextInput
placeholder='Super Useful Link'
style={styles.inputContainer}
onChangeText={enteredText => setSource(enteredText)}
value={enteredSource}
/>
</View>
<View>
<Button
style={styles.addMovie}
title='ADD'
color='#a30b00'
onPress={movieDataHandler}
/>
<Button
style={styles.addMovie}
title='SEE COMPLETE LIST'
color='#cd5c5c'
onPress={() => {
props.navigation.navigate('Items Screen');
}}
/>
</View>
</ScrollView>
</View >
</ScrollView>
)
}
const styles = StyleSheet.create({
bodyHighlight: {
padding: 10,
margin: 5,
fontWeight: 'bold',
fontSize: 25,
textAlign: 'center',
backgroundColor: '#C4BDBA'
},
inputContainer: {
borderColor: 'black',
borderWidth: 2,
width: 380,
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 10,
marginBottom: 5,
},
addMovie: {
padding: 10,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'stretch',
marginHorizontal: 10,
},
})
export default Registration;
You can manage all states in an object. For example:
import React from 'react';
import {
SafeAreaView,
StyleSheet,
TextInput,
Button,
Alert,
} from 'react-native';
const UselessTextInput = () => {
const [user, setUserData] = React.useState({ name: '', age: 0 });
return (
<SafeAreaView>
<TextInput
style={styles.input}
onChangeText={(text) => setUserData({...user, name: text })}
value={user.name}
/>
<TextInput
style={styles.input}
onChangeText={(age) => setUserData({...user, age: age })}
value={user.age}
/>
<Button onPress={() => Alert.alert(`User name ${user.name}, age ${user.age}`)} title="click me" />
</SafeAreaView>
);
};
const styles = StyleSheet.create({
input: {
height: 40,
marginTop: 42,
borderWidth: 1,
padding: 10,
},
});
export default UselessTextInput;
create a new function and make changes to the a copied object and push the new object to the state
const handleChange=(key,value)=>{
const myState = user
myState[key] = value
setUserData(myState)
}
then pass the function call to onChangeText prop
<TextInput
style={styles.input}
onChangeText={(text) => handleChange('name', text)}
value={user.name}
/>

How can use useState() with Flatlist data?

I've had a problem when i used useState(). i have to filter by searched words on my data and list.
i need to define my data list with State (i'd list with searched words) but when i use State, i've taken 'Invalid Hook' error.
let [list, setList] = useState(data);
//called
data={list}
I don't find where i use that , I couldn't fix for 3 days, i can't reach next step :( I hope i'll fix with expert helps...
import React, {Component, useState} from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
export default class Flatlistexample extends Component {
render () {
//defined below
let [list, setList] = useState(data);
seachFilter=(text)=>{
const newData = data.filter(item=>{
const listitem= `${item.name.toLowerCase()} ${item.company.toLowerCase()}`;
return listitem.indexOf(text.toLowerCase())
})
};
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList
//called
data={list}
renderItem={({item, index})=>{
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb'},
]}>
<Image style={styles.profile} source={{uri: item.picture}} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
ListHeaderComponent={() => {
const [search, setSearch] = useState('');
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text=>{
setSearch(text)
}}
></TextInput>
</View>
)
}}
/>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
borderBottomWidth: 1,
borderColor: 'gray',
},
profile: {
width: 50,
height: 50,
borderRadius: 25,
marginLeft: 10,
},
rightside: {
marginLeft: 20,
justifyContent: 'space-between',
marginVertical: 5,
},
name: {
fontSize: 22,
marginBottom: 10,
},
searchContainer: {
padding: 10,
borderWidth: 2,
borderColor: 'gray',
},
textInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
},
})
Thank you
React hooks can be used with functional component only, here you are using class component
You need to understand the difference between functional component and class component first.
Here you are using class component so your state should be manageed in the following way
export default class Flatlistexample extends Component {
constructor(props)
{
this.state={list:[]}
}
}
and to update list
this.setState({list: <array of data>})
If you want to use hooks, your component needs to be changed something like the following:
const Flatlistexample = () => {
//defined below
let [list, setList] = useState(data);
seachFilter = (text) => {
const newData = data.filter(item => {
const listitem = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`;
return listitem.indexOf(text.toLowerCase())
})
};
return (
<SafeAreaView
style={{
flex: 1,
}}>
<FlatList data={list} renderItem={Your flatlist Item}/>
</SafeAreaView>
)
}
export default Flatlistexample
Here you go, I've added lots of comments. I hope you find this instructive. Let me know if you have questions!
import React, { useMemo, useState } from 'react'
import {
Text,
StyleSheet,
View,
FlatList,
SafeAreaView,
ScrollView,
Image,
TextInput,
} from 'react-native'
import data from '../../data'
// changed this to a functional component so you can use hooks. You can't use hooks in class components.
const Flatlistexample = () => {
// you don't actually need to `useState` for your list, since you're always just filtering `data`
// you would need to use `useState` if you were receiving data from an API request, but here it's static
const [search, setSearch] = useState('') // this should live in the main component so you can filter the list
const parsedSearch = search.toLowerCase() // do this once outside the filter, otherwise you're converting it for each item in the data array
const filteredList = useMemo(
() =>
data.filter(item => {
const itemText = `${item.name.toLowerCase()} ${item.company.toLowerCase()}`
return itemText.indexOf(parsedSearch) > -1 // returns `true` if search is found in string
}),
[parsedSearch], // this will only run if parsedSearch changes
)
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList
//called
data={filteredList} // use the filtered list here
renderItem={({ item, index }) => {
return (
<ScrollView>
<SafeAreaView
style={[
styles.container,
{ backgroundColor: index % 2 === 0 ? '#fafafa' : '#bbb' },
]}
>
<Image style={styles.profile} source={{ uri: item.picture }} />
<View style={styles.rightside}>
<Text style={styles.name}>{item.name}</Text>
<Text style={styles.company}>{item.company}</Text>
</View>
</SafeAreaView>
</ScrollView>
)
}}
keyExtractor={item => item._id}
ListHeaderComponent={() => {
return (
<View style={styles.seachContainer}>
<TextInput
style={styles.textInput}
placeholder={'Search...'}
value={search}
onChangeText={text => {
setSearch(text)
}}
/>
</View>
)
}}
/>
</SafeAreaView>
)
}
export default Flatlistexample

Change a button color when textinput is null, by using onPress

I just started to learn React Native technology, so i try to change some lines in tutorial code. This is a form, which add new title, but I want to change color of button if value === "". I try to find, but mostly examples use classes, in this project I want to use functions
import React, { useState } from 'react'
import { View, StyleSheet, TextInput, Button, Alert } from 'react-native'
export const AddTodo = ({ onSubmit }) => {
const [value, setValue] = useState('')
const pressHandler = () => {
if (value.trim()) {
onSubmit(value)
setValue('')
} else {
}
}
return (
<View style={styles.block}>
<TextInput
style={styles.input}
onChangeText={setValue}
value={value}
disabled
placeholder='Введите название дела...'
autoCorrect={false}
autoCapitalize='none'
/>
<Button title='Добавить' onPress={pressHandler} />
</View>
)
}
const styles = StyleSheet.create({
block: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 15
},
input: {
width: '70%',
padding: 10,
borderStyle: 'solid',
borderBottomWidth: 2,
borderBottomColor: '#3949ab'
},
button: {
color: 'red'
}
})
You use a controlled input field. You store the value in your state and you change it onChange with the input field. Next step is to set a style for your button depending on your current state.
<TextInput
style={[styles.input, value === '' ? styles.red : null]}
onChangeText={setValue}
value={value}
disabled
placeholder='Введите название дела...'
autoCorrect={false}
autoCapitalize='none'
/>
In this case you need to add a style called "red" which changes the button color.
red: {
backgroundColor: 'red'
}
Something like this.
Because your state is updated every time you change the input value, it gets updated onChange. If you want to set it on submit you need to add a isSubmitted boolean (default false ) to your state and set it to true in your pressHandler.
You need to destructure isSubmitted in this example:
style={[styles.input, value === '' && isSubmitted ? styles.red : null]}
You can apply a simple logic as below
<Button
title="Добавить"
onPress={pressHandler}
color={value === null ? 'red' : 'green'}
/>
EDIT
Check below sample which I created according to your requirement
import React, { useState } from 'react';
import { View, StyleSheet, TextInput, Button } from 'react-native';
export default App = () => {
const [value, setValue] = useState('');
const [error, handleError] = useState(false);
const pressHandler = () => {
if (value.trim()) {
setValue('');
} else {
handleError(true);
}
};
const onHandleChange = (text) => {
setValue(text)
handleError(false)
}
return (
<View style={styles.block}>
<TextInput
style={styles.input}
onChangeText={onHandleChange}
value={value}
placeholder="Введите название дела..."
autoCorrect={false}
autoCapitalize="none"
/>
<Button
title="Добавить"
onPress={pressHandler}
color={error ? 'red' : 'green'}
/>
</View>
);
};
const styles = StyleSheet.create({
block: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 15,
},
input: {
width: '70%',
padding: 10,
borderStyle: 'solid',
borderBottomWidth: 2,
borderBottomColor: '#3949ab',
}
});
Hope this helps you. Feel free for doubts.

FlatList show according to TextInput handle

I have Dynamic form in which user can add form and remove form when user start typing on first form TextInput it will give suggestion as per input. Now the problem is when user start typing on first TextInput field it will get suggestion but when user add another form by clicking on addForm Button and when user start typing on new form it will get suggestion but on same time in the first form it also start giving suggestion and same if there is three form it will start giving suggestion for all three form if user start typing in one form.I want to say that If user type any of form it will give suggestion on all form.
I want like if user is on first form then it will give suggestion only for first form not for second form as well. if user is on second form it will only get suggestion on second form not on first as well.
You can see in above picture it is giving suggestion for both form even if I'm typing on second form
import React, { PureComponent } from 'react'
import {
View,
TextInput,
ScrollView,
KeyboardAvoidingView,
StyleSheet,
Picker,
ListView,
FlatList
} from 'react-native'
import { getStockItems } from "../../actions/getIndentsAction";
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { TouchableOpacity } from 'react-native-gesture-handler';
import { CardSection, Text, Button, Block, Input } from '../../components';
import { theme } from '../../constants';
import { MaterialIcons,AntDesign,Entypo } from '#expo/vector-icons';
import { CardItem,Content, ListItem,Icon,Card, Left, Body, Right } from 'native-base';
class IndentForm extends PureComponent {
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerRight: (
<TouchableOpacity onPress={() => params.handleSave()}>
<AntDesign
name='plus'
style={{ paddingRight:10}}
size={25}
color='white'
/>
</TouchableOpacity>
)
};
};
constructor(props) {
super(props);
this.state = {
companyName:'',
formFields:[{
Item_Description:'',
Quantity:'',
}],
searchedForm:[]
};
}
componentDidMount() {
this.props.navigation.setParams({ handleSave: this.addInput});
this.props.getStockItems()
}
//add dynamic form
addInput = () => {
const existingFormFields = this.state.formFields.map(fields => ({...fields}))
const allFormFieldsAfterAddingNew = [...existingFormFields, {Item_Description: '', Quantity:''}]
this.setState({formFields: allFormFieldsAfterAddingNew})
}
//remove dynamic form
removeInput = index => () => {
this.setState({
formFields: this.state.formFields.filter((s, sidx) => index !== sidx)
});
};
//on Item Descriptionchange
onItemDescriptionChange = (text, index) => {
const { stocks } = this.props.indent;
const existingFormFields = this.state.formFields.map(fields => ({...fields}))
let targetField = {...existingFormFields[index]}
targetField.Item_Description = text
existingFormFields[index] = targetField
var searchedForm = stocks.filter(function(stock) {
return stock.Item.toLowerCase().indexOf(text.toLowerCase()) > -1;
});
this.setState({searchedForm: searchedForm , formFields: existingFormFields})
}
//on Quantity change
onQuantityChange = (text, index) => {
const existingFormFields = this.state.formFields.map(fields => ({...fields}))
let targetField = {...existingFormFields[index]}
targetField.Quantity = text
existingFormFields[index] = targetField
this.setState({formFields: existingFormFields})
}
itemSelect = (item,index) => {
const existingFormFields = this.state.formFields.map(fields => ({...fields}))
let targetField = {...existingFormFields[index]}
targetField.Item_Description = item.Item
existingFormFields[index] = targetField
this.setState({searchedForm:[], formFields:existingFormFields})
console.log("hello" + " " + item.Item + " " + index);
}
onsubmit = () => {
const data = {
companyName:this.state.companyName,
formFields:this.state.formFields
}
console.log(data)
}
render() {
const { stocks } = this.props.indent;
return (
<KeyboardAvoidingView style={{flex:1, justifyContent:"center"}} behavior="padding">
<ScrollView
showsVerticalScrollIndicator={false}
>
<Block padding={[5]}>
<Card>
<Picker
style={{flex:1}}
selectedValue={this.state.companyName}
onValueChange={(companyName)=>this.setState({companyName:companyName})}
>
<Picker.Item label='developer' value="0" />
<Picker.Item label="Developer" value="Developer" />
<Picker.Item label="Junior Develope" value="Junior Develope" />
</Picker>
</Card>
{
this.state.formFields.map((field, index) => {
return(
<Card key={index} >
<CardItem bordered>
<Left>
<Text bold>Items no : {index + 1}</Text>
</Left>
<Right>
<TouchableOpacity
onPress={this.removeInput(index)}
>
<Entypo
name="cross"
size={20}
color='#E46932'
/>
</TouchableOpacity>
</Right>
</CardItem>
<Block padding={[0, theme.sizes.base]}>
<Block>
<Input
label="description"
style={[styles.input]}
value={field.Item_Description}
onChangeText={(text)=> this.onItemDescriptionChange(text, index)}
/>
<FlatList
data={this.state.searchedForm}
keyExtractor={(ItemId,index) => index.toString()}
renderItem={({item,index})=>(
<ListItem
button={true}
key={index}
onPress={()=>this.itemSelect(item,index)}
>
<Text bold>{item.Item}</Text>
</ListItem>
)}
/>
</Block>
<Input
label="Quantity"
style={[styles.input]}
value={field.Quantity}
onChangeText={(text)=> this.onQuantityChange(text, index)}
/>
</Block>
</Card>
)
})
}
<Block padding={[0, theme.sizes.base * 1.5]}>
<Button
style={styles.submitInput}
onPress={this.onsubmit}>
<Text bold white center>Submit</Text>
</Button>
</Block>
</Block>
</ScrollView>
</KeyboardAvoidingView>
)
}
}
IndentForm.propTypes = {
getStockItems: PropTypes.func.isRequired,
indent: PropTypes.object.isRequired,
};
const mapStateToProps = state => ({
indent: state.indent,
errors:state.errors
});
export default connect(
mapStateToProps,
{
getStockItems,
}
)(IndentForm);
const styles = StyleSheet.create({
input: {
borderRadius: 0,
borderWidth: 0,
borderBottomColor: theme.colors.gray2,
borderBottomWidth: StyleSheet.hairlineWidth,
marginLeft:5
},
submitInput:{
backgroundColor:"#2ecc71"
},
addInput:{
backgroundColor:"white"
},
addButton:{
alignItems:"flex-end",
position:"absolute",
right:20,
bottom:20,
},
searchBarContainerStyle: {
marginBottom: 10,
flexDirection: "row",
height: 40,
shadowOpacity: 1.0,
shadowRadius: 5,
shadowOffset: {
width: 1,
height: 1
},
backgroundColor: "rgba(255,255,255,1)",
shadowColor: "#d3d3d3",
borderRadius: 10,
elevation: 3,
marginLeft: 10,
marginRight: 10
},
selectLabelTextStyle: {
color: "#000",
textAlign: "left",
width: "99%",
padding: 10,
flexDirection: "row"
},
placeHolderTextStyle: {
color: "#D3D3D3",
padding: 10,
textAlign: "left",
width: "99%",
flexDirection: "row"
},
dropDownImageStyle: {
marginLeft: 10,
width: 10,
height: 10,
alignSelf: "center"
},
pickerStyle: {
marginLeft: 18,
elevation:3,
paddingRight: 25,
marginRight: 10,
marginBottom: 2,
shadowOpacity: 1.0,
shadowOffset: {
width: 1,
height: 1
},
borderWidth:1,
shadowRadius: 10,
backgroundColor: "rgba(255,255,255,1)",
shadowColor: "#d3d3d3",
borderRadius: 5,
flexDirection: "row"
}
})
when you do addInput, it adds new FlatList for each input. but, data of FlatList is managed by single state which is this.state.searchedForm.
So whenever onItemDescriptionChange gets called, it updates the searchedForm state and all the FlatList reflects that change.
To resolve this, either you'll have to keep the FlatList data inside formFields state as one key or you can manage different state for each input.