React Native Conditional style onFocus onBlur using Reusable Function Component - react-native

I have a reusable text input component using Native Base that I used on many screen, the goal is when text input on focus, the border changes color to #6852E1. When on blur, it changes to #8B8B8B.
The code below doesn't work like I want, or maybe there is something wrong with my code. How can I achieve that? Thanks
Here's the code
import React, { useState } from "react";
import { Dimensions } from "react-native";
import { Item, Input, Label, Icon } from "native-base";
import * as Font from "expo-font";
let borderColor;
// prettier-ignore
Font.loadAsync({
Calibre_Regular: require("../assets/fonts/Calibre-Regular.ttf"),
"Calibre_Regular": require("../assets/fonts/Calibre-Regular.ttf"),
});
const CustomTextInput = ({
value,
onChangeText,
label,
onSubmitEditing,
getRef,
onPress,
onPress2,
returnKeyType,
keyboardType,
editable,
secureTextEntry,
iconName,
iconName2,
whichStyle,
defaultValue,
}) => {
const { itemStyle1, itemStyle2, textInput, floatingLabel } = InputFieldStyles;
return (
<Item
floatingLabel
style={whichStyle ? itemStyle2 : itemStyle1}
onPress={onPress2}
>
<Icon style={{ marginLeft: 10, color: "#8B8B8B" }} name={iconName2} />
<Label style={floatingLabel}>{label}</Label>
<Input
onBlur={() => (borderColor = "#8B8B8B")}
onFocus={() => (borderColor = "#6852E1")}
style={textInput}
blurOnSubmit={false}
getRef={getRef}
value={value}
defaultValue={defaultValue}
editable={editable}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
returnKeyType={returnKeyType}
keyboardType={keyboardType}
secureTextEntry={secureTextEntry}
/>
<Icon name={iconName} onPress={onPress} />
</Item>
);
};
const InputFieldStyles = {
textInput: {
padding: 10,
marginVertical: 10,
fontSize: 16,
color: "rgba(0, 0, 0, 0.87)",
fontFamily: "Calibre_Regular",
},
floatingLabel: {
marginLeft: 10,
marginTop: 8,
fontFamily: "Calibre_Regular",
},
itemStyle1: {
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: borderColor,
// borderColor: "#6852E1",
// borderColor: "#8B8B8B",
borderBottomWidth: 3,
},
itemStyle2: {
marginLeft: 0,
backgroundColor: "#F6F7FC",
borderColor: borderColor,
borderBottomWidth: 3,
},
itemStyle3: {
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: "#6852E1",
borderBottomWidth: 3,
},
};
export { CustomTextInput };
this is my code with the right answer for those who needs
import React, { useState } from "react";
import { Dimensions } from "react-native";
import { Item, Input, Label, Icon } from "native-base";
import * as Font from "expo-font";
// prettier-ignore
Font.loadAsync({
Calibre_Regular: require("../assets/fonts/Calibre-Regular.ttf"),
"Calibre_Regular": require("../assets/fonts/Calibre-Regular.ttf"),
});
const CustomTextInput = ({
value,
onChangeText,
label,
onSubmitEditing,
getRef,
onPress,
onPress2,
returnKeyType,
keyboardType,
editable,
secureTextEntry,
iconName,
iconName2,
whichStyle,
defaultValue,
}) => {
const { itemStyle1, itemStyle2, textInput, floatingLabel } = InputFieldStyles;
const [isFocused, setIsFocused] = useState(false);
return (
<Item
floatingLabel
style={whichStyle ? itemStyle2 : itemStyle1({ isFocused })}
onPress={onPress2}
>
<Icon style={{ marginLeft: 10, color: "#8B8B8B" }} name={iconName2} />
<Label style={floatingLabel}>{label}</Label>
<Input
onBlur={() => setIsFocused(false)}
onFocus={() => setIsFocused(true)}
style={textInput}
blurOnSubmit={false}
getRef={getRef}
value={value}
defaultValue={defaultValue}
editable={editable}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
returnKeyType={returnKeyType}
keyboardType={keyboardType}
secureTextEntry={secureTextEntry}
/>
<Icon name={iconName} onPress={onPress} />
</Item>
);
};
const InputFieldStyles = {
textInput: {
padding: 10,
marginVertical: 10,
fontSize: 16,
color: "rgba(0, 0, 0, 0.87)",
fontFamily: "Calibre_Regular",
},
floatingLabel: {
marginLeft: 10,
marginTop: 8,
fontFamily: "Calibre_Regular",
},
itemStyle1: ({ isFocused }) => ({
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: isFocused ? "#6852E1" : "#8B8B8B",
borderBottomWidth: 3,
}),
itemStyle2: {
marginLeft: 0,
backgroundColor: "#F6F7FC",
borderBottomWidth: 3,
},
itemStyle3: {
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: "#6852E1",
borderBottomWidth: 3,
},
};
export { CustomTextInput };

Try this:
const CustomTextInput = () => {
const [isFocused, setIsFocused] = setState(false);
return (
/** ... */
<Item style={itemStyle({ isFocused })}>
>
<Input
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
</Item>
/** ... */
);
};
itemStyle: ({ isFocused }) => ({
borderColor: isFocused ? 'focused-color' : 'unfocused-color'
}),

Related

Unable to access state variable declared inside useEffect

I have a react native screen where I am calling an API on useEffect and setting two state variables using hooks, i.e. cityList, filteredCityList. filteredCityList is bind to autocomplete dropdown. On change of this dropdown, a function called filterCity gets called. I am unable to access the cityList inside this function.
Please advise what am I missing here.
import React, {useCallback, useEffect, useState} from 'react';
import {View, StyleSheet} from 'react-native';
import {Button, Card, Portal, Text, Modal, FAB} from 'react-native-paper';
import {AutocompleteDropdown} from 'react-native-autocomplete-dropdown';
import Icon from 'react-native-vector-icons/Feather';
import {getCities} from '../API/api';
import {useFocusEffect} from '#react-navigation/native';
const AddHospital = () => {
const [selectedCity, setSelectedCity] = useState(null);
const [cityListFiltered, setCityListFiltered] = useState([]);
const [cityList, setCityList] = useState([]);
const [cityDDLoading, setCityDDLoading] = useState(false);
const [selectedCityError, setSelectedCityError] = useState(false);
console.log('reloading');
const filterCity = q => {
console.log(q);
console.log('City List', cityList);
};
const loadCities = async () => {
setCityDDLoading(true);
var citiesResponse = await getCities();
if (citiesResponse.responseData) {
var cities = citiesResponse.responseData.records.map(item => ({
id: item.id,
title: item.cityname,
}));
console.log('setting cities', cities);
setCityList(cities);
// setCityListFiltered(cities);
// setCityDDLoading(false);
} else {
console.log('Failed to load cities');
}
};
useEffect(() => {
loadCities();
}, []);
return (
<View>
<Card style={styles.container}>
<Card.Title title="Select Hospital"></Card.Title>
<Card.Content>
<AutocompleteDropdown
clearOnFocus={false}
closeOnBlur={true}
closeOnSubmit={false}
onSelectItem={item => {
item && setSelectedCity(item);
}}
dataSet={cityListFiltered}
debounce={600}
onChangeText={text => filterCity(text)}
suggestionsListMaxHeight={120}
loading={cityDDLoading}
useFilter={false} // prevent rerender twice
textInputProps={{
placeholder: 'Select City',
autoCorrect: false,
autoCapitalize: 'none',
style: {
// borderRadius: 25,
backgroundColor: '#f6f6f6',
color: 'black',
paddingLeft: 18,
borderWidth: 1,
borderColor: selectedCityError ? 'red' : 'gray',
borderStyle: 'solid',
},
placeholderTextColor: 'black',
}}
rightButtonsContainerStyle={{
// borderRadius: 25,
right: 8,
height: 30,
top: 10,
alignSelfs: 'center',
backgroundColor: '#f6f6f6',
// backgroundColor: "#383b42"
}}
inputContainerStyle={{
backgroundColor: 'transparent',
zIndex: 0,
}}
suggestionsListContainerStyle={
{
//backgroundColor: "#383b42"
//color: '#fff'
// zIndex: 1000
}
}
containerStyle={{
flexGrow: 1,
flexShrink: 1,
marginBottom: 100,
marginTop: 10,
zIndex: 0,
}}
renderItem={(item, text) => (
<Text style={{color: 'black', padding: 15}}>{item.title}</Text>
)}
ChevronIconComponent={<Icon name="chevron-down" size={24} />}
ClearIconComponent={<Icon name="x" size={18} />}
inputHeight={50}
showChevron={true}
showClear={true}
// style={styles.autoComplete}
/>
</Card.Content>
</Card>
<Text>{cityList.length}</Text>
</View>
);
};
export default AddHospital;
const styles = StyleSheet.create({
container: {
flex: 0,
margin: 10,
},
});

how to search item in listed element react native

I am stuck with a problem, when am trying to search elements from listed data it's not working, I seem lots of document ad I applied it, but still, its work for me, can anyone help me.
if you have any questions please free feel to ask any time.
home.js
This is Home.js file where I wrote my all code. and here I use some React native paper components.
import React, { useEffect, useState } from 'react'
import { Text, View, FlatList, StyleSheet, ScrollView, TouchableOpacity } from 'react-native';
import { Avatar } from 'react-native-elements';
import { Searchbar, Provider, Portal, TextInput, Button } from 'react-native-paper';
import { AntDesign, Entypo } from '#expo/vector-icons';
import Modal from "react-native-modal";
export default function Home() {
const [searchquery, setSearchquery] = React.useState();
const [isModalVisible, setModalVisible] = useState(false);
const [name, setName] = React.useState('');
const [number, setNumber] = React.useState('');
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
const filterItem = (text) => {
users.filter((item) => {
return item.name.toLowerCase().inludes(text.toLowerCase())
})
setSearchquery(text)
}
const [users, setUser] = useState([
{
id: 1,
name: "Ashish Nirvikar",
number: 3289768909,
},
{
id: 2,
name: "Drew Macntyre",
number: 3345661276
},
{
id: 3,
name: "Jonh Cena",
number: 9087392878
},
{
id: 4,
name: "Rock Samoa",
number: 9723780928
},
{
id: 5,
name: "Boby Lashely",
number: 8769213678
},
{
id: 6,
name: "Seth Rollins",
number: 6890326741
},
])
return (
<View >
<Searchbar
placeholder="Search Contacts"
onChangeText={(text) => setSearchquery(text)}
value={searchquery}
style={{ marginTop: 30, marginHorizontal: 10 }}
/>
<ScrollView>
{
filterItem(users).map((item, index) => {
return (
<View key={index} style={styles.names}>
<Text style={{ color: 'black', fontSize: 20, fontWeight: 'bold' }}>Name : {item.name}</Text>
<Text style={{ color: 'black' }}>Mobile no : {item.number}</Text>
</View>
)
})
}
</ScrollView>
<Modal isVisible={isModalVisible} style={{ backgroundColor: 'white', height: 50, marginBottom: 200, marginTop: 100 }}>
<View style={{ flex: 2 }}>
<Text style={{ color: 'black', fontSize: 50, textAlign: 'center' }}>Add Contact</Text>
<TextInput
style={styles.input}
label="Enter Full name"
value={name}
onChangeText={text => setName(text)}
/>
<TextInput
style={styles.input1}
label="Enter Mobile Number"
value={number}
onChangeText={text => setNumber(text)}
/>
<Button title="Hide modal" onPress={toggleModal} style={{ color: 'black', backgroundColor: 'white', borderWidth: 1, borderColor: 'gray', marginHorizontal: 10, marginTop: 15 }}>Cancle</Button>
</View>
</Modal>
<AntDesign name="plus" size={34} color="black" style={styles.plus} onPress={toggleModal} />
</View>
);
}
const styles = StyleSheet.create({
customText: {
padding: 10,
marginTop: 20,
textAlign: 'center',
backgroundColor: 'lightgray',
fontWeight: 'bold',
fontSize: 20
},
plus: {
fontSize: 50,
position: 'absolute',
top: 680,
right: 40,
backgroundColor: 'pink',
borderRadius: 15,
borderWidth: 0.5,
padding: 5,
},
names: {
padding: 15,
fontSize: 25,
fontWeight: 'bold',
backgroundColor: 'lightgray',
marginTop: 10,
borderRadius: 20,
color: 'black'
},
addcontactname: {
fontSize: 30,
textAlign: 'center',
marginTop: 10,
marginBottom: 30
},
input: {
marginHorizontal: 10,
marginBottom: 20,
marginTop: 20
},
input1: {
marginHorizontal: 10,
marginBottom: 10,
}
});
Your Searchbar should be a controlled input (call setSearchquery with the change value from the Searchbar).
Then you can use the value of searchquery to perform the filtering inline in your jsx.
Finally, use FlatList to render a list of items instead of a map inside a ScrollView.
In your example, there's no need for the list of users to be stored in state.
import React, { Component } from 'react';
import { Text, View, StyleSheet, ScrollView, FlatList } from 'react-native';
import { Searchbar } from 'react-native-paper';
const data = [...];
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
searchquery: '',
};
}
renderHeader = () => {
return (
<Searchbar
placeholder="Search Contacts"
onChangeText={(searchquery) =>
this.setState({
searchquery,
})
}
value={this.state.searchquery}
/>
);
};
renderItem = ({ item, index }) => {
return (
<View key={index} style={styles.names}>
<Text>
Name : {item.name}
</Text>
<Text>Mobile no : {item.number}</Text>
</View>
);
};
render() {
return (
<FlatList
data={data.filter((item) => {
if (!this.state.searchquery) return true
return item.name
.toUpperCase()
.includes(this.state.searchquery.toUpperCase());
})}
ListHeaderComponent={this.renderHeader}
renderItem={this.renderItem}
/>
);
}
}
Snack
you can try with this code if it will not work then call filterItem function with bracket and parameter also my code is working while the name is lowercase.
<Searchbar
placeholder="Search Contacts"
onChangeText={filterItem}
onClear={(users) => setUser('')}
value={searchquery}
style={{ marginTop: 30, marginHorizontal: 10 }}
/>
const filterItem = (text) => {
setSearchquery(text)
let searchText = text.toLowerCase()
let filterData = users
filterData = filterData.filter(function (id) {
return id.name.toLowerCase().includes(searchText)
})
setUser(filterData);
if (text === "") {
setUser(
[
{
id: 1,
name: "Ashish Nirvikar",
number: 3289768909,
},
{
id: 2,
name: "Drew Macntyre",
number: 3345661276
},
{
id: 3,
name: "Jonh Cena",
number: 9087392878
},
{
id: 4,
name: "Rock Samoa",
number: 9723780928
},
{
id: 5,
name: "Boby Lashely",
number: 8769213678
},
{
id: 6,
name: "Seth Rollins",
number: 6890326741
},
]
);
}
}
Try this
const filterItem = (searchItems) => {
searchItems.filter((item) => {
return item.name.toLowerCase().inludes(searchquery.toLowerCase())
})
}
<Searchbar
placeholder="Search Contacts"
onChangeText={(text) => setSearchquery(text)}
onClear={(text) => searchquery("")}
value={searchquery}
style={{ marginTop: 30, marginHorizontal: 10 }}
/>
<ScrollView>
{
filterItem(users).map((item, index) => {
return (
<View key={index} style={styles.names}>
<Text style={{ color: 'black', fontSize: 20, fontWeight: 'bold' }}>Name : {item.name}</Text>
<Text style={{ color: 'black' }}>Mobile no : {item.number}</Text>
</View>
)
})
}
</ScrollView>

How to get the value from Async Storage getData function?

I want to store username to local storage using #react-native-async-storage/async-storage in React Native. When I checked through console.log, username was saved successfully but while retrieving the data back to different screen using getData function, It says null. Help me to figure out the issue.
this is my storage.js file where I've kept all the Async Storage functions.
import AsyncStorage from '#react-native-async-storage/async-storage';
const storeData = async (key, value) => {
try {
await AsyncStorage.setItem(key, value)
} catch (e) {
console.log('Error on saving')
}
}
const getData = async (key) => {
try {
const value = await AsyncStorage.getItem(key)
if (value !== null) {
console.log('Promise', value)
return value
}
} catch (e) {
// error reading value
}
}
export { storeData, getData };
this is my Log In Screen file
import React, { Component, useState } from 'react';
import { View, Text, Button, ScrollView, TextInput, TouchableHighlight, StyleSheet } from 'react-native';
import * as yup from 'yup'
import { Formik } from 'formik'
import { storeData } from '../utils/storage';
const Login = (props) => {
const handleLogin = (name) => {
storeData('username',name)
props.navigation.navigate('Home')
}
return (
<Formik
initialValues={{
name: '',
password: ''
}}
onSubmit={values => Alert.alert(JSON.stringify(values))}
validationSchema={yup.object().shape({
name: yup
.string()
.required('Please, provide your name!'),
password: yup
.string()
.min(4)
.max(10, 'Password should not excced 10 chars.')
.required(),
})}
>
{({ values, handleChange, errors, setFieldTouched, touched, isValid, handleSubmit }) => (
<ScrollView style={styles.scrollb}>
<View style={styles.container}>
<Text style={styles.title}>LOGIN PAGE</Text>
<Text style={styles.subtitle}>Welcome Back.</Text>
</View>
<View style={styles.container2}>
<TextInput
style={styles.tinput}
placeholder="Username"
value={values.name}
onChangeText={handleChange('name')}
onBlur={() => setFieldTouched('name')}
/>
{touched.name && errors.name &&
<Text style={{ fontSize: 12, color: '#FF0D10' }}>{errors.name}</Text>
}
</View>
<View style={styles.container2}>
<TextInput
style={styles.tinput}
placeholder="Password"
value={values.password}
onChangeText={handleChange('password')}
placeholder="Password"
onBlur={() => setFieldTouched('password')}
secureTextEntry={true}
/>
{touched.password && errors.password &&
<Text style={{ fontSize: 12, color: '#FF0D10' }}>{errors.password}</Text>
}
</View>
<View style={styles.container3}>
<TouchableHighlight
style={{
borderRadius: 10,
}}>
<Button
title="Login"
borderRadius={25}
containerViewStyle={{ borderRadius: 25 }}
buttonStyle={{ width: 145, height: 45, borderRadius: 25 }}
accessibilityLabel="Learn more about this button"
onPress={() => handleLogin(values.name)}
disabled={!isValid}
/>
</TouchableHighlight>
</View>
</ScrollView>
)}
</Formik>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 24,
backgroundColor: "#61dafb",
},
container2: {
flex: 1,
paddingTop: 14,
paddingHorizontal: 24,
backgroundColor: "#61dafb",
},
container3: {
flex: 1,
paddingTop: 284,
paddingHorizontal: 34,
backgroundColor: "#61dafb",
borderRadius: 40,
},
title: {
marginTop: 16,
borderRadius: 6,
backgroundColor: "#61dafb",
color: "white",
textAlign: "center",
fontSize: 50,
fontWeight: "bold",
},
subtitle: {
borderRadius: 6,
paddingLeft: 33,
backgroundColor: "#61dafb",
color: "white",
textAlign: "left",
fontSize: 30,
fontWeight: '400',
},
tinput: {
height: 50,
textAlign: "center",
paddingVertical: 8,
backgroundColor: "white",
borderRadius: 27,
},
scrollb: {
backgroundColor: "#61dafb",
},
});
export default Login;
This is my Home screen file. Where I want to retrieve that username from Login Page via async storage.
import React, { Component, useEffect, useState } from 'react';
import { View, Text, ScrollView, TouchableHighlight, Image, StyleSheet } from 'react-native';
import { getData } from '../utils/storage';
const Home = (props) => {
const [username, setUsername] = useState('');
useEffect(() => {
getData('username')
console.log('useEffect',getData('username'))
}, [])
const CategoriesAr = [
{
name: "Business",
path: "Business",
imgURL: "https://img.icons8.com/clouds/100/000000/analytics.png",
},
{
name: "Technology",
path: "Technology",
imgURL: "https://img.icons8.com/clouds/100/000000/transaction-list.png",
},
{
name: "Science",
path: "Science",
imgURL: "https://img.icons8.com/clouds/100/000000/innovation.png",
},
{
name: "Health",
path: "Health",
imgURL: "https://img.icons8.com/clouds/100/000000/client-company.png",
}
]
const GridItem = (gridProps) => {
const { data } = gridProps;
return (
<>
<TouchableHighlight onPress={() => props.navigation.navigate(data.path)}>
<View style={styles.card}>
<View style={styles.header}>
<Text style={{ fontWeight: "bold", fontSize: 18 }}>{data.name}</Text>
</View>
<View style={styles.imgbody}>
<Image
style={styles.tinyLogo}
source={{
uri: data.imgURL,
}}
/>
</View>
</View>
</TouchableHighlight>
</>
)
}
return (
<ScrollView style={styles.sclb}>
<Text style={styles.title}>Hi {username}</Text>
<View style={styles.containerX}>
{CategoriesAr.map((item) => <GridItem data={item} />)}
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
title: {
marginTop: 16,
borderRadius: 6,
backgroundColor: "#61dafb",
color: "white",
textAlign: "center",
fontSize: 50,
fontWeight: "bold",
},
containerX: {
flex: 1,
flexWrap: "wrap",
marginTop: 8,
maxHeight: 400,
backgroundColor: "#61dafb",
},
card: {
height: 150,
width: 150,
backgroundColor: "white",
alignItems: "center",
borderRadius: 15,
elevation: 10,
padding: 10,
margin: 22,
},
imgbody: {
paddingTop: 20,
},
tinyLogo: {
height: 90,
width: 90,
},
header: {
flexDirection: "row",
},
sclb: {
backgroundColor: "#61dafb",
}
});
export default Home;
You need to put await before getData like this.
useEffect(() => {
(async()=>{
await getData('username')
console.log('useEffect',await getData('username'))
})();
}, [])
useEffect(() => {
CallMethod()
}, [])
const CallMethod = async() =>{
await getData('username')
}

how to get current flat list item data in reactnative using react-native-swipe-list-view

I'm not getting how to get the current item object of a flat list
I used react-native-swipeout and react-native-swipe-list-view and in both examples I stuck.
And on google I found very big answers. Which are not pointing only the particular issue which confused me a lot.
the below is the deleted function when I used react-native-swipeout plugin
const swipeSettings = {
left: [
{
text: 'Delete',
onPress: () => {
console.log('-----delete-----');
},
type: 'delete',
},
}
All I need is to get the current item object data like below inside onpress() when i tapped the delete button .
{
id: 1,
prodName : "abcdefg",
}
That's all, I came from native script background and in that framework I never faced such issue. Because the documentation was crystal clear. But here In react native everything seems to be complicated for me.
Kindly any one help me.
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({item, index}) => (
<Swipeout {...swipeSettings}>
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
)}
/>
entire page
import React, {useState} from 'react';
import {View} from 'react-native-animatable';
import {
TextInput,
TouchableOpacity,
FlatList,
} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/FontAwesome';
import {StyleSheet, Pressable, Text, Button} from 'react-native';
import * as Animatable from 'react-native-animatable';
import Swipeout from 'react-native-swipeout';
import ButtonPressable from '../../components/ButtonPressable';
var sqlite_wrapper = require('./sqliteWrapper');
const DATA = [
{
prodName: 'Added data will look like this',
},
];
const swipeSettings = {
style: {
marginBottom: 10,
},
autoClose: false,
backgroundColor: 'transparent',
close: false,
disabled: false,
onClose: (sectionID, rowId, direction) => {
console.log('---onclose--');
},
onOpen: (sectionID, rowId, direction) => {
console.log('---onopen--');
},
right: [
{
backgroundColor: 'dodgerblue',
color: 'white',
text: 'Edit',
onPress: () => {
console.log('-----edit-----');
},
},
],
left: [
{
backgroundColor: 'red',
color: 'white',
text: 'Delete',
onPress: () => {
console.log('-----delete-----');
sqlite_wrapper.deleteById
},
type: 'delete',
// component : (<ButtonPressable text="delete" />)
},
],
// buttonWidth: 100,
};
const AddProductList = ({route, navigation}) => {
const {navData} = route.params;
const [prodName, setProdName] = useState('');
var [data, setData] = useState(DATA);
return (
<View style={styles.container}>
<Animatable.View
animation="bounceIn"
duration={1000}
style={styles.inputFieldView}>
<TextInput
style={styles.textInput}
onChangeText={(value) => setProdName(value)}
placeholder="Add the Product"
defaultValue={prodName}
/>
<TouchableOpacity
style={styles.addView}
onPress={() => {
sqlite_wrapper
.insert({prodName: prodName}, sqlite_wrapper.collection_product)
.then((result) => {
console.log('---result---');
console.log(result);
if (result.rowsAffected) {
fetchAllData();
}
});
function fetchAllData() {
sqlite_wrapper
.readAll(sqlite_wrapper.collection_product)
.then((resultData) => {
console.log('---resultData---');
console.log(resultData);
setData(resultData);
setProdName('');
});
}
// without sql this is how to update the state having a array
// const updatedArray = [...data];
// updatedArray.push({prodName: prodName});
// setData(updatedArray);
// setProdName('');
}}>
<Icon name="plus" size={16} style={styles.add} color="white" />
</TouchableOpacity>
</Animatable.View>
<Animatable.View
animation="bounceInLeft"
duration={1500}
style={{flex: 1}}>
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({item, index}) => (
<Swipeout {...swipeSettings}>
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
)}
/>
</Animatable.View>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
},
inputFieldView: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'stretch',
margin: 10,
},
textInput: {
flex: 1,
backgroundColor: '#b2ebf2',
borderTopLeftRadius: 7,
borderBottomLeftRadius: 7,
fontSize: 16,
},
addView: {
backgroundColor: '#0f4c75',
alignSelf: 'stretch',
alignItems: 'center',
justifyContent: 'center',
borderTopEndRadius: 7,
borderBottomEndRadius: 7,
padding: 9,
},
add: {
padding: 7,
},
listView: {
padding: 20,
backgroundColor: 'green',
margin: 0,
borderRadius: 0,
},
listViewText: {
color: 'white',
},
});
export default AddProductList;
So if I get you right you have one generic swipe setting that you want to adjust to each element in the list.
Try changing the renderItem of the Flatlist like this and let me know how it worked for you:
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={({ item, index }) => {
let right = [...swipeSettings.right]; <---- ADDED
let left = [...swipeSettings.left]; <---- ADDED
right[0].onPress = () => console.log('edit', item.prodName); <---- ADDED
left[0].onPress = () => console.log('delete', item.prodName); <---- ADDED
<Swipeout {...swipeSettings} {...{ right, left}} > <---- CHANGED
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
}}
/>
So what I have done here is sending the generic swipe settings to each instance of Swipeout but changed their "Left" and "Right" in order to overwrite their "onPress" function and adjust it to the rendered item.
I know it is hard to understand it like this and it's probably not the best explanation but I hope it will help you somehow.
EDIT
import React, { useState } from 'react';
import { View } from 'react-native-animatable';
import {
TextInput,
TouchableOpacity,
FlatList,
} from 'react-native-gesture-handler';
import Icon from 'react-native-vector-icons/FontAwesome';
import { StyleSheet, Pressable, Text, Button } from 'react-native';
import * as Animatable from 'react-native-animatable';
import Swipeout from 'react-native-swipeout';
import ButtonPressable from '../../components/ButtonPressable';
var sqlite_wrapper = require('./sqliteWrapper');
const DATA = [
{
prodName: 'Added data will look like this',
},
];
const AddProductList = ({ route, navigation }) => {
const { navData } = route.params;
const [prodName, setProdName] = useState('');
var [data, setData] = useState(DATA);
const renderItem = ({ item, index }) => {
const swipeSettings = {
style: {
marginBottom: 10,
},
autoClose: false,
backgroundColor: 'transparent',
close: false,
disabled: false,
onClose: (sectionID, rowId, direction) => {
console.log('---onclose--');
},
onOpen: (sectionID, rowId, direction) => {
console.log('---onopen--');
},
right: [
{
backgroundColor: 'dodgerblue',
color: 'white',
text: 'Edit',
onPress: () => console.log('-----edit-----', item.prodName)
},
],
left: [
{
backgroundColor: 'red',
color: 'white',
text: 'Delete',
onPress: () => {
console.log('-----delete-----', item.prodName);
sqlite_wrapper.deleteById
},
type: 'delete',
// component : (<ButtonPressable text="delete" />)
},
],
// buttonWidth: 100,
};
return (
<Swipeout {...swipeSettings}>
<View style={styles.listView}>
<Text style={styles.listViewText}>{item.prodName}</Text>
</View>
</Swipeout>
)
}
return (
<View style={styles.container}>
<Animatable.View
animation="bounceIn"
duration={1000}
style={styles.inputFieldView}>
<TextInput
style={styles.textInput}
onChangeText={(value) => setProdName(value)}
placeholder="Add the Product"
defaultValue={prodName}
/>
<TouchableOpacity
style={styles.addView}
onPress={() => {
sqlite_wrapper
.insert({ prodName: prodName }, sqlite_wrapper.collection_product)
.then((result) => {
console.log('---result---');
console.log(result);
if (result.rowsAffected) {
fetchAllData();
}
});
function fetchAllData() {
sqlite_wrapper
.readAll(sqlite_wrapper.collection_product)
.then((resultData) => {
console.log('---resultData---');
console.log(resultData);
setData(resultData);
setProdName('');
});
}
// without sql this is how to update the state having a array
// const updatedArray = [...data];
// updatedArray.push({prodName: prodName});
// setData(updatedArray);
// setProdName('');
}}>
<Icon name="plus" size={16} style={styles.add} color="white" />
</TouchableOpacity>
</Animatable.View>
<Animatable.View
animation="bounceInLeft"
duration={1500}
style={{ flex: 1 }}>
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={renderItem}
/>
</Animatable.View>
</View>
);
};
var styles = StyleSheet.create({
container: {
flex: 1,
},
inputFieldView: {
flexDirection: 'row',
alignItems: 'center',
alignSelf: 'stretch',
margin: 10,
},
textInput: {
flex: 1,
backgroundColor: '#b2ebf2',
borderTopLeftRadius: 7,
borderBottomLeftRadius: 7,
fontSize: 16,
},
addView: {
backgroundColor: '#0f4c75',
alignSelf: 'stretch',
alignItems: 'center',
justifyContent: 'center',
borderTopEndRadius: 7,
borderBottomEndRadius: 7,
padding: 9,
},
add: {
padding: 7,
},
listView: {
padding: 20,
backgroundColor: 'green',
margin: 0,
borderRadius: 0,
},
listViewText: {
color: 'white',
},
});
export default AddProductList;

How to focus one textinput per time in react-native?

I have 3 different textinput, textinput1, textinput2 and textinput 3.
I want that when i click on textinput1 that his bordercolor be blue, i did that and works.
What i want now is, when i click on textinput2 to textinput1 be back to his orignal color and the textinput2 be blue now.
Example on the photo.
Example
This is my code:
state = { isFocused: true };
onFocusChange = () => {
this.setState({ isFocused: false });
}
render() {
return (
<View style={styles.container}>
<Text style={styles.headline}>Website ou App</Text>
//TEXTINPUT1
<TextInput
onFocus={this.onFocusChange}
style={(this.state.isFocused) ? {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: 'gray'} : {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: '#00b7eb'}}
onChangeText={(text) => this.setState({ site: text })}
value={this.state.site}
//TEXTINPUT2
<Text style={styles.headline}>Utilizador/Email</Text>
<TextInput
style={{ marginTop: 5, height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={(text) => this.setState({ local: text })}
value={this.state.local}
/>
Some idea how i can do that? Thank you.
Sharing my same answer from here.
Set up your text inputs and their styles in a component. Then use state in the component to control your styles.
const [focus, setFocus] = useState(false);
<TextInput
style={focus ? styles.inputOnFocus : styles.inputOnBlur}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
/>
Styles:
const styles = StyleSheet.create({
inputOnFocus: { borderColor: '#C0C0C0' },
inputOnBlur: { borderColor: '#4b6cd5' }
});
One option is to track the name of the focused TextInput. You'll need to make sure to use the updater version of setState in the blur event to avoid race conditions between the onBlur and onFocus methods of the two inputs:
state = { focusedInput: null };
onFocusChange = (inputName) => {
this.setState({focusedInput: inputName});
}
onBlurChange = (inputName) => {
this.setState(state => {
if (state.focusedInput === inputName) {
return {focusedInput: null};
}
// no change if some other input already has focus
return null;
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.headline}>Website ou App</Text>
//TEXTINPUT1
<TextInput
onFocus={() => this.onFocusChange("input1")}
onBlur={() => this.onBlurChange("input1")}
style={(this.state.focusedInput === "input1") ? {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: 'gray'} : {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: '#00b7eb'}}
onChangeText={(text) => this.setState({ site: text })}
value={this.state.site} />
Repeat for other inputs with a name different than "input1".
I think the easiest way to do it is just to create your own custom component to handle the border line. I have created a expo snack for you to see a workaround (other than the mentioned before). https://snack.expo.io/#ianvasco/e8efb0.
Anyway here is the code.
//somefile.js
import React, {useState} from 'react';
import { Text, View, StyleSheet, TextInput } from 'react-native';
import Constants from 'expo-constants';
export default App = () => {
const [isInputFocused, setInputFocused] = useState({input1: false, input2: false})
return (
<View style={styles.container}>
<TextInput
onFocus={() => setInputFocused((prev) => ({...prev, input1: true}))}
onBlur={() => setInputFocused((prev) => ({...prev, input1: false}))}
style={isInputFocused.input1 ? styles.input : styles.inputFocused }
onChangeText={() => {}}/>
<TextInput
style={isInputFocused.input2 ? styles.input : styles.inputFocused }
onChangeText={() => {}}
onFocus={() => setInputFocused((prev) => ({...prev, input2: true}))}
onBlur={() => setInputFocused((prev) => ({...prev, input2: false}))}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
inputFocused: {
marginTop: 5,
height: 40,
borderWidth: 2,
borderRadius: 5,
borderColor: 'grey'
},
input: {
marginTop: 5,
height: 40,
borderWidth: 2,
borderRadius: 5,
borderColor: '#00b7eb'
}
});
Also, I just added React Hooks. I encourage you to use them, since the code get simplified a lot. Here is more about Hooks
Create Custom TextInput component which will set "borderColor" to "black" or "blue" in component with help of "onFocus" and "onBlur" events. In this way you can use multiple TextInputs without any conditions in parent
Sample Code
import React from "react";
import { SafeAreaView, TextInput, Text } from "react-native";
class CustomTextInput extends React.Component {
state = { hasFocus: false };
_onFocus = () => {
this.setState({ hasFocus: true });
};
_onBlur = () => {
this.setState({ hasFocus: false });
};
render() {
const borderColor = this.state.hasFocus ? "blue" : "black";
return (
<TextInput
style={{ padding: 16, borderColor: borderColor, borderWidth: 1 }}
onFocus={this._onFocus}
onBlur={this._onBlur}
/>
);
}
}
export default class App extends React.Component {
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Text style={{ marginTop: 16, textAlign: "center" }}>Website App</Text>
<CustomTextInput />
<Text style={{ marginTop: 16, textAlign: "center" }}>Email</Text>
<CustomTextInput />
<Text style={{ marginTop: 16, textAlign: "center" }}>Password</Text>
<CustomTextInput />
</SafeAreaView>
);
}
}
App Preview
**We can control the multiple text input by using Switch case and method **
_onFocusTo=(data)=>{
const {
overdueAmount,
bounceCharges,
penalInterest,
overdueCharges,
collectionPickupCharge,
ebcCharges,
foreClosureAmount,
amount,
} = this.state;
console.log("focus");
switch(data) {
case 1:{
if(amount === "0"){
this.setState({amount:""})
}
}break;
case 2:{
if(bounceCharges === "0"){
this.setState({bounceCharges:""})
}
}break;
case 3:{
if(penalInterest === "0"){
this.setState({penalInterest:""})
}
}break;
case 4:{
if(foreClosureAmount === "0"){
this.setState({foreClosureAmount:""})
}
}break;
case 5:{
if(ebcCharges === "0"){
this.setState({ebcCharges:""})
}
}break;
case 6:{
if(collectionPickupCharge === "0"){
this.setState({collectionPickupCharge:""})
}
}break;
}
}
/In Textinput make function and pass it to onFocus
<TextInput
underlineColorAndroid="transparent"
style={styles.textInput1}
placeholder={""}
placeholderTextColor={Colors.labelTextColor1}
keyboardType={"numeric"}
onFocus={() => this._onFocusTo(1)}
onBlur={this.addTotal}
onChangeText={(amount) => this.setAmountDes(amount)}
value={this.state.amount}
/>
<TextInput
underlineColorAndroid="transparent"
style={styles.textInput1}
placeholder={""}
placeholderTextColor={Colors.labelTextColor1}
onFocus={() => this._onFocusTo(2)}
onBlur={this.addTotal}
keyboardType={"numeric"}
onChangeText={(bounce) => this.setBounce(bounce)}
value={this.state.bounceCharges}
/>
<TextInput
underlineColorAndroid="transparent"
style={styles.textInput1}
placeholder={this.state.penalInterest}
placeholderTextColor={Colors.labelTextColor1}
onFocus={() => this._onFocusTo(3)}
onBlur={this.addTotal}
keyboardType={"numeric"}
onChangeText={(penal) => this.setPenal(penal)}
value={this.state.penalInterest}
/>
....continues