Update Input Value while mapping React Native - react-native

I am creating react-native mobile app. I have an array with some values. I want to set array's value into input field. I have added value in the fields but i can't able to update these values. I have set my values in a qty variable like this:
constructor(props) {
super(props);
this.state = {
qty:[],
}
}
componentWillMount() {
var ids = [];
this.props.data.map((dataImage,Index) => {
dataImage['pro-name'] != undefined && (
ids.push({'qty':dataImage['pro-qty']})
)
})
this.setState({qty:ids})
}
render() {
return {
this.props.data.map((dataImage,Index)=>(
<View key={Index} style={productStyle.cartview}>
{dataImage['pro-name'] && (
<View style={productStyle.cartmain}>
<Input value={this.state.qty[Index]['qty']} onChange={this.handleChangeInput.bind(this)} style={{width:40,height:40,textAlign:'left'}} />
</View>
)}
</View>
))
}
}
Its showing values properly into the input field but i can't able to type anything into the field to update the values. what can i do for this

I will suggest you to move your input container into separate class, its better approach and each component will handle its own state. Its easy to handle and will result better in performance too.
components = []
render() {
return this.props.data.map((item, index) => (
<CustomComponent data={item} index={index} ref={(ref) => this.components[index] = ref} />
))
}
You can then get child (CustomComponent) value from its ref.
this.components[index].getValue()
this.components[index].setValue('Value');
You will need to create these functions (getValue & setValue) in CustomComponent class.
solution
Here is solution to your query. You need to install lodash or find other solution to make a new copy qty.
<Input onChangeText={(text) => this.handleChangeText(text, index)} />
handleChangeText = (text, index) => {
const qty = _.cloneDeep(this.state.qty);
qty[index] = {
qty: text
}
this.setState({qty})
}

Your Input's value is set to this.state.qty[Index]['qty']. And to change it on text edit, you can do it like this. You do not need to bind the function, instead use an arrow function like this.
onChangeText={ (newValue) => {
this.setState({ <your-input-value-state>:newValue })
}}

You have to update the value of each Input individually on onChange event.
Replace your with Input with this
<Input value={this.state.qty[Index]['qty']}
onChange={this.handleChangeInput.bind(this, Index)}
style={{width:40,height:40,textAlign:'left'}}
/>
and update the state accordingly with the Index when the event is called
handleChangeInput(index, value){
let {qty} = this.state;
let qty_update = qty.slice();
qty_update[index]['qty'] = value;
this.setState({qty: qty_update});
}

Related

How to make a dynamic number of input fields using Flatlist in React Native?

I am trying to make an input form for a team that does not have a fixed number of players and it should be optional on how many you enter without limits.
The idea is to have a button that puts an empty string into an array of team players which then FlatList should react to without refreshing the page and give you fields for input which would store the value on change without a button.
So it would something like this:
const TeamContentScreen = ({navigation}) => {
const [list, setList] = useState([""]);
const addToList = () => {
let tempArr = list;
tempArr.push("");
setList(tempArr);
console.log(list);
console.log(list.length);
};
return(
<View>
<Button onPress={addToList} title={"+1 player"}/>
<FlatList
data={list}
keyExtractor = {(e,i)=> i.toString()}
renderItem={({item, index})=>{
return(
<TextInput
placeholder="Type player name here"
onChangeText={/*way to dynamically update the value of an element of this index*/}}
/>
)
}}
/>
)
}
export default TeamContentScreen;
Is this possible?
If yes, how do you suggest dynamically updating the input fields display without refreshing?
How would you suggest storing the inputted values in the array without a button?
Try this
const onChangeText = (value, index) => {
let newList = [...list]; // clone list to a new list
newList[index] = value; // change the value at the index of list
setList(newList); // set new list
}
<TextInput
placeholder="Type player name here"
onChangeText={(value) =>onChangeText(value, index) }
/>

How to allow text input in list item using react native?

This question relates to React Native specifically the text input component. I wanted to create an app which allows users to select a number of people from their contacts and based on their selection, create a list with text input each beside them. From there, they are able to do text input and with the onChangeText function, changes the state of a particular key.
Below is the code that I have attempted. I tried to change the state of percent inside the prop which I believe is incorrect since all elements will share the same text input.
By doing so, whenever I made a text input to one field, the text input will erase subsequently.
constructor(props) {
super(props);
this.state = {
selected2: undefined,
description: "",
amount: "",
notes: "",
percent: {},
selectedContacts:
this.props.navigation.state.params.selectedContacts,
};
}
const SelectedList = (props) => {
const list = ({ allContacts }) => {
if (allContacts) {
return allContacts.map((item) => {
return (
<ListItem key={item.id}>
<Body>
<Text>{`${item.first_name}`}</Text>
<Text note>{`${item.phone_number}`}</Text>
</Body>
<Right>
<Item>
<Input
placeholder="0"
maxLength={3}
onChangeText={(percent) => {
this.setState({percent});
}}
/>
<Text>%</Text>
</Item>
</Right>
</ListItem>
)
})
}
}
<SelectedList
allContacts={this.state.selectedContacts}
/>
I hope to achieve is that after selecting the number of contacts and transferring the array data, I want the array to be printed out and the text input of each list item to be independent of each other.
Any feedback and advice are welcome and I really appreciate for you to spending time reading my query and helping me with my problem. Thank you!
I think its about your logic.. something like this should work. make 'percent' type to array and in onChangeText change specific item
this.state = {
...
percent: [],
...
}
...
return allContacts.map((item,index) => {
...
onChangeText={(someText) => {
var {percent} = this.state;
percent[index] = someText;
this.setState({percent});
}}

How to Highlight Updated Items onRefresh of FlatList

I set up a FlatList with an onRefresh function to update the state when the user drags down the screen. It works properly, however I was wondering how I can highlight items in the FlatList that have been updated after the refresh.
Say, for example, I want to change the background for a few seconds for any item in the list that was updated, then return to normal.
<FlatList
data={scores}
renderItem={({item}) => (
<View style={styles.scoreContainer}>
<ScoreRow data={item.away} />
<ScoreRow data={item.home} />
</View>
)}
keyExtractor={item => item.gameID}
refreshing={isRefreshing}
onRefresh={updateScores}
/>
The best I could do was add a useEffect in the ScoreRow component to detect if something changes within that component, but that only allows me to update one component at a time, not the entire View.
const [runUpdate, setRunUpdate] = useState(false)
const [runs, setRuns] = useState(data.R)
useEffect(() => {
if(runs !== data.R) {
setRunUpdate(true)
setRuns(data.R)
setTimeout(() => setRunUpdate(false), 10000)
}
}, [data.R])
I can't figure out how to detect a change on an an item in the View of the FlatList so that I can change the entire View the way I did each component.
You can achieve this by using data of FlatList. You have to make an extra parameter for this.
eg:
//Method to refresh data
_refreshMethod() {
// Do your code to fetch...
...
let newDataArray = data // Data fetch from server or some thing.
let updatedArray = []
newDataArray.map((data, index) => {
data["isNewItem"] = true;
updatedArray.push(data);
});
this.setState({scores: updatedArray})
this._callTimer()
}
// Method to update new item status after a delay
_callTimer() {
setTimeout(function() {
let updatedArray = []
this.state.scores.map((data, index) => {
data["isNewItem"] = false;
updatedArray.push(data);
});
this.setState({scores: updatedArray})
}, 3000); // The time you want to do...
}
Then change the style of row based on the state value.
<FlatList
data={this.state.scores}
renderItem={({item}) => (
<View style={item.isNewItem ? styles.yourNewItemStyle : styles.scoreContainer}>
<ScoreRow data={item.away} />
<ScoreRow data={item.home} />
</View>
)}
keyExtractor={item => item.gameID}
refreshing={isRefreshing}
onRefresh={updateScores}
extraData={this.state}
/>

How to check checkbox when there is an array in React Native?

I want to get checked friends using checkbox. But I not quite sure how i will achieve it, hope someone can help me.
This is my state:
state = {checked: false}
This is where I want to map array
{this.props.navigation.getParam('friends').map((name, key) => (
<View>
<Text>{name}</Text>
<CheckBox
checked={this.state.checked}
onPress={(val)=>{}}
/>
</View>))}
Note: Or Could someone write me an app/code snippet in snack.expo.io how to get only checked checkbox value
You can write a custom checkbox component
export default class CustomCheckbox extends Component {
constructor(props) {
super(props);
this.state = {
checked: false,
};
}
toggleChange(){
this.setState({checked: !this.state.checked});
}
render() {
return (
<View>
<Text>{this.props.name}</Text>
<CheckBox
checked={this.state.checked}
onPress={() => this.bind.toggleChange(this)}
/>
</View>
);
}
}
and import your CustomCheckbox component
import CustomCheckbox from "your CustomCheckbox.js path"
{this.props.navigation.getParam('friends').map((name, key) => (
<View>
<CustomCheckbox name={name} />
</View>
))}
Your code is pretty good to go, you just need to update a bit. You have following two options:
Your friend's array should have checked key within each containing object, then you can simply do something like this.
{
this.props.navigation.getParam('friends').map((item, key) => (
let {name, checked} = item // item is an object from friends array,the and it have name, checked and other keys
<View>
<Text>{name}</Text>
<CheckBox
checked={checked}
onPress={(val)=>{}}
/>
</View>))
}
Other is you to save the name of the person as key and true/false as the checked state, eg :
toggleCurrentFirendState = (item)=>{
this.setState((prevState)=>{
let {name} = item //get name from clicked friend from the list
return {
...prevState, //used spread operator, so that other states doesn't get mutat.
[name]:!prevState[name] //toogle state of clicked item
}
})
}
//within your render
{
this.props.navigation.getParam('friends').map((item, key) => (
let {name} = item // item is an object from friends array,the and it have name, checked and other keys
<View>
<Text>{name}</Text>
<CheckBox
checked={name ===this.state[name]} //see change
onPress={(val)=>{this.toggleCurrentFirendState(item)}}
/>
</View>))
}

How to hide some elements in JSX

I want to display on my app a list of meal 'tags'. So based on the code below, I was able to do that. So as a result of the code, I will get a list or a set of mealTags displayed.
Question: I want to only show the first 2 tags, hide the rest and put a link 'show more where the rest will appear when I click it . How can I do this in ReactJS?
return (
<View {...otherprops} style={styles.mainContainer} elevation={3}>
<View style={styles.contentContainer}>
<MealTagsSection mealTags={post.mealTags} />
</View>
type MealTagsProps = {
mealTags: Array<MealTag>;
};
export function MealTagsSection(props: MealTagsProps) {
let {mealTags} = props;
return (
<View style={styles.mealTagsContainer}>
{
mealTags.map((mealTag) => {
let tagStyle = '';
if (mealTag.category === 1) {
tagStyle = styles.tag_healthy;
} else {
tagStyle = styles.tag_improve;
}
return (
<View style={tagStyle}>
<Text style={styles.tagText}>{mealTag.description}</Text>
</View>
);
})
}
</View>
);
}
You can use set visible count in state
this.state= {
visibleCount:2
}
and use slice function before map, for example
mealTags.slice(0, this.state.visibleCount).map(...)
Then you can increase visible count as you want in button onClick funtion.
Another option is to track the index in your .map block
mealTags.map((mealTag, idx) => ...
and style accordingly e.g. display:none when idx >= 2