Get data from multiple custom checkboxes in react native - javascript

I am building a small quiz in react native. On my screen, I want the user to chose several correct answers from a choice of 4-6 options. I build a custom checkbox for that. If the correct answers are checked (and all wrong answers are unchecked) the user should get a message that the answer was correct.
Here is the custom checkbox component. I only included the code for three boxes to make the code a bit shorter:
import { TouchableOpacity, StyleSheet, View, Text } from "react-native";
import { FontAwesome } from "#expo/vector-icons";
function AnswerContainer_CheckBox(props) {
const [userInput, setUserInput] = useState("");
const answerHandler = () => {
if (userInput == props.finalAnswer) {
dispatch(answerTrue());
}
};
const [checked_1, setChecked_1] = useState(false);
const [checked_2, setChecked_2] = useState(false);
const [checked_3, setChecked_3] = useState(false);
/*Visibility
if set to false via props, the checkbox won't show
*/
const [box_1_Visibility, setBox_1_Visibility] = useState(
props.box_1_Visibility
);
const [box_2_Visibility, setBox_2_Visibility] = useState(
props.box_2_Visibility
);
const [box_3_Visibility, setBox_3_Visibility] = useState(
props.box_3_Visibility
);
/* Functions to chech and uncheck ityems*/
const checkedHandler_1 = () => {
if (checked_1 == false) {
setChecked_1(true);
setUserInput(userInput + props.box_1_Letter);
answerHandler();
} else {
setChecked_1(false);
setUserInput(userInput.replace(props.box_1_Letter,""));
answerHandler();
}
};
const checkedHandler_2 = () => {
if (checked_2 == false) {
setChecked_2(true);
setUserInput(userInput + props.box_2_Letter);
answerHandler();
} else {
setChecked_2(false);
setUserInput(userInput.replace(props.box_2_Letter,""));
answerHandler();
}
};
const checkedHandler_3 = () => {
if (checked_3 == false) {
setChecked_3(true);
setUserInput(userInput + props.box_3_Letter);
answerHandler();
} else {
setChecked_3(false);
setUserInput(userInput.replace(props.box_4_Letter,""));
answerHandler();
}
};
return (
<View>
{/* Checkbox 1 */}
<TouchableOpacity
onPress={() => {
checkedHandler_1();
}}
>
<View
style={
(box_1_Visibility === true && styles.mainContainer) || styles.hide
}
>
<View style={styles.icon}>
<FontAwesome
name={checked_1 == true ? "check-square" : "square-o"}
size={24}
color={checked_1 == true ? "#3787FF" : "#BFD3E5"}
/>
</View>
<Text style={styles.checkButtonText}>{props.box_1_Label}</Text>
</View>
</TouchableOpacity>
{/* Checkbox 2 */}
<TouchableOpacity
onPress={() => {
checkedHandler_2();
}}
>
<View
style={
(box_2_Visibility === true && styles.mainContainer) || styles.hide
}
>
<View style={styles.icon}>
<FontAwesome
name={checked_2 == true ? "check-square" : "square-o"}
size={24}
color={checked_2 == true ? "#3787FF" : "#BFD3E5"}
/>
</View>
<Text style={styles.checkButtonText}>{props.box_2_Label}</Text>
</View>
</TouchableOpacity>
{/* Checkbox 3 */}
<TouchableOpacity
onPress={() => {
checkedHandler_3();
}}
>
<View
style={
(box_3_Visibility === true && styles.mainContainer) || styles.hide
}
>
<View style={styles.icon}>
<FontAwesome
name={checked_3 == true ? "check-square" : "square-o"}
size={24}
color={checked_3 == true ? "#3787FF" : "#BFD3E5"}
/>
</View>
<Text style={styles.checkButtonText}>{props.box_3_Label}</Text>
</View>
</TouchableOpacity>
</View>
);
}
So what is happening here: onPress the checkedHandler-function checks the state. If "false" it will change it to "true". If it is "true" it will change to "false". Depending on the state, the style of the checkbox will change. The checkedHandler-function will also update the string within "userInput" depending on the state. The content of the string is catched via props from the parent component ("box_1_Letter" etc).
This is how I added the component in my screen/parent component:
<AnswerContainer_CheckBox
finalAnswer={"AC"}
box_1_Visibility={true}
box_2_Visibility={true}
box_3_Visibility={true}
box_4_Visibility={true}
box_5_Visibility={false}
box_6_Visibility={false}
box_1_Label={"Shanghai"}
box_1_Letter={"A"}
box_2_Label={"Paris"}
box_2_Letter={"B"}
box_3_Label={"New York"}
box_3_Letter={"C"}
box_4_Label={"Berlin"}
box_4_Letter={"D"}
/>
As you can see I first define how many boxes should be visible and I also add a label to each box and the associated "letter". "finalAnswer" contains the correct answer.
Now comes my problem: let's say in my example "Shanghai" and "New York" are the correct answers. Both boxes have to be checked while all other boxes have to be unchecked. How do I check that within the parent component/Screen?. My solution does not work. The user would have to check the boxes in the right order (and even then it somehow didn't work). The solution would also only be available within the component, not the parent. I do not want to create a global state with redux for this.
Any help appreciated (be aware: I am pretty new to this :-)

this modified answerHandler should solve your problem
const answerHandler = () => {
// if input length equals result length
if (userInput.length === props.finalAnswer.length) {
const inclusionMap = Array.from(props.finalAnswer).map((char) => {
return userInput.includes(char);
});
// if all the characters are included
if (inclusionMap.every((bool) => bool === true)) {
dispatch(answerTrue());
}
}
};

Related

Callback function leads to infinity loop error in react native

I am new to react native and simply can not find the reason for the infinity loop error I spent my last few hours with... Here is what is happening:
I have the following custom component
import { TouchableOpacity, StyleSheet, View, Text } from "react-native";
import { FontAwesome } from "#expo/vector-icons";
function AnswerContainer_CheckBox(props) {
const [checked, setChecked] = useState(false);
const checkedHandler =()=>{
if (checked == false) {
setChecked(true);
} else {
setChecked(false);
}
}
return (
<View>
<TouchableOpacity
onPress={() => {
checkedHandler();
props.true_1;
}
}
>
<View style={styles.mainContainer}>
<View style={styles.icon}>
<FontAwesome
name={checked == true ? "check-square" : "square-o"}
size={24}
color={checked == true ? "#3787FF" : "#BFD3E5"}
/>
</View>
<Text style={styles.checkButtonText}>{props.title}</Text>
</View>
</TouchableOpacity>
</View>
);
}
I use that Component in my screen like this:
function myScreen(props) {
const [true1, setTrue1] = useState(false);
const setTrue_1_Handler = () => {
switch (true1) {
case false:
setTrue1(true);
alert("true");
break;
case true:
setTrue1(false);
break;
}
};
return (
<SafeAreaView>
<AnswerContainer_CheckBox true_1={setTrue_1_Handler()} title="Test_1" />
<AnswerContainer_CheckBox title="Test_2" />
<AnswerContainer_CheckBox title="Test_3" />
</SafeAreaView>
);
}
Whenever I navigate to "myScreen", the infite loop error apperas and crashes the app - even though I didn't press that button yet.
Any ideas? I know the issue has come up a few times but I still didn't make it work (useEffect didn't help somehow...).
Thanks

How to check a textInput on emptiness

I need your help. I want to check my textInput for an empty filed, when I am pressing a button. Because now my application can route user to target page with empty fields. So I need to check this fields on emptyness. But I don't know how to do it. I will be very glad, if you help me.
This is my component
import React, { Component } from 'react'
import { View, TextInput } from 'react-native'
import { MyButton, ErrorMessage } from '../uikit'
import { FormStyle, InputStyle } from '../constants/styles'
import { LOG_IN } from '../routes'
export class SignIn extends Component {
state = {
isValidPasword: true,
isEqual: true,
isValidMail: true,
currentPassword: ''
}
isEnoughSymbols = (text) => {
if (text.trim().length < 8) {
this.setState({ isValidPasword: false })
}
else {
this.setState({ currentPassword: text, isValidPasword: true })
}
}
isMatch = (text) => {
if (text != this.state.currentPassword) {
this.setState({ isEqual: false })
}
}
isMail = (text) => {
const pattern = /\b[a-z0-9._]+#[a-z0-9.-]+\.[a-z]{2,4}\b/i
let res = text.search(pattern)
res == -1 ? this.setState({ isValidMail: false }) : this.setState({ isValidMail: true })
}
render() {
const { mainContainer, buttons } = FormStyle
const { container, text } = InputStyle
const { isValidPasword, isEqual, isValidMail, currentPassword } = this.state
return (
<View style={mainContainer}>
<View style={container}>
<TextInput
style={text}
placeholder={'Email'}
onEndEditing={(e) => this.isMail(e.nativeEvent.text)}
>
</TextInput>
{
isValidMail ? null : <ErrorMessage errorText={'Invalid email!'} />
}
</View>
<View style={container}>
<TextInput
style={text}
placeholder={'Password'}
secureTextEntry={true}
onEndEditing={(e) => this.isEnoughSymbols(e.nativeEvent.text)}
>
</TextInput>
{
isValidPasword ? null : <ErrorMessage errorText={'Password must have at least 8 symbols!'} />
}
</View>
<View style={container}>
<TextInput
style={text}
secureTextEntry={true}
placeholder={'Confirm password'}
>
</TextInput>
{
isEqual ? null : <ErrorMessage errorText={'Passwords not matching'} />
}
</View>
<View style={buttons}>
<MyButton
name={'confirm'.toUpperCase()}
onPress={() => (isEqual && isValidMail && isValidPasword) ? this.props.navigation.navigate(LOG_IN) : alert('Your data is wrong!')} />
</View>
</View>
)
}
}
Set the value of the text input using state.
E.g.
state = {
/// rest of state
textValue: ""
}
In the TextInput component add a function to set the state onChange, so the textValue changes when the user types, e.g. (e) => this.setState({ textValue: e.nativeEvent.text })
Then you can check if the input is empty with a function that checks for the state value, like if(this.textValue === "") and then handle the empty vs. not-empty condition.
Better way you can make function like this to check empty spaces, Blank value and text length.
function isEmpty(isFieldEmpty) {
isFieldEmpty = isFieldEmpty.trim()
if (!isFieldEmpty || isFieldEmpty == "" || isFieldEmpty.length <= 0) {
return true;
}
else {
return false;
}
}

Trouble getting states to work in react native

I'm pretty new to the idea of states in react native and have trouble using them to change the states of the components. I have three text components one which is a question and another two are answers (yes and no), and another text component that checks if my answer to the question is write, so the check text component. When I click on yes for a certain question the state of the last check component should change to 'right' if the answer was yes or to 'wrong' if the answer is no. So basically, this is what I want to do :
This is what I have so far:
This is the error I get :
This is the code I have so far:
import React, { useState, useEffect } from 'react';
import { StyleSheet, Text, View, TouchableOpacity, Alert, ScrollView, Image } from 'react-native';
// import TextComp from './components/Home2'
export default function App() {
const [answer, setAnswer] = useState('answer');
const [correctAns, setCorrectAns] = useState('');
const useEffect = () => {
if (answer == 'answer') {
setCorrectAns('please answer!');
} else if (answer == 'Yes') {
setCorrectAns('Right');
} else if (answer == 'No') {
setCorrectAns('Wrong');
};
};
const corAns = () => { Alert('Your answer was ', correctAns) }
return (
<ScrollView style={styles.container}>
<View style={{ alignItems: 'center' }}>
<Image source={require('./images/pic.jpeg')} style={styles.uriImg} />
<Text style={styles.title}>Is this Mt. Fuji?</Text>
<TouchableOpacity
onPress={() => setAnswer('Yes')}>
<Text style={styles.text}>Yes</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setAnswer('No')}>
<Text style={styles.text}>No</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={corAns}>
<Text style={styles.text2}>Check</Text>
</TouchableOpacity>
<Image source={require('./images/yellow.png')} style={styles.uriImg} />
<Text style={styles.title}>Is this red color?</Text>
<TouchableOpacity
onPress={() => setAnswer('Yes')}>
<Text style={styles.text}>Yes</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => setAnswer('No')}>
<Text style={styles.text}>No</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={corAns}>
<Text style={styles.text2}>Check</Text>
</TouchableOpacity>
</View>
</ScrollView>);
}
Can anyone tell me how it could be done? Thanks!
use useEffect like this
useEffect(() => {
if (answer === 'Yes') {
Alert.alert('Right')
}
if (answer === 'No') {
Alert.alert('Wrong')
}
}, [ answer ])
or by pressing check button
const checkAnswer = () => {
if (answer === 'Yes') {
Alert.alert('Right')
}
if (answer === 'No') {
Alert.alert('Wrong')
}
if (answer === 'answer') {
Alert.alert('please answer')
}
}
set check button onPress={checkAnswer}

How to do conditional rendering in react native

How to do conditional rendering in react native with more than 1 condition?
Following is some portion of my code
Index
.then(response => response.json())
.then((responseData) => {
this.setState({
progressData:responseData,
});
.....
......
render() {
const { progressData }= this.state;
return(
<View style={{flex:1}}>
<HeaderExample />
<View>
{progressData == "1"}
(<View>
<Text style={{fontSize:28,color:"#8470ff",fontWeight: 'bold',paddingTop:20,alignSelf:'center'}}>Pending</Text>
</View>)}
{ progressData == "2" &&
(<View>
<CardSection>
<Text style={{fontSize:28,color:"#8470ff",fontWeight: 'bold',paddingTop:20,alignSelf:'center'}}>InProgress </Text>
<View style={styles.buttonContainer}>
<Button
title="Report"
color="#8470ff"
onPress={() =>onPressReport()}
/>
</View>)}
But here it is for a single case means if responseData contains only one field. But now the reponseData contains 2 arrays. Each with 3 objects. So how do I check conditional rendering here?My responseData looks like this. I want to populate some UI on each condition. That means if status = 1 && work_type ="plumber" then render some UI.
Also if status = 2 && work_type="electrical" && assigend_to="worker_45" then render some ui. So how do I do this?
Please help
You can move your render in a new variable, or function. to keep clear the render function
render() {
const { progressData }= this.state;
return(
<View style={{flex:1}}>
<HeaderExample />
<View>
{renderProgressData(progressData)}
... //rest of your code
)
}
and in your renderProgressData function you can create a switch
renderProgressData = (progress) => {
switch(progress) {
case 1:
return (<View>1</View>)
case 2:
return (<View>1</View>)
// ... and so on
default:
return (<View>Default View</View>)
}
}
It is a little cleaner in this way for me.

React-native- conditionally Disable TouchableHighlight if array is empty

I want to disable TouchableHighlight if my array is empty and turn it back to enable if my array has value.
this.state = {
modalVisible: false,
array:[],
}
}
toggleModal(visible) {
this.setState({modalVisible: visible})
}
<TouchableHighlight
underlayColor="transparent"
onPress = {() => {
if(this.state.array == undefined || this.state.array.length == 0){
this.toggleModal(this.state.modalVisible)}
else {
this.toggleModal(!this.state.modalVisible)}
}}>
<Text>close</Text>
</TouchableHighlight>
Above is my code. I think I have it right but its not working. Any advise or comments would be really appreciated.
You can do this
this.state =
{
modalVisible: false,
array: []
}
toggleModal = visible => this.setState({modalVisible: visible})
render = () =>
{
return (
<TouchableHighlight
underlayColor="transparent"
disabled={this.state.array.length === 0}
onPress = {() =>
{
if(this.state.array == undefined || this.state.array.length == 0)
this.toggleModal(this.state.modalVisible);
else
this.toggleModal(!this.state.modalVisible);
}}>
<Text>close</Text>
</TouchableHighlight>
);
}

Categories

Resources