React-native- conditionally Disable TouchableHighlight if array is empty - javascript

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>
);
}

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;

Get data from multiple custom checkboxes in react native

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());
}
}
};

todos not loading while using AsyncStorage

I am trying to use AsyncStorage to fetch my todos from inside the useEffect hook. If there are no todos(Meaning todos === []) Then a Text Component shows saying "Add a todo".
App image in expo
Initially the todos are set to "[]" inside the useState hook. When the addItem() method is called onPress the todos are not loading.
I do not know why this is happening...
export default function App() {
const [todo, setTodo] = useState('');
const [todos, setTodos] = useState([]);
useEffect(() => {
_retrieveData();
}, [todos]);
const addItem = (newTodo) => {
if (newTodo.length === 0) {
Alert.alert(
'Enter a String',
'You have entered a string with 0 characters',
[{ text: 'Okay', style: 'default' }]
);
} else {
console.log(newTodo);
let newTodos = [newTodo, ...todos];
setTodo('');
_storeData(JSON.stringify(newTodos));
}
};
const deleteTodo = (idx) => {
setTodos(todos.filter((todo, id) => id !== idx));
};
const _storeData = async (value) => {
try {
await AsyncStorage.setItem('TASKS', value);
} catch (error) {
// Error saving data
console.log(e);
}
};
const _retrieveData = async () => {
try {
const value = await AsyncStorage.getItem('TASKS');
if (value !== null) {
// We have data!!
setTodos(JSON.parse(value));
console.log(value);
}
} catch (error) {
// Error retrieving data
console.log(error);
}
};
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.outerContainer}>
<Text style={styles.header}>TODO</Text>
<View style={styles.container}>
<TextInput
placeholder='new todo'
style={styles.input}
value={todo}
onChangeText={(text) => {
setTodo(text);
}}
></TextInput>
<Button title='Add' onPress={() => addItem(todo)}></Button>
</View>
<ScrollView style={styles.scrollView}>
{todos === [] ? (
<View>
<Text>Add a todo!</Text>
</View>
) : (
todos.map((todo, idx) => (
<View style={styles.todo} key={idx}>
<Text style={styles.todoText}>{todo}</Text>
<View style={styles.delete}>
<Button
color='red'
title='Delete'
onPress={() => deleteTodo(idx)}
></Button>
</View>
</View>
))
)}
</ScrollView>
</View>
</TouchableWithoutFeedback>
);
}
Dont use passed todo value newTodo, as setState is async dont get executed immediately, so you can use current setted todo value instead passed old value,
const addItem = (newTodo) => {
if (todo.length === 0) {
Alert.alert(
'Enter a String',
'You have entered a string with 0 characters',
[{ text: 'Okay', style: 'default' }]
);
} else {
console.log(todo);
let newTodos = [todo, ...todos];
setTodo('');
_storeData(JSON.stringify(newTodos));
setTodos(newTodos);
}
};

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;
}
}

React Native, redux function not going to original state after updating

I created a function to view cart details below every screen when a user add a item to cart and when user remove function cart details will hide again, but when I remove item from cart, cart details not hidding, can someone tell me what's wrong, below is my code
reducer
if (action.type === SHOW_CART) {
let addedItem = state.addedItems;
if (addedItem === 0) {
console.log(addedItem);
return {
...state,
show: state.showCart,
};
}
}
const initialstate = {
showChart: false,
addedItems: [],
}
It's my redux code where I'm performing that function, addItems is my cart which is blank array
action
export const showCart = (id) => {
return {
type: SHOW_CART,
showCart: true,
id,
};
};
Here is my action
ViewCart
{this.props.show ? (
<View style={styles.total}>
<Text style={styles.totaltext}>Total:</Text>
<Text style={styles.priceTotal}>{this.props.total}</Text>
<View style={styles.onPress}>
<Text
style={styles.pressText}
onPress={() => RootNavigation.navigate("Cart")}
>
View Cart
</Text>
</View>
</View>
) : null}
Here is my view cart detail where I showing cart details when user add item to cart
can someone please help
You should compare the length, you are currently comparing the array directly so it would also go to the false path, so change that first.
if (action.type === SHOW_CART) {
let addedItem = state.addedItems;
if (addedItem.length === 0) {
console.log(addedItem);
return {
...state,
show: state.showCart,
};
} else {
return {
...state,
show: action.showCart,
};
}
}
In view cart,
{this.props.show && this.props.items.length >0 ? (
<View style={styles.total}>
<Text style={styles.totaltext}>Total:</Text>
<Text style={styles.priceTotal}>{this.props.total}</Text>
<View style={styles.onPress}>
<Text
style={styles.pressText}
onPress={() => RootNavigation.navigate("Cart")}
>
View Cart
</Text>
</View>
</View>
) : null}
const mapStateToProps = (state) => {
return {
total: state.clothes.total,
show: state.clothes.show,
items: state.clothes.addedItems,
};
};

Categories

Resources