How can I get the value from custom radio button component in parent class - react-native

I have a custom radio button component. I am importing that to my parent form to create a dynamic fields of radio button from JSON file. I have multiple other views too. I am getting these views values and creating a JSON array in my parent form. I am stuck in how to get my custom radio buttons values and pass them to my method where i am creating JSON array of values.Here is my custom component radio button code
import React, { Component } from "react";
import { View, TouchableOpacity, Text, StyleSheet } from "react-native";
export default class RadioButton extends Component {
state = {
value: null,
};
render() {
const { PROP } = this.props;
const { value } = this.state;
return (
<View>
{PROP.map((res) => {
return (
<View key={res.key} style={styles.container}>
<Text style={styles.radioText}>{res.text}</Text>
<TouchableOpacity
style={styles.radioCircle}
onPress={() => {
this.setState({
value: res.text,
});
}}
>
{value === res.text && <View style={styles.selectedRb} />}
</TouchableOpacity>
</View>
);
})}
<Text> Selected: {this.state.value} </Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
marginBottom: 15,
alignItems: "center",
flexDirection: "row",
justifyContent: "space-between",
},
radioText: {
marginRight: 35,
color: "#000",
},
radioCircle: {
height: 20,
width: 20,
marginRight: 10,
borderRadius: 100,
borderWidth: 2,
borderColor: "#3740ff",
alignItems: "center",
justifyContent: "center",
},
selectedRb: {
width: 15,
height: 15,
borderRadius: 15,
backgroundColor: "#3740ff",
},
result: {
marginTop: 20,
color: "white",
fontWeight: "600",
backgroundColor: "#F3FBFE",
},
});
This is my main class.
import React, { Component } from "react";
import CheckBox from "#react-native-community/checkbox";
import { View, TextInput, Button, StyleSheet, Text } from "react-native";
const data = require("../json/registration.json");
import MyRadioButton from "../component/MyRadioButton";
class Registration extends Component {
constructor(props) {
super(props);
this.state = {
itemstorender: [],
inputData: [],
checked: "",
};
}
addValues = (value, index) => {
let dataArray = this.state.inputData;
let checkBool = false;
if (dataArray.length !== 0) {
dataArray.forEach((element) => {
if (element.index === index) {
element.value = value;
checkBool = true;
}
});
}
if (checkBool) {
this.setState({
inputData: dataArray,
});
} else {
dataArray.push({ value: value, index: index });
this.setState({
inputData: dataArray,
});
// console.log('Data',dataArray);
}
};
getValues = () => {
console.log("Data", this.state.inputData);
};
componentDidMount() {
this.renderData();
}
hideComponent(data) {
// console.log("checkd",data)
this.setState({
checked: data,
});
console.log(this.state.checked);
}
renderData = () => {
const result = data.info;
var itemstorenderLocal = [];
for (var i = 0; i < result.length; i++) {
if (result[i].element == "TextInput") {
let i_id = result[i].id;
console.log("Ids : ", i_id);
itemstorenderLocal.push(
<TextInput
key={result[i].id}
placeholder={result[i].label}
onChangeText={(value) => this.addValues(value, i_id)}
/>
);
this.setState({ itemstorenderLocal });
}else if (result[i].element == "RadioButtons") {
let i_id = result[i].id;
// let options = console.log("Ids : ", i_id);
itemstorenderLocal.push(
<Text>{result[i].label}</Text>,
<View style={styles.container}>
<MyRadioButton
PROP={result[i].options}
/>
</View>
);
this.setState({ itemstorenderLocal });
} else if (result[i].element == "button") {
itemstorenderLocal.push(
<Button
key={result[i].id}
title={result[i].label}
onPress={() => this.getValues()}
/>
);
}
}
this.setState({
itemstorender: itemstorenderLocal,
});
};
render() {
return <View>{this.state.itemstorender}</View>;
}
}
export default Registration;

Related

TypeError: undefined is not an object (evaluating '_this2.state.dataSource.cloneWithRows') when replacing ListView with FlatList

I'm updating a project to react-native 62+ from 50~, and ListView was removed from react-native, and so I'm trying to change the ListView in this file to a FlatList. I don't know what to do with datasource to properly manage the data. Can somebody help me upgrade this file?
This is the original code using the ListView without any of my attempts at upgrading, which gives "Invariant Error: ListView has been removed from React-Native": (my attempted code below)
'use strict';
import React, { Component } from 'react';
import {
ListView,
Platform,
StyleSheet,
Text,
Image,
View,
TouchableOpacity,
TouchableHighlight,
TouchableNativeFeedback,
} from 'react-native';
import PoplarEnv from '../util/PoplarEnv';
import CommentCell from './CommentCell';
import {getCommentsOfObject} from '../api/CommentAPI';
import URLConf from '../api/URLConf';
const avatar_thumbnail = '?imageView2/1/w/48/h/48';
export default class CommentList extends Component{
constructor(props) {
super(props);
this.state = {
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2,
}),
loaded: false,
replyModalVisible: false,
commentsArray: [],
commentCounter: this.props.commentCounter,
commented: this.props.commented,
limit: this.props.limit, //评论显示行数
comment: null,
commentBarVisible: false,
};
}
componentDidMount() {
this.fetchData();
}
/*
被评论的feed类型
*/
getCommentObjType(type) {
var type_str = '';
switch (type) {
case PoplarEnv.COMMENT_OBJ_TYPE.POST:
type_str = 'post';
break;
case PoplarEnv.COMMENT_OBJ_TYPE.PHOTO:
type_str = 'photo';
break;
case PoplarEnv.COMMENT_OBJ_TYPE.ALBUM:
type_str = 'album';
break;
case PoplarEnv.COMMENT_OBJ_TYPE.SPOST:
type_str = 'spost';
break;
default:
type_str = '';
}
return type_str;
}
fetchData() {
var type_str = this.getCommentObjType(this.props.object_type);
getCommentsOfObject(type_str, this.props.object_id,this.state.limit, (result, comments) => {
this.setState({
commentsArray: comments,
dataSource: this.state.dataSource.cloneWithRows(comments),
loaded: true,
});
});
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading...
</Text>
</View>
);
}
setReplyModalVisible() {
this.setState({replyModalVisible: true});
}
setReplyModalInVisible() {
this.setState({replyModalVisible: false});
}
addNewComment(comment) {
console.log('add new comment to comments list');
console.log(comment);
var commentsArray = this.state.commentsArray;
commentsArray.push(comment);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(commentsArray),
});
}
componentWillReceiveProps(nextProps) {
if(this.props.commentCounter == nextProps.commentCounter) return;
if(nextProps.newComment != undefined && nextProps.newComment != null) {
this.addNewComment(nextProps.newComment);
}
}
render() {
if(!this.state.loaded) {
return this.renderLoadingView();
}
return this.renderCommentList(this.props.commentCounter);
}
showCommentBar() {
this.setState({
commentBarVisible: true,
});
}
hideCommentBar() {
this.setState({
isComment: false,
commentBarVisible: false,
});
}
renderCommentList(commentCounter) {
if(commentCounter > 0) {
return (
<TouchableOpacity style={styles.commentList} onPress={this.props.nav2FeedDetail}>
<ListView
dataSource={this.state.dataSource}
renderRow={(comment)=>this.renderRow(comment, this.props.caller)}
/>
</TouchableOpacity>
);
} else {
return (<View/>);
}
}
renderAuthorName(comment) {
if(comment.comment_parent_author_name != undefined && comment.comment_parent_author_name != null) {
return (<View style={{flex: 1, flexDirection: 'row'}}>
<Text style={styles.username}>{comment.comment_author_name}</Text>
<Text style={{fontSize: 14, color: '#9B9B9B', bottom: 1}}> Reply </Text>
<Text style={styles.username}>{comment.comment_parent_author_name}</Text>
</View>
);
} else {
return (<Text style={styles.username}>{comment.comment_author_name}</Text>);
}
}
renderRow(comment, caller) {
if(comment == null || comment == undefined) {
return (<View />);
} else {
if(caller == 'FeedCell') {
return(
<View style={styles.commentBox}>
<Image style={styles.avatar} source={{uri:URLConf.IMG_BASE_URL+comment.comment_author_avatar+avatar_thumbnail}} />
<View style={{flex:1}}>
{this.renderAuthorName(comment)}
<Text style={styles.comment}>{comment.comment_content}</Text>
</View>
</View>
);
} else if(caller == 'FeedDetail') {
return(
<CommentCell comment={comment} reply={this.props.reply}/>
);
}
}
}
};
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
commentList: {
marginTop: -10,
marginLeft:8,
marginRight:8,
paddingTop: 0,
},
commentBox: {
flex: 1,
flexDirection: 'row',
//borderColor: 'black',
//borderWidth: 1,
padding: 10,
paddingBottom: 4,
},
avatar: {
borderRadius: 16,
width: 32,
height: 32,
marginRight: 10,
},
username: {
fontSize: 14,
fontWeight: 'bold',
color: 'black',
// lineHeight: 13,
marginBottom: 4,
},
commentTime: {
},
comment: {
fontSize: 14,
color: '#030303',
lineHeight: 18,
},
});
module.exports = CommentList;
This is the code of my attempt at upgrading it, but I get this error "TypeError: undefined is not an object (evaluating '_this2.state.dataSource.cloneWithRows')" on line 78 "dataSource: this.state.dataSource.cloneWithRows(comments),"
'use strict';
import React, { Component } from 'react';
import {
FlatList,
//ListView,
Platform,
StyleSheet,
Text,
Image,
View,
TouchableOpacity,
TouchableHighlight,
TouchableNativeFeedback,
} from 'react-native';
import PoplarEnv from '../util/PoplarEnv';
import CommentCell from './CommentCell';
import {getCommentsOfObject} from '../api/CommentAPI';
import URLConf from '../api/URLConf';
const avatar_thumbnail = '?imageView2/1/w/48/h/48';
export default class CommentList extends Component{
constructor(props) {
super(props);
this.state = {
// dataSource: new ListView.DataSource({
// rowHasChanged: (row1, row2) => row1 !== row2,
// }),
loaded: false,
replyModalVisible: false,
commentsArray: [],
commentCounter: this.props.commentCounter,
commented: this.props.commented,
limit: this.props.limit, //评论显示行数
comment: null,
commentBarVisible: false,
};
}
componentDidMount() {
this.fetchData();
}
/*
被评论的feed类型
*/
getCommentObjType(type) {
var type_str = '';
switch (type) {
case PoplarEnv.COMMENT_OBJ_TYPE.POST:
type_str = 'post';
break;
case PoplarEnv.COMMENT_OBJ_TYPE.PHOTO:
type_str = 'photo';
break;
case PoplarEnv.COMMENT_OBJ_TYPE.ALBUM:
type_str = 'album';
break;
case PoplarEnv.COMMENT_OBJ_TYPE.SPOST:
type_str = 'spost';
break;
default:
type_str = '';
}
return type_str;
}
fetchData() {
var type_str = this.getCommentObjType(this.props.object_type);
getCommentsOfObject(type_str, this.props.object_id,this.state.limit, (result, comments) => {
this.setState({
commentsArray: comments,
dataSource: this.state.dataSource.cloneWithRows(comments),
loaded: true,
});
});
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading...
</Text>
</View>
);
}
setReplyModalVisible() {
this.setState({replyModalVisible: true});
}
setReplyModalInVisible() {
this.setState({replyModalVisible: false});
}
addNewComment(comment) {
console.log('add new comment to comments list');
console.log(comment);
var commentsArray = this.state.commentsArray;
commentsArray.push(comment);
this.setState({
dataSource: this.state.dataSource.cloneWithRows(commentsArray),
});
}
componentWillReceiveProps(nextProps) {
if(this.props.commentCounter == nextProps.commentCounter) return;
if(nextProps.newComment != undefined && nextProps.newComment != null) {
this.addNewComment(nextProps.newComment);
}
}
render() {
if(!this.state.loaded) {
return this.renderLoadingView();
}
return this.renderCommentList(this.props.commentCounter);
}
showCommentBar() {
this.setState({
commentBarVisible: true,
});
}
hideCommentBar() {
this.setState({
isComment: false,
commentBarVisible: false,
});
}
renderCommentList(commentCounter) {
if(commentCounter > 0) {
return (
<TouchableOpacity style={styles.commentList} onPress={this.props.nav2FeedDetail}>
<FlatList
data={this.state.dataSource}
extraData={this.state}
renderItem={(comment)=>this.renderRow(comment, this.props.caller)}
/>
{/* <ListView
dataSource={this.state.dataSource}
renderRow={(comment)=>this.renderRow(comment, this.props.caller)}
/> */}
</TouchableOpacity>
);
} else {
return (<View/>);
}
}
renderAuthorName(comment) {
if(comment.comment_parent_author_name != undefined && comment.comment_parent_author_name != null) {
return (<View style={{flex: 1, flexDirection: 'row'}}>
<Text style={styles.username}>{comment.comment_author_name}</Text>
<Text style={{fontSize: 14, color: '#9B9B9B', bottom: 1}}> Reply </Text>
<Text style={styles.username}>{comment.comment_parent_author_name}</Text>
</View>
);
} else {
return (<Text style={styles.username}>{comment.comment_author_name}</Text>);
}
}
renderRow(comment, caller) {
if(comment == null || comment == undefined) {
return (<View />);
} else {
if(caller == 'FeedCell') {
return(
<View style={styles.commentBox}>
<Image style={styles.avatar} source={{uri:URLConf.IMG_BASE_URL+comment.comment_author_avatar+avatar_thumbnail}} />
<View style={{flex:1}}>
{this.renderAuthorName(comment)}
<Text style={styles.comment}>{comment.comment_content}</Text>
</View>
</View>
);
} else if(caller == 'FeedDetail') {
return(
<CommentCell comment={comment} reply={this.props.reply}/>
);
}
}
}
};
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'white',
},
commentList: {
marginTop: -10,
marginLeft:8,
marginRight:8,
paddingTop: 0,
},
commentBox: {
flex: 1,
flexDirection: 'row',
//borderColor: 'black',
//borderWidth: 1,
padding: 10,
paddingBottom: 4,
},
avatar: {
borderRadius: 16,
width: 32,
height: 32,
marginRight: 10,
},
username: {
fontSize: 14,
fontWeight: 'bold',
color: 'black',
// lineHeight: 13,
marginBottom: 4,
},
commentTime: {
},
comment: {
fontSize: 14,
color: '#030303',
lineHeight: 18,
},
});
module.exports = CommentList;
If you need any more code, like CommentCell or FeedCell, just let me know and I'll edit the post to add the code. Can somebody please help me with this, I've spent hours on it.
You have to totally change ListView to Flatlist.
So first import Flatlist from the react-native :
import { FlatList } from "react-native";
Then change ListView to Flatlist as below :
renderCommentList(commentCounter) {
if(commentCounter > 0) {
return (
<TouchableOpacity style={styles.commentList} onPress={this.props.nav2FeedDetail}>
<FlatList
data={this.state.dataSource}
extraData={this.state}
renderItem={({ item })=>this.renderRow(item, this.props.caller)}
/>
</TouchableOpacity>
);
} else {
return (<View/>);
}
}
You can find more documentation here
Update
Your dataSource state variable should be simple array like this :
this.state = {
dataSource: []
}
Then when you fetch the data, append your data in dataSource state variable like this :
this.setState({
commentsArray: comments,
dataSource: comments,
loaded: true,
});
**Note : **Your renderItems method should be as below :
renderItem={({ comment })=>this.renderRow(comment, this.props.caller)}
comment should be in {} braces.

To store multiple values of form using AsyncStorage

I need to store two values from a screen using AsyncStorage and also store it in the format of key value pairs.I want this data to be stored locally in the mobile and later retrieved from it when needed.
I have tried to retrieve single data but haven't been able to do with multiple data.
import React, { Component } from 'react';
import { StyleSheet, AsyncStorage, TextInput, View, Alert, Button, Text, TouchableOpacity } from 'react-native';
class FormData extends Component {
constructor(props){
super(props)
this.state = {
// myKey: '',
key: '',
text1: '',
text2: '',
getValue: '',
infoValue:''
};
}
savefunction = () => {
let storedObject = {};
storedObject.textval1 = text1;
storedObject.textval2 = text2;
try {
AsyncStorage.setItem('allTextValue', JSON.stringify(storedObject));
} catch (error) {
}
}
getfunction = () => {
try {
AsyncStorage.getItem('allTextValue').then((infoValue) => {
let resObject = JSON.parse(infoValue);
let textval1 = resObject.text1
let textval2 = resObject.text2
}).done();
} catch (error) {
}
}
render (){
return(
<View style={styles.MainContainer}>
<Text style= {styles.TextComponentStyle}>User Form</Text>
<TextInput
placeholder="Enter User Email"
onChangeText={(value) => this.setState({ text1: value})}
underlineColorAndroid='transparent'
style={styles.TextInputStyleClass}
/>
<TextInput
placeholder="Enter User Password"
onChangeText={(value) => this.setState({ text2: value})}
underlineColorAndroid='transparent'
style={styles.TextInputStyleClass}
/>
<Button onPress={this.savefunction}
title="Save key" color="#2196F3" />
<Button onPress={this.getfunction}
title="Get key" color="#2196F3" />
<Text style={styles.text}> {this.state.getValue} </Text>
</View>
);
}
}
export default FormData;
const styles = StyleSheet.create({
MainContainer :{
justifyContent: 'center',
flex:1,
margin: 10,
},
TextInputStyleClass: {
textAlign: 'center',
marginBottom: 7,
height: 40,
borderWidth: 1,
// Set border Hex Color Code Here.
borderColor: '#2196F3',
// Set border Radius.
borderRadius: 5 ,
},
text: {
fontSize: 20,
textAlign: 'center',
},
TextComponentStyle: {
fontSize: 20,
color: "#000",
textAlign: 'center',
marginBottom: 15
}
});
I expect multiple data to be stored in the map with key value pair
You're not saving the price properly. You declare a status value and are putting a value into a variable with the same name. Code needs to be modified.
savefunction = () => {
let storedObject = {};
storedObject.textval1 = this.state.text1;
storedObject.textval2 = this.state.text2;
try {
AsyncStorage.setItem('allTextValue', JSON.stringify(storedObject));
} catch (error) {
}
}
...
getfunction = async () => {
try {
const infoValue = await AsyncStorage.getItem('allTextValue')
let resObject = JSON.parse(infoValue);
let textval1 = resObject.textval1
let textval2 = resObject.textval2
console.log(textval1);
console.log(textval2);
} catch (error) {
console.log(error);
}
}
The only part i see a problem is where you get the values from the object when you get the items:
let resObject = JSON.parse(infoValue);
let textval1 = resObject.textval1
let textval2 = resObject.textval1
You can also change it to
let resObject = JSON.parse(infoValue);
let {textval1, textval2} = resObject

How to make a QR code scanner in React native using expo?

When I run https://snack.expo.io/#sushil62/qr-code-scanner in the expo which works fine, but when copy the same code given in App.js file, after running the application the camera opens but it shows no result while scanning, and
in expo also when changing the snack version 33 or higher it does not work there too.
import React, { Component } from 'react';
import { Alert, Linking, Dimensions, LayoutAnimation, Text, View, StatusBar, StyleSheet, TouchableOpacity } from 'react-native';
import { BarCodeScanner, Permissions } from 'expo';
export default class App extends Component {
state = {
hasCameraPermission: null,
lastScannedUrl: null,
};
componentDidMount() {
this._requestCameraPermission();
}
_requestCameraPermission = async () => {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted',
});
};
_handleBarCodeRead = result => {
if (result.data !== this.state.lastScannedUrl) {
LayoutAnimation.spring();
this.setState({ lastScannedUrl: result.data });
}
};
render() {
return (
<View style={styles.container}>
{this.state.hasCameraPermission === null
? <Text>Requesting for camera permission</Text>
: this.state.hasCameraPermission === false
? <Text style={{ color: '#fff' }}>
Camera permission is not granted
</Text>
: <BarCodeScanner
onBarCodeRead={this._handleBarCodeRead}
style={{
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
}}
/>}
{this._maybeRenderUrl()}
<StatusBar hidden />
</View>
);
}
_handlePressUrl = () => {
Alert.alert(
'Open this URL?',
this.state.lastScannedUrl,
[
{
text: 'Yes',
onPress: () => Linking.openURL(this.state.lastScannedUrl),
},
{ text: 'No', onPress: () => {} },
],
{ cancellable: false }
);
};
_handlePressCancel = () => {
this.setState({ lastScannedUrl: null });
};
_maybeRenderUrl = () => {
if (!this.state.lastScannedUrl) {
return;
}
return (
<View style={styles.bottomBar}>
<TouchableOpacity style={styles.url} onPress={this._handlePressUrl}>
<Text numberOfLines={1} style={styles.urlText}>
{this.state.lastScannedUrl}
</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.cancelButton}
onPress={this._handlePressCancel}>
<Text style={styles.cancelButtonText}>
Cancel
</Text>
</TouchableOpacity>
</View>
);
};
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#000',
},
bottomBar: {
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0,0,0,0.5)',
padding: 15,
flexDirection: 'row',
},
url: {
flex: 1,
},
urlText: {
color: '#fff',
fontSize: 20,
},
cancelButton: {
marginLeft: 10,
alignItems: 'center',
justifyContent: 'center',
},
cancelButtonText: {
color: 'rgba(255,255,255,0.8)',
fontSize: 18,
},
});
It would be very nice if someone suggests me to solve this or give me an example(such as downgrading the expo version) so that I can implement this.
You can use
expo-barcode-scanner
Run expo install expo-barcode-scanner
Usage
You must request permission to access the user's camera before attempting to get it. To do this, you will want to use the Permissions API. You can see this in practice in the following example.
import * as React from 'react';
import {
Text,
View,
StyleSheet,
Button
} from 'react-native';
import Constants from 'expo-constants';
import * as Permissions from 'expo-permissions';
import {
BarCodeScanner
} from 'expo-barcode-scanner';
export default class BarcodeScannerExample extends React.Component {
state = {
hasCameraPermission: null,
scanned: false,
};
async componentDidMount() {
this.getPermissionsAsync();
}
getPermissionsAsync = async() => {
const {
status
} = await Permissions.askAsync(Permissions.CAMERA);
this.setState({
hasCameraPermission: status === 'granted'
});
};
render() {
const {
hasCameraPermission,
scanned
} = this.state;
if (hasCameraPermission === null) {
return <Text > Requesting
for camera permission < /Text>;
}
if (hasCameraPermission === false) {
return <Text > No access to camera < /Text>;
}
return ( <
View style = {
{
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-end',
}
} >
<
BarCodeScanner onBarCodeScanned = {
scanned ? undefined : this.handleBarCodeScanned
}
style = {
StyleSheet.absoluteFillObject
}
/>
{
scanned && ( <
Button title = {
'Tap to Scan Again'
}
onPress = {
() => this.setState({
scanned: false
})
}
/>
)
} <
/View>
);
}
handleBarCodeScanned = ({
type,
data
}) => {
this.setState({
scanned: true
});
alert(`Bar code with type ${type} and data ${data} has been scanned!`);
};
}
Note: Passing undefined to the onBarCodeScanned prop will result in no scanning. This can be used to effectively "pause" the scanner so that it doesn't continually scan even after data has been retrieved.
Allow all the permisions which gets popped.
You're good to go!!
Hope this helps.

ReactNative: Custom CheckBox for both Android and iOS

As said here <checkBox/> is only possible for android but i want to implement single code for both android and iOS (without using any node packages). For this i'm proceeding with views as below
import React, { Component } from 'react';
import { Platform, View, TouchableOpacity } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
checkSelected: 1
}
}
checkClick(id) {
this.setState({
checkSelected: id
})
}
render() {
const products = [{
id: 1
},
{
id: 2
},
{
id: 3
}];
return (
products.map((val) => {
return (
<TouchableOpacity key={val.id} onPress={this.checkClick.bind(this, val.id)}>
<View style={{
height: 24,
width: 24,
border: 12,
borderWidth: 2,
borderColor: '#000',
alignItems: 'center',
justifyContent: 'center',
}}>
{
val.id == this.state.checkSelected ?
<View style={{
height: 12,
width: 12,
border: 6,
backgroundColor: '#000',
}} />
: null
}
</View>
</TouchableOpacity>
)
})
);
}
}
This output will be like this
This approach is like RadioButton but i want to follow the <View/> approach for CheckBox also. For this i've implemented like this
import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
checkSelected: []
}
}
checkClick(id) {
let todos = [...this.state.checkSelected]; //creating the copy
//adding new data
todos.push({
checkId: id
});
//updating the state value
this.setState({ checkSelected: todos }, () => {
alert('state: ' + JSON.stringify(this.state.checkSelected));
});
}
render() {
const products = [{
id: 1
},
{
id: 2
},
{
id: 3
}];
return (
products.map((val) => {
return (
<TouchableOpacity key={val.id} onPress={this.checkClick.bind(this, val.id)}>
<View style={{
height: 24,
width: 24,
border: 12,
borderWidth: 2,
borderColor: '#000',
alignItems: 'center',
justifyContent: 'center',
}}>
{
this.state.checkSelected.map((checkIds) => {
{
checkIds.checkId == val.id ?
<View style={{
height: 12,
width: 12,
border: 6,
backgroundColor: '#000',
}} />
: null
}
})
}
</View>
</TouchableOpacity>
)
})
);
}
}
In this approach i'm storing clicked id's in state and trying to select all checkboxes which id's are in state but i'm unable to do that. Can any one suggest me to select multiple check boxes.
Solution
Make new CheckBox component.
Call CheckBox components with right props.
Change your state value depending on CheckBox's clicked prop.
import React, { Component } from 'react';
import { View, TouchableOpacity } from 'react-native';
class CheckBox extends Component {
  constructor(props) {
    super(props);
    this.state = {isCheck: false};
  }
  checkClicked = async () => {
    await this.setState(prevState => ({
      isCheck: !prevState.isCheck,
    })); // setState is async function.
    // Call function type prop with return values.
    this.props.clicked && this.props.clicked(this.props.value, this.state.isCheck);
  }
  render() {
    return (
      <TouchableOpacity onPress={this.checkClicked} style={this.props.style}>
        <View style={{
          height: 24,
          width: 24,
          borderWidth: 2,
          borderColor: '#000',
          alignItems: 'center',
          justifyContent: 'center',
        }}>
          <View style={{
            height: 12,
            width: 12,
            backgroundColor: this.state.isCheck ? '#000' : '#FFF',
          }} />
        </View>
      </TouchableOpacity>
    )
  }
}
const products = [
  {
    id: 1
  },
  {
    id: 2
  },
  {
    id: 3
  }
];
export default class CheckBoxScreen extends Component {
constructor(props) {
super(props);
this.state = {
checkSelected: [],
    }
}
  toggleCheckBox = (id, isCheck) => {
    let { checkSelected } = this.state;
    if (isCheck) {
      checkSelected.push(id);
    } else { // remove element
      var index = checkSelected.indexOf(id);
      if (index > -1) {
        checkSelected.splice(index, 1);
      }
    }
    this.setState({ checkSelected });
    alert(this.state.checkSelected); // logging
  }
render() {
    const checkboxs = products.map(({id}) =>
      <CheckBox style={{marginTop: 50,}}key={id} value={id} clicked={(id, isCheck) => this.toggleCheckBox(id, isCheck)}></CheckBox>
    )
return (
      <View style={{flex: 1, alignItems: 'center'}}>
        {checkboxs}
      </View>
);
}
}
It will work and you can use my example to other ways what you want.
In a different soluion, i would recommend to make a checkbox component , which will have properties id and onCheckBoxValueChange. Both will take initial values from parent component, and on every change, the state of local component will change, returning a callback with the id of the selected.
Child:
constructor(props) {
super(props);
this.state = {
value: this.props.value
};
}
onCheckBoxValueChange(id) {
this.setState({ value: !this.state.value });
this.props.onCheckBoxValueChange(id, !this.state.value);
}
render() {
return (
<ViewStyledAsCheckBox
style={styles.checkBox}
isChecked={this.state.value}
onPress={() => this.onCheckBoxValueChange(this.props.id)}
/>
Parent will call child component like this:
<CheckBoxComponent
id={1}
onCheckBoxValueChange={(id, value) =>
this.doSomethingWithChangedValueInThisSpecificChekbox(id, value)
}
/>
<CheckBoxComponent
id={2}
onCheckBoxValueChange={(id, value) =>
this.doSomethingWithChangedValueInThisSpecificChekbox(id, value)
}
/>
Let me know if this works for you or want more information as this is more of a template than real implementation

React Native Search Dropdown

I'm working on React native app. I'm looking for a searchable dropdown which I need to implement in many places.
Below see below video for reference:
Sample Video
I have implemented below third parties but they are not same as I need:
https://www.npmjs.com/package/react-native-searchable-dropdown
https://www.npmjs.com/package/react-native-searchable-selectbox
https://github.com/toystars/react-native-multiple-select
I tried implementing something similar a while ago and at the time I dropped the idea of having a drop down as it was inconsistent on both platforms & I could not find a perfect solution. I cannot see your video but I think I know where you're going with this.
Here is my advice:
I would create a separate screen that opens on the tap on this component that would be a 'dropdown', and in there create a searchable/filtrable list. You could try doing that using this: https://www.npmjs.com/package/searchable-flatlist, or create your own flatlist, which is super easy and allows for more customization!
EDIT:
If you don't want a separate screen use this: https://www.npmjs.com/package/react-native-searchable-dropdown
try implementing one :
const sports = ["Badminton","Cricket","Chess","Kho-Kho","Kabbadi","Hockey","Boxing","Football","Basketball","Volleyball","Tennis","Table Tennis"];
predict(){
let q = this.state.query;
let arr = sports.filter(ele => ele.toLowerCase().indexOf(q.toLowerCase()) != -1).splice(0,5);
this.setState((prev = this.state)=>{
let obj={};
Object.assign(obj,prev);
obj.predictions.splice(0,obj.predictions.length);
arr.forEach(ele=>{
obj.predictions.push({key : ele});
});
return obj;
});
}
<TouchableWithoutFeedback onPress={()=>{this.setState({done : true})}}>
<ScrollView
keyboardShouldPersistTaps='handled'
contentContainerStyle={style.content}
>
<View>
<TextInput
onChangeText={(text)=>{
this.setState({query : text , done : false});
this.predict();
}}
placeholder="What do you want to play ?"
placeholderTextColor="#A6A4A4"
value = {this.state.query}
onSubmitEditing = {()=>{this.setState({done : true})}}
underlineColorAndroid = "#0098fd"
></TextInput>
<TouchableOpacity onPress={()=>{this.filteredEvents()}}><Icon name="search" color = "#0098fd" size = {20}></Icon></TouchableOpacity>
</View>
{
this.state.predictions.length != 0 && !this.state.done &&
<FlatList
style={styles.predictor_view}
data={this.state.predictions}
extraData = {this.state}
renderItem = {
({item})=>(
<TouchableOpacity
style={styles.predictions}
onPress={()=>{
console.log('ok');
this.setState({query : item.key,done : true});
console.log(this.state);
}}>
<Text>{item.key}</Text>
</TouchableOpacity>
)
}
/>
}
</ScrollView>
</TouchableWithoutFeedback>
I have used react-native-autocomplete-input
I have written a component to help in the dropdown:
customDropDownComponent.js
/*This is an example of AutoComplete Input/ AutoSuggestion Input*/
import React, { Component } from 'react';
import { StyleSheet, Text, TouchableOpacity, View, Button, ScrollView } from 'react-native';
//import all the components we are going to use.
import Autocomplete from 'react-native-autocomplete-input'
//import Autocomplete component
class CustomDropDownComponent extends Component {
constructor(props) {
super(props);
//Initialization of state
//films will contain the array of suggestion
//query will have the input from the autocomplete input
this.state = {
query: '',
data: [],
dataDuplicate:[],
itemSelected: false
};
}
componentDidMount() {
//Loading all data
this.loadData()
}
findElement(query, text, itemSelected) {
//method called everytime when we change the value of the inputquery === '' ||
if (itemSelected === true||query==='') {
//if the query is null or an item is selected then return blank
return [];
}
//making a case insensitive regular expression to get similar value from the data json
const regex = new RegExp(`${query.trim()}`, 'i');
//return the filtered data array according the query from the input
var newList = [];
var result = this.state.IATADup.filter(data => {
if (data.id.search(regex) === 0) {
newList.push(data);
return false;
} else {
return data.id.search(regex) >= 0;
}
});
result = newList.concat(result);
this.props.adjustMargin(1, result.length);//expadnding space in page to make room for dropdown
this.setState({ data: result, query: text, itemSelected: itemSelected });
}
loadData = () => {
var dataToLoad = Commondata.aircraftDetail
dataToLoad.sort(function (a, b) {
if (a.id > b.id) {
return 1;
}
if (b.id > a.id) {
return -1;
}
return 0;
});
this.setState({
dataDuplicate: dataToLoad
})
}
render() {
const { query } = this.state;
const data = this.state.data;
const comp = (a, b) => a.toLowerCase().trim() === b.toLowerCase().trim();
var inputContainerStyle = styles.inputContainerStyle;
if (this.props.destinationBorder === "#FF0000") {
inputContainerStyle = styles.inputContainerRedStyle;
}
return (
<View style={styles.container} >
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
flatListProps={{ nestedScrollEnabled: true }}
containerStyle={styles.autocompleteContainer}
listStyle={styles.listStyle}
inputContainerStyle={inputContainerStyle}
data={data}
keyExtractor={(item, i) => { return i }
defaultValue={query}
onChangeText={text => {
//handle input
if (text.trim() === "") this.props.adjustMarginBack();//adjust margin to normal in case of empty searrch element
this.findElement(text, text, false);//search for element
}}
placeholder={en.pick_one}
renderItem={({ item }) => (
//you can change the view you want to show in suggestion from here
<TouchableOpacity onPress={() => {
this.props.adjustMarginBack()
this.setState({ query: item.id, itemSelected: true, data: [] });
}}>
<Text style={styles.itemText}>
{item.id}
</Text>
<Text style={styles.itemSubText}>
{item.name}
</Text>
</TouchableOpacity>
)}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF'
},
autocompleteContainer: {
backgroundColor: '#ffffff',
borderWidth: 0,
},
inputContainerStyle: {
borderWidth: 0.5, borderColor: '#D9D9D9', padding: '1.5%'
},
inputContainerRedStyle: {
borderWidth: 0.5, borderColor: '#FF0000', padding: '1.5%'
},
descriptionContainer: {
flex: 1,
justifyContent: 'center',
padding: '5%'
},
itemText: {
fontSize: 15,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
},
itemSubText: {
fontSize: 10,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
marginLeft: 10
},
infoText: {
textAlign: 'center',
fontSize: 16,
},
listStyle: {
height: 100,
position: "relative",
zIndex: 999
}
});
export default CustomComponent;
Now in the display screen:
app.js
import React, { Component } from 'react';
import { View, Text, ScrollView } from 'react-native';
import CustomDropDownComponent from './CustomDropDownComponent.js'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<View>
<ScrollView
nestedScrollEnabled={true}
keyboardShouldPersistTaps={'handled'}>
<CustomDropDownComponent /*Handle all inputs and margin resets as props *//>
</ScrollView>
</View>
);
}
}