React Native - Single select in Flatlist - javascript

I'm trying to make a simple button with text where if a user taps on it, it would change it's colour and text. This button with text is displayed in my Flatlist I can now change the text on it if it is tapped, but the problem is the other buttons with text in my Flatlist is also changing.
What I'am targeting is to change the single button that will be tapped.
Here's my code.
export default class tables extends Component {
constructor(props){
super(props)
this.state = {
data: [],
...
toggle: true,
}
}
_onPress() {
const newState = !this.state.toggle;
this.setState({ toggle: newState })
}
render() {
const { toggle } = this.state;
const textValue = toggle?"Available":"Occupied";
const buttonBg = toggle?"dodgerblue":"white";
const textColor = toggle?"white":"black";
return (
<View>
<FlatList
....
renderItem = {({ item }) =>
<View>
<Text>Table No: { item.tbl_id }</Text>
<TouchableHighlight
onPress = { () => this._onPress()}>
<Text>{textValue}</Text> // Button with text
</TouchableHighlight>
<View>
<TouchableHighlight
....>
<Text>DINE-IN</Text>
</TouchableHighlight>
<TouchableHighlight
....
<Text>TAKE-OUT</Text>
</TouchableHighlight>
</View>
</View>
}
/>
</View>
)
}
}

The toggle: true, value must be in the item
Actually your bollean affect all the items present in data. Your item should look like this:
data: [
{ itemName: 'hi', toggle: false, id: 1 },
{ itemName: 'hey', toggle: false, id: 2 },
// others items
]
then, your onPress:
onPress = (id) => {
const { data } = this.state
data.forEach((elem) => {
elem.toggle = false
if (elem.id === id) {
elem.toggle = true
}
})
this.setState({ data })
}
In the map:
<TouchableHighlightonPress = { () => this._onPress(item.id)}>
<Text>{item.toggle ? "Available" : "Occupied"}</Text>
You could do it in another way by storing the item.id in this.state.toggle and then have something easier:
onPress = (id) => {
this.setState({ toggle: id })
}
<Text>{item.id === this.state.toggle ? "Occupied": "Available" }</Text>

Related

Disable TouchableOpacity after 5 clicks - React Native

I am pulling memes from an API and only want to show 5 memes therefore I tried to disable the touchableOpacity after certian number of clicks. Any ideas on how I can do that?
const link = 'https://meme-api.herokuapp.com/gimme'
class Meme extends React.Component {
constructor() {
super()
this.state = {
loading: false,
data: {
postLink: "sample data",
subreddit: "sample data",
title: "sample data",
url: 'https://poster.keepcalmandposters.com/8170567.jpg'
}
}
}
load = () => {
this.setState({ loading: true })
axios.get(link).then(res => {
this.setState({
data: res.data,
loading: false,
})
console.log(Object.keys(res.data))
})
}
This is where the "button" is
render() {
return (
<View>
<View style={styles.container}>
<View style={styles.imageView}>
<ProgressiveImage source={{ uri: this.state.data.url }} />
</View>
<TouchableOpacity style={styles.button}
onPress={() => {this.load()}} >
<Text style={styles.btnText}>Click to open a meme!</Text>
</TouchableOpacity>
</View>
<AnimatedLoader
visible={this.state.loading}
overlayColor="rgba(255,255,255,0.75)"
source={require("../loader.json")}
animationStyle={styles.lottie}
speed={1} />
</View>
);
}
};
I tried using state/setState for disabiling the button but nothing seems to work. I am okay with just disabiling the button but I tried it with two different pressHandlers, one for this.load() and another for disabling after a click but both of them does not work at the same time.
You need to create a counter state for the button and set the disable properties as well. Here's a simple example for it.
class Meme extends React.Component {
constructor() {
super();
this.state = {
count: 0
};
}
load = () => {
this.setState({ count++ })
// and others logic
}
render() {
return (
<TouchableOpacity onPress={() => {this.load()}} disabled = {this.state.count == 5 ? true : false}>
<Text>Click to open a meme!</Text>
</TouchableOpacity>
);
}
}
functional component example for this.
const Meme = () => {
const [count, setCount] = useState(0)
const loadForAPI = () => {
setCount(count => count + 1)
}
render() {
return (
<TouchableOpacity onPress={() => {loadForAPI()}} disabled = {count == 5 ? true : false}>
<Text>Click to open a meme!</Text>
</TouchableOpacity>
);
}
}
export default Meme;

Add value of checkbox to an array when it is clicked

I have this situation where I want to transfer userid to an array which is defined in State.
I want to do it when I click on the checkbox to select it, and I want to remove the userid from the array when I deselect the checkbox
import React, { Component } from "react";
import {
View,
Text,
StyleSheet,
FlatList,
AsyncStorage
} from "react-native";
import axios from 'axios';
import { Button, Container, Content, Header, Body, Left, Right, Title } from 'native-base';
import Icon from 'react-native-vector-icons/Ionicons';
import { List, ListItem, SearchBar, CheckBox } from "react-native-elements";
// const itemId = this.props.navigation.getParam('itemId', 'NO-ID');
// const otherParam = this.props.navigation.getParam('otherParam', 'some default value');
class TeacherSubjectSingle extends Component{
static navigationOptions = {
header : null
}
// static navigationOptions = {
// headerStyle: {
// backgroundColor: '#8E44AD',
// },
// headerTintColor: '#fff',
// }
state = {
class_id: null,
userid: null,
usertype: null,
student_list: [],
faq : [],
checked: [],
}
componentWillMount = async () => {
const {class_id, student_list, userid, usertype} = this.props.navigation.state.params;
await this.setState({
class_id : class_id,
student_list : student_list,
userid : userid,
usertype : usertype,
})
console.log(this.state.class_id)
var result = student_list.filter(function( obj ) {
return obj.class_section_name == class_id;
});
this.setState({
student_list: result[0]
})
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE",
}}
/>
);
};
checkItem = (item) => {
const { checked } = this.state;
console.log(item)
if (!checked.includes(item)) {
this.setState({ checked: [...checked, item] });
} else {
this.setState({ checked: checked.filter(a => a !== item) });
}
console.log(checked)
};
render(){
return (
<Container>
<Header style={{ backgroundColor: "#8E44AD" }}>
<Left>
<Button transparent onPress={()=> this.props.navigation.navigate('ClassTeacher')}>
<Icon name="ios-arrow-dropleft" size={24} color='white' />
</Button>
</Left>
<Body>
<Title style={{ color: "white" }}>{this.state.class_id}</Title>
</Body>
<Right>
{this.state.checked.length !== 0 ? <Button transparent onPress={()=> this.props.navigation.navigate('ClassTeacher')}>
<Text>Start Chat</Text>
</Button> : null}
</Right>
</Header>
<View style={{flex: 1, backgroundColor: '#fff'}}>
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.student_list.students}
extraData={this.state.checked}
renderItem={({ item }) => (
<ListItem
// roundAvatar
title={<CheckBox
title={item.name}
checkedColor='#8E44AD'
onPress={() => this.checkItem(item.userid)}
checked={this.state.checked.includes(item.userid)}
/>}
// subtitle={item.email}
// avatar={{ uri: item.picture.thumbnail }}
//containerStyle={{ borderBottomWidth: 0 }}
onPress={()=>this.props.navigation.navigate('IndividualChat', {
rc_id: item.userid,
userid: this.state.userid,
usertype: this.state.usertype,
subject_name: this.state.student_list.subject_name
})}
/>
)}
keyExtractor={item => item.userid}
ItemSeparatorComponent={this.renderSeparator}
/>
</List>
</View>
</Container>
);
}
}
export default TeacherSubjectSingle;
const styles = StyleSheet.create({
container:{
flex:1,
alignItems:'center',
justifyContent:'center'
}
});
this is the code for the same, I have created a function checkItem()for the same and it is working, the only problem is, when I click on the first item, it will output the blank array, I select the second item and it will return the array with first item and so on. Please help me resolve it, thanks in advance
Its because you are printing this.state.checked value just after the setState, setState is async, it will not immediately update the state value.
You can use setState callback method to check the updated state values.
Write it like this:
checkItem = (item) => {
const { checked } = this.state;
let newArr = [];
if (!checked.includes(item)) {
newArr = [...checked, item];
} else {
newArr = checked.filter(a => a !== item);
}
this.setState({ checked: newArr }, () => console.log('updated state', newArr))
};
Check this answer for more details about setState:
Why calling setState method doesn't mutate the state immediately?
Try below code:
checkItem = (e) => {
let alreadyOn = this.state.checked; //If already there in state
if (e.target.checked) {
alreadyOn.push(e.target.name); //push the checked value
} else {
//will remove if already checked
_.remove(alreadyOn, obj => {
return obj == e.target.name;
});
}
console.log(alreadyOn)
this.setState({checked: alreadyOn});
}
Like this, with an event listener and the .push method of an array.
var checkboxes = document.querySelectorAll('input[type=checkbox]');
var myArray = [];
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].addEventListener("click", function(e) {
myArray.push(e.target.value);
console.log(myArray);
});
};
<div>
<input type="checkbox" name="feature" value="scales" />
<label >Scales</label>
</div>
<div>
<input type="checkbox" name="feature" value="horns" />
<label >Horns</label>
</div>
<div>
<input type="checkbox" name="feature" value="claws" />
<label >Claws</label>
</div>

React Native - Modal with Flatlist items

I'm making a modal that will popup when the user clicks a flatlist button or items, and there the user will see the details about the item he/she clicks. Basically, I want to pass the items of flatlist to modal.
I'm actually done with the popup of the modal, now I have to show the details like menu description and menu price. I've found a post here in stackoverflow and I follow everything in there but I am having an error regarding with an " id ", and I can't figure out how to fix it.
Here is my code
Details.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, Modal, TextInput, TouchableWithoutFeedback, Keyboard
} from 'react-native';
import AddModal from '../Modal/AddModal';
var screen = Dimensions.get('window');
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress = {() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
export default class Details extends Component {
static navigationOptions = {
title: ''
};
constructor()
{
super ()
this.state = {
data: [],
showModal: false,
id: null,
}
}
fetchData = async() => {
const { params } = this.props.navigation.state;
const response_Cat = await fetch('http://192.168.254.101:3307/categories/' + params.id);
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
_onRefresh() {
this.setState({ refreshing: true });
this.fetchData().then(() => {
this.setState({ refreshing: false })
});
};
_onPressItem(id) {
this.setState({
modalVisible: true,
id: id
});
}
_renderItem = ({item}) => {
return (
<TouchableHighlight
id = { item.menu_desc }
onPress = { this._onPressItem(item.menu_desc) }
>
<View>
<Text>{ this.state.id }</Text>
</View>
</TouchableHighlight>
)
};
render() {
const { params } = this.props.navigation.state;
return (
<View style = { styles.container }>
<AddModal
modalVisible = { this.state.modalVisible }
setModalVisible = { (vis) => { this.setModalVisible(vis) }}
id = { this.state.id }
/>
<FlatList
data = { this.state.data }
renderItem = { this._renderItem }
keyExtractor={(item, index) => index}
/*refreshControl = {
<RefreshControl
refreshing = { this.state.refreshing }
onRefresh = { this._onRefresh.bind(this) }
/>
}*/
/>
</View>
);
}
}
const styles = StyleSheet.create({
...
})
//AppRegistry.registerComponent('Details', () => Details);
AddModal.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, TextInput, Modal
} from 'react-native';
export default class AddModal extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
id: null
};
}
componentWillReceiveProps(nextProps) {
this.setState({
showModal: nextProps.showModal,
id: nextProps.id,
})
}
render() {
return (
<Modal
animationType="slide"
transparent={ true }
visible={ this.state.modalVisible }
onRequestClose={() => { this.props.setModalVisible(false) }}>
<View>
<View>
<Text>{ this.state.id }</Text>
<TouchableHighlight
onPress = {() => { this.props.setModalVisible(false) }}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
)
}
}
Just wanted to pointout an issue in your code (not related to 'id' error, id error already answer by digit). In the renderItem function, you are calling onPress = { this._onPressItem(item.menu_desc) }, it should be changed to
onPress = { () => this._onPressItem(item.menu_desc) }
I guess, you will call the onPressItem when user click on list item.
EDIT:
I have made a couple of changes to make your code working. Here are the changes.
In your AppModal.js, you are setting modal visibility in showModal: nextProps.showModal , but in the <Modal ...> you have set visible
= { this.state.modalVisible }. Also in Details.js you have written <AddModal modalVisible ...>.
First I changed showModal to modalVisible in Details.js and in AppModal.js.
Details.js
constructor()
{
super ()
this.state = {
data: [],
modalVisible: false,
id: null,
}
}
Then I changed _onPressItem(id) to _onPressItem = (id)
Made changes in renderItem as
<TouchableHighlight
id = { item.enName }
onPress = { () => this._onPressItem(item.enName) }
>
in render function I have set modal visibility as
<AddModal
...
setModalVisible = { (vis) => { this.setState({
modalVisible: vis
})
}}
...
/>
AppModal.js
Changed showModal to modalVisible
constructor(props) {
super(props);
this.state = {
modalVisible: props.modalVisible,
d: null
};
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
id: nextProps.id,
})
}
In the constructor, I have added modalVisible: props.modalVisible.
Hope this will help!
I guess item.menu_desc is an id of each item so it must be {item.menu_desc} not {id}. Change it like below
_renderItem = ({item}) => {
return (
<TouchableHighlight
id = { item.menu_desc }
onPress = { this._onPressItem(item.menu_desc) }
>
<View>
<Text>{ item.menu_desc }</Text>
</View>
</TouchableHighlight>
)
};

How to have multiple Flatlists with filtered data in React Native

How do I create multiple Flatlists that only present data with one type of 'status'?
For example:
One Flatlist for status === 'inProgress'
One Flatlist for status ===
'Done'
One Flatlist for status ===
'Failed'
All data is in the array ‘goallist’, which comes from a Firebase database.
I would really appreciate your help with this.
import React, { Component } from 'react';
import { Text, FlatList, View, Image, TouchableOpacity, Alert } from 'react-native';
import firebase from 'firebase';
import { Button, Card, CardSection } from '../common';
import styles from '../Styles';
class List extends Component {
static navigationOptions = {
title: 'List',
}
constructor(props) {
super(props);
this.state = {
goallist: '',
loading: false,
};
}
componentDidMount() {
this.setState({ loading: true });
const { currentUser } = firebase.auth();
const keyParent = firebase.database().ref(`/users/${currentUser.uid}/goalProfile`);
keyParent.on(('child_added'), snapshot => {
const newChild = {
key: snapshot.key,
goal: snapshot.val().goal,
status: snapshot.val().status
};
this.setState((prevState) => ({ goallist: [...prevState.goallist, newChild] }));
console.log(this.state.goallist);
});
this.setState({ loading: false });
}
onRenderItem = ({ item }) => (
<TouchableOpacity onPress={this.showAlert}>
<Text style={styles.listStyle}>
{ item.goal } { item.key }
</Text>
</TouchableOpacity>
);
showAlert = () => {
Alert.alert(
'Did you succeed or fail?',
'Update your status',
[
{ text: 'Completed?',
onPress: () => console.log('Completed Pressed'), },
{ text: 'Failed?',
onPress: () => console.log('Failed Pressed'),
},
{ text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel' },
],
{ cancelable: false }
);
}
keyExtractor = (item) => item.key;
render() {
return (
<Card>
<View style={{ flex: 1 }}>
<FlatList
data={this.state.goallist}
keyExtractor={this.keyExtractor}
extraData={this.state}
renderItem={this.onRenderItem}
/>
</View>
</Card>
);
}
}
export { List };
You just need to modify your onRenderItem function to render some specific objects as below (this Flatlist shows only inProgress objects):
onRenderItem = ({ item }) => {
if (item.type === 'inProgress') {
return (
<TouchableOpacity onPress={this.showAlert}>
<Text style={styles.listStyle}>
{ item.goal } { item.key }
</Text>
</TouchableOpacity>
)
} else { return null; }
};

React Native Flatlist returns the wrong number of empty rows

When I run the code below, it displays 3 empty rows. It should be showing two rows each with a color and enddate and I want to use the 'Parent' as the unique key. The 'Parent' is the unique key created by Firebase when color and enddate were pushed to Firebase with '.push'.
I've tried all sorts of things to get it to display. I did get content to display when I made the 'renderItems' return 'this.state.list', but that returned 3 lines all with the same data, which is the content of the last array on the console log.
I would really appreciate some help to get this working.
Here is the code, a copy of Firebase database and the console.log. Please note that the Firebase 'goal' has been changed to 'color'.
import React, { Component } from 'react';
import { Text, FlatList, View, Image } from 'react-native';
import firebase from 'firebase';
import { Button, Card, CardSection } from '../common';
import styles from '../Styles';
class List extends Component {
static navigationOptions = {
title: 'List',
}
constructor(props) {
super(props);
this.state = {
list: [],
};
}
componentDidMount() {
const { currentUser } = firebase.auth();
const Parent = firebase.database().ref(`/users/${currentUser.uid}/Profile`);
Parent.on(('child_added'), snapshot => {
this.setState({ list: [snapshot.key, snapshot.val().color, snapshot.val().enddate] });
console.log(this.state.list);
});
}
keyExtractor = (item, index) => index;
render() {
return (
<Card>
<View style={{ flex: 1 }}>
<FlatList
data={this.state.list}
keyExtractor={this.keyExtractor}
extraData={this.state}
renderItem={({ item }) => (
<Text style={styles.listStyle}>
{ item.color }
{ item.enddate }
</Text>
)}
/>
</View>
<CardSection>
<Button
style={{
flex: 1,
flexDirection: 'row'
}}
onPress={() => this.props.navigation.navigate('NextPage', { name: 'user' })}
title="Go to next page"
>
Go to next page
</Button>
</CardSection>
</Card>
);
}
}
export { List };
This is the correct way to store the list
componentDidMount() {
const { currentUser } = firebase.auth();
const Parent = firebase.database().ref(`/users/${currentUser.uid}/Profile`);
Parent.on(('child_added'), snapshot => {
const newChild = {
key: snapshot.key,
color: snapshot.val().color,
enddate: snapshot.val().enddate
}
this.setState((prevState) => ({ list: [...prevState.list, newChild] }));
console.log(this.state.list);
});
}
and your keyExtractor
keyExtractor = (item, index) => item.key;

Categories

Resources