I am trying to get user input, create an array of objects from userInput and save that array of objects into an array. Below is code I have written, but no output.
import React, { Component } from 'react';
import {Text, View, StyleSheet, TextInput, Image, TouchableOpacity, ListView} from 'react-native';
//import {Actions} from 'react-native-router-flux';
const count = 0;
export default class SecondPage extends Component {
constructor(props) {
super(props);
this.state = {
quan:'',
desc:'',
amt:'',
dataStorage :[],
data: { quantity: this.quan, description: this.desc, amount: this.amt },
}
}
_add(){
console.log('Add button pressed');
this.state.dataStorage[count].push(this.state.data);
console.log(this.state.data);
count++;
}
render(){
return(
<View style={styles.container}>
<View style={styles.itemDescription}>
<Text style={styles.itemDescriptionText}>QUANTITY</Text>
<Text style={styles.itemDescriptionText}>DESCRIPTION</Text>
<Text style={styles.itemDescriptionText}>AMOUNT</Text>
<TouchableOpacity style={styles.addButton} onPress={this._add}>
<Text style={styles.addButtonText}>ADD</Text>
</TouchableOpacity>
</View>
<View style={styles.rowsOfInput}>
<TextInput style = {styles.nameInput}
onChangeText={(text) => this.setState({quan: text})}
value = {this.state.quan}
autoCapitalize='none'
autoCorrect={false}
returnKeyType="next"
keyboardAppearance="dark"
/>
<TextInput style = {styles.nameInput}
onChangeText={(text) => this.setState({desc: text})}
value = {this.state.desc}
autoCapitalize='none'
autoCorrect={false}
returnKeyType="next"
keyboardAppearance="dark"
/>
<TextInput style = {styles.nameInput}
onChangeText= {(text) => this.setState({amt: text})}
value = {this.state.amt}
autoCapitalize='none'
autoCorrect={false}
returnKeyType="next"
keyboardAppearance="dark"
/>
</View>
</View>
)}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'column',
},
itemDescription: {
marginTop:20,
backgroundColor:'#00CED1',
flexDirection:'row',
justifyContent:'space-between',
},
itemDescriptionText:{
fontSize:12,
color:'white',
},
addButton:{
borderWidth:1,
height:20,
borderRadius:5,
overflow:'hidden',
backgroundColor:'red',
},
addButtonText:{
paddingLeft:10,
paddingRight:10,
},
nameInput:{
flex:1,
height: 20,
textAlignVertical:'bottom',
paddingLeft: 5,
paddingRight: 5,
fontSize: 12,
backgroundColor:'#E0FFFF',
},
hairLine:{
height:1,
backgroundColor:'black',
marginTop:0,
marginLeft:20,
marginRight:20
},
rowsOfInput:{
// flex:1,
flexDirection:'row',
justifyContent:'space-around'
},
});
Whats wrong in the code? I want to store userInput for each entry into QUANTITY, DESCRIPTION, AMOUNT as array of object.
One of your issues is a scoping issue. Change your _add method to this.
_add = () => {
let dataStorage = [{amt: this.state.amt, quan: this.state.quan, desc: this.state.desc}, ...this.state.dataStorage]
console.log(dataStorage)
this.setState({dataStorage})
}
Also, your data property on state will never work and is unnecessary.
Here is an example.
It still won't display anything because you do nothing with dataStorage.
Related
I have been finding it very difficult to search a mapped list in react native. Actually, doing that with a Flatlist would be very easy for me, but this is really giving me a headache. I hope someone will be able to help me out.
So, the code looks like this
import React, { Component, useState } from 'react';
import { Button, Animated, Share, ScrollView,
ImageBackground, StyleSheet, View} from "react-native";
import { Container, Header, Content, ListItem, Item, Input, Text, Icon, Left, Body, Right, Switch } from 'native-base';
const Auslawpart = ({ route, navigation}) => {
const {parts, hereme} = route.params;
const [search, setSearch] = useState('');
const [filteredDataSource, setFilteredDataSource] = useState(parts);
const filterSearch = (text) => {
const newData = parts.filter((part)=>{
const itemData = part.name.toUpperCase()
const textData = text.toUpperCase()
return itemData.indexOf(textData)>-1
});
setFilteredDataSource(newData);
setSearch(text);
}
return (
<Container>
<Animated.View
style={{
transform:[
{translateY:translateY }
],
elevation:4,
zIndex:100,
}}
>
<View style={{
// marginTop:Constant.statusBarHeight,
position:"absolute",
top:0,
left:0,
right:0,
bottom: 0,
height: 50,
backgroundColor:"#f0f0f0",
borderBottomWidth: 1,
borderBottomColor: '#BDC3C7',
flexDirection:"row",
justifyContent:"space-between",
elevation: 4,
}}>
<View style={{margin: 10, flex: 1 }}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Icon type="MaterialIcons" name="arrow-back" style={{ left: 10, }}
size={50} />
</TouchableOpacity>
</View>
<View style={{
justifyContent:"space-around",
margin: 4,
flex: 1,
marginLeft:0,
}}>
<Text numberOfLines={3} style={{fontSize:10,
alignSelf: 'flex-end', color:"#212F3C",
padding: 2}}>{hereme}</Text>
</View>
</View>
</Animated.View>
<Content style={{marginTop:50}}>
<Item>
<Icon type= "MaterialIcons" />
<Input placeholder="Search legal terms and maxisms"
onChangeText={(text) => filterSearch(text)}
/>
<Icon type="Octicons" name="law" />
</Item>
{parts.map((part) => (
<TouchableOpacity
key={part.name}
>
<ListItem onPress={() =>
navigation.navigate("Auslawcount", {
meaning: part.meaning,
partname: part.name})
}>
<Icon type="Octicons" name="law" />
<Body>
<Text onScroll={(e)=>{
scrollY.setValue(e.nativeEvent.contentOffset.y)
}} style={{ fontSize: 17, fontFamily: "Lato-Regular",}} key={part.name}>{part.name.toUpperCase()}</Text>
</Body>
</ListItem>
</TouchableOpacity>
))}
</Content>
</Container>
);
};
export default Auslawpart;
The data in part.name are passed from another screen to this screen. I am try to make the Input field search through the mapped part.name. can anybody please help me with a solution.
Here is an Example
snack: https://snack.expo.io/#ashwith00/bold-waffles
const data = [
{ name: 'Suleman' },
{ name: 'Sulan' },
{ name: 'Suljan' },
{ name: 'Ram' },
{ name: 'Raj' },
];
const Auslawpart = ({ route, navigation }) => {
const {} = route.params;
const [filteredDataSource, setFilteredDataSource] = useState(parts);
const filterSearch = (text) => {
if (text.length > 0) {
const newList = data.filter((part) => {
const name = part.name.toUpperCase();
const textData = text.toUpperCase();
return name.includes(textData);
});
setFilteredDataSource(newList);
} else {
setFilteredDataSource(parts);
}
};
return (
<View>
<TextInput placeholder="Enter here" onChangeText={filterSearch} />
<ScrollView>
{filteredDataSource.map((item, i) => (
<Text key={i} style={{ paddingVertical: 30 }}>
{item.name}
</Text>
))}
</ScrollView>
</View>
);
};
I'm a newbie in React Native.
What I'm trying to do is making a Google Maps-like app. At the MainMap.js screen, when we enter,the screen will immediately generate 2 search bars. The first one will have the text "Your location". The second one and so on will be empty for users to type in for searching location.
But, I'm having some problems with the FlatList component. In my PlaceInput component, I use the defaultValue, as a prop, for the text input. And then in the MainMap.js, I will have a state which initially be set as "Your Location", then I'll change it to null when the FlatList starts rendering from the 2nd PlaceInput component.
Here's the MainMap.js*
import React from 'react';
import {
TouchableWithoutFeedback,
StyleSheet,
Keyboard,
PermissionsAndroid,
Platform,
View,
Button,
FlatList,
Dimensions
} from 'react-native';
import PlaceInput from '../components/PlaceInput';
import axios from 'axios';
import PolyLine from '#mapbox/polyline';
import MapView, {Polyline, Marker} from 'react-native-maps';
import Geolocation from 'react-native-geolocation-service';
const INCREMENT = 1;
const HEIGHT = Dimensions.get('window').height;
const WIDTH = Dimensions.get('window').width;
class MainMap extends React.Component{
constructor(props){
super(props);
this.state={
_userLocationDisplayed: null,
userLatitude: 0,
userLongitude: 0,
numOfInput:[0,1],
counter: 1,
};
};
componentDidMount(){
this._requestUserLocation();
};
// Get user current location
// Ask user permission for current location
// Request the Directions API from Google
// Get the formatted_address & name from Google Places API
// Adding a search bar
onAddSearch(){
this.setState((state) => ({
counter: state.counter + INCREMENT,
numOfInput: [...state.numOfInput, state.counter],
}));
};
onChangeSearchDisplay(){
this.setState({
_userLocationDisplayed: null
})
};
render(){
return(
<TouchableWithoutFeedback onPress={this.hideKeyboard} >
<View style={styles.container} >
<View style={{height: HEIGHT/2.5 }}>
<FlatList
data={this.state.numOfInput}
keyExtractor={(item, index) => item}
renderItem={itemData => {
return(
<PlaceInput
id={itemData.item}
onDelete={this.onDeleteSearch}
showDirectionOnMap={this.showDirectionOnMap}
userLatitude={userLatitude}
userLongitude={userLongitude}
userLocationDisplayed={this.state._userLocationDisplayed}
/>
)
}}
/>
</View>
</View>
</TouchableWithoutFeedback>
)
}
}
//}
export default MainMap;
const styles = StyleSheet.create({
container:{
flex: 1
},
map:{
...StyleSheet.absoluteFillObject
},
});
Here's the PlaceInput component
import React from 'react';
import {
View,
TextInput,
StyleSheet,
Text,
Dimensions,
TouchableOpacity,
Keyboard,
} from 'react-native';
import axios from 'axios';
import _ from 'lodash'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
const WIDTH = Dimensions.get('window').width;
const HEIGHT = Dimensions.get('window').height;
class PlaceInput extends React.Component{
constructor(props){
super(props);
this.state={
...
}
...
}
render() {
// console.log(this.state);
// Code for displaying the suggestions from the Google Place API
// Don't care about it too much :)))
const predictions = this.state.predictions.map(prediction => {
const { id, structured_formatting, place_id } = prediction;
return(
<TouchableOpacity
key={id}
onPress={() => this.setDestination(structured_formatting.main_text, place_id)}
>
<View style={styles.suggestion}>
<Text style={styles.mainText}>{structured_formatting.main_text}</Text>
<Text style={styles.secText}>{structured_formatting.secondary_text}</Text>
</View>
</TouchableOpacity>
);
} )
return (
<View style={{flex: 1, flexDirection: 'column'}} key={this.props.id}>
<View style={styles.buttonContainer}>
<View style={{flex: 1, alignItems: 'center'}}>
<Text style={{fontSize: 8}}>{'\u25A0'}</Text>
</View>
<View style={{flex: 4}}>
<TextInput
key={this.id}
autoCorrect={false}
autoCapitalize='none'
style={styles.inputStyle}
placeholder='Search your places'
onChangeText={(input) => {
this.setState({destinationInput: input});
this.getPlacesDebounced(input);
}}
value={this.state.destinationInput}
{/*What I'm trying here as mentioned*/}
defaultValue={this.props.userLocationDisplayed}
/>
</View>
<View style={styles.rightCol}>
<TouchableOpacity onPress={() => this.props.onDelete(this.props.id)}>
<Icon name='delete' size={25} style={{alignSelf: 'center'}} />
</TouchableOpacity>
</View>
</View>
{predictions}
</View>
)
}
}
const styles = StyleSheet.create({
buttonContainer:{
flexDirection: 'row',
height: (HEIGHT - 690),
width: (WIDTH-48),
marginTop: 55,
padding: 5,
backgroundColor: 'white',
shadowColor: '#000000',
elevation: 7,
shadowRadius: 5,
shadowOpacity: 1,
borderRadius: 5,
alignItems: 'center',
alignSelf:'center'
},
inputStyle:{
fontFamily: 'sans-serif-thin',
fontSize: 16,
color: 'black',
fontWeight: 'bold'
},
suggestion:{
backgroundColor: 'white',
padding: 10,
borderWidth: 0.5,
width: (WIDTH-48),
alignSelf: 'center'
},
secText:{
color: '#777'
},
mainText:{
color: '#000'
},
rightCol:{
flex: 1,
borderLeftWidth: 1,
borderColor: '#ededed',
},
})
export default PlaceInput;
I'd love to hear your comments for helping me.
Also, feel free to give out other ways too since I think my way isn't optimized enough. And I'm building this for production too.
If I understand your question correctly, you're asking how to conditionally set a prop value based upon where it is in the flatlist data. Basically you want the first PlaceInput component to have a displayed "entered" text value of "Your Location" and the rest to have nothing.
Update API of PlaceInput to take in another prop to indicate displaying a default value or not.
PlaceInput.js
...
<TextInput
key={this.id}
autoCorrect={false}
autoCapitalize='none'
style={styles.inputStyle}
placeholder='Search your places'
onChangeText={(input) => {
this.setState({destinationInput: input});
this.getPlacesDebounced(input);
}}
value={this.state.destinationInput}
defaultValue={this.props.displayDefaultValue ? this.props.defaultValue : null}
/>
...
And pass in whether or not any specific PlaceInput should display it or not. Since you want only the first to display and the rest to not, using the array index is a good place to start. Here we can leverage the fact that in javascript 0 is a falsey value, while all other numbers are truthy. Using !index then !0 is true while !1, !2, etc, are all false.
MainMap.js
<FlatList
data={this.state.numOfInput}
keyExtractor={(item, index) => item}
renderItem={({ index, item }) => {
return(
<PlaceInput
id={item}
defaultValue="Your Location"
displayDefaultValue={!index} // index 0 is falsey, all others truthy
onDelete={this.onDeleteSearch}
showDirectionOnMap={this.showDirectionOnMap}
userLatitude={userLatitude}
userLongitude={userLongitude}
userLocationDisplayed={this.state._userLocationDisplayed}
/>
)
}}
/>
I take advantage of Drew Reese's answer but It doesn't work
I found out why it doesn't work because of the value prop, whose value is set by this.state.destinationInput which is " " in the state in the constructor. I again use Drew's way in the value prop instead, and it works
<TextInput
key={this.id}
autoCorrect={false}
autoCapitalize='none'
style={styles.inputStyle}
placeholder='Search your places'
onChangeText={(input) => {
this.setState({destinationInput: input});
this.getPlacesDebounced(input);
}}
value={this.props.displayDefaultValue ? this.props.defaultValue : this.state.destinationInput}
/>
BIG thanks to Drew Reese
In my RN application, I have the following array.
const PDFItems = [
{ id: 1001, name: 'APPLICATION FORM.PDF', size: '2.77 MB' },
{ id: 1002, name: 'BENEFIT ILLUSTRATION.PDF', size: '368 KB' },
{ id: 1003, name: 'PRODUCT SUMMARY.PDF', size: '2.02 MB' },
{ id: 1004, name: 'TERMS AND CONDITIONS.PDF', size: '269 KB' },
];
I created the following function to render items.
renderPDFItems = () => {
return PDFItems.map(item => (
<ListItem
key={item.id.toString()}
icon={<Download />}
title={item.name}
label={item.size}
onPress={() => {}}
/>
));
}
This is my ListItem component.
import React, { Component } from 'react';
import { StyleSheet, TouchableOpacity, View } from 'react-native';
import colors from 'res/colors';
import SinglifeText from './text';
interface IProps {
title: string;
label: string;
icon: Object;
key: string;
onPress?: Function;
}
class ListItem extends Component<IProps> {
render() {
const { title, label, icon, key, onPress } = this.props;
return (
<TouchableOpacity onPress={onPress} key={key}>
<View style={styles.itemContainer}>
<View style={styles.titleContainer}>
<View style={styles.icon}>{icon}</View>
<SinglifeText type={SinglifeText.Types.BUTTON_LBL} label={title} />
</View>
<SinglifeText type={SinglifeText.Types.BODY_SMALL} label={label} />
</View>
</TouchableOpacity>
);
}
}
const styles = StyleSheet.create({
itemContainer: {
borderColor: colors.gray,
borderRadius: 4,
borderWidth: 0.5,
padding: 14,
paddingVertical: 24,
flexDirection: 'row',
alignContent: 'center',
alignItems: 'center',
marginBottom: 10,
},
titleContainer: {
flex: 1,
flexDirection: 'row',
alignContent: 'center',
alignItems: 'center',
},
icon: {
marginRight: 10,
},
});
export default ListItem;
When I run the app, it shows a warning saying that,
key is not a prop. Trying to access it will result in undefined being returned. If you need to access the same value within the child component, you should pass it as a different prop
What am I doing wrong here? My keys are unique and still gives this error.
Just dont name the prop key. Something like id has the same syntactic meaning.
renderPDFItems = () => {
return PDFItems.map(item => (
<ListItem
id={item.id.toString()}
icon={<Download />}
title={item.name}
label={item.size}
onPress={() => {}}
/>
));
}
ListItem.js
class ListItem extends Component<IProps> {
render() {
const { title, label, icon, id, onPress } = this.props;
return (
<TouchableOpacity onPress={onPress} key={id}>
<View style={styles.itemContainer}>
<View style={styles.titleContainer}>
<View style={styles.icon}>{icon}</View>
<SinglifeText type={SinglifeText.Types.BUTTON_LBL} label={title} />
</View>
<SinglifeText type={SinglifeText.Types.BODY_SMALL} label={label} />
</View>
</TouchableOpacity>
);
}
}
It seems your key prop defined is ambiguous to TouchableOpacity key={key}. Try renaming key prop to some other name.
As some guys have said above, we don't need the key prop. TouchableOpacity has the key by default, and we can't use key another prop as 'key'
I have some issue with Flatlist, I have an array of objects I got them from DB,
and save them to state, now when I log the this.state.providers in render() method or in the callback func after setState I got the valid Object like this
[{username: "Test", key: "53HoDga6aYhHsV5pCi5sx6LGbx42"}]
but when I passed these object into data prop in <Flatlist data={this.state.providers} /> the flatlist not rendering!
but when I add the object in the data prop manual like this
<Flatlist data={[{username: "Test One", key: "53HoDga6aYhHsV5pCi5sx6LGbx42"}]}
the flatlist work very well,
But I'm sure the code is correct because I added them into other project and work very well!!
Edit
when I pass tow object into the array the flatlist work!!
so how to handle it if I got one object from DB!
Code
import React, { Component } from "react";
import firebase from "react-native-firebase";
import Icon from "react-native-vector-icons/Ionicons";
import {
View,
Text,
StyleSheet,
FlatList,
TouchableOpacity,
Dimensions
} from "react-native";
class ListChats extends Component {
constructor(props) {
super(props);
this.state = {
providers: []
};
}
_chatList = () => {
let currentUser = firebase.auth().currentUser.uid;
let ref = firebase.database().ref(`Messages/${currentUser}`);
let providersKeys = [];
ref.once("value").then(snapshot => {
snapshot.forEach(childsnap => {
console.log(childsnap.key);
providersKeys.push(childsnap.key);
});
let usernames = [];
providersKeys.forEach(key => {
firebase
.database()
.ref("users")
.child(key)
.once("value")
.then(providersShot => {
let username = providersShot.val().username;
usernames.push({ username: username, key: key });
});
});
this.setState({ providers: usernames }, () =>
console.log(this.state.providers)
);
});
};
componentDidMount() {
this._chatList();
}
_listEmptyComponent = () => {
return (
<View style={styles.container}>
<Text style={{ alignSelf: "center" }}>No Chats Found :O</Text>
</View>
);
};
render() {
console.log(this.state.providers); // I got [{username: "Test", key: "53HoDga6aYhHsV5pCi5sx6LGbx42"}]
return (
<View style={{ flex: 1 }}>
<FlatList
key={Math.random() * 1000}
data={this.state.providers}
contentContainerStyle={{ flexGrow: 1 }}
ListEmptyComponent={this._listEmptyComponent()}
keyExtractor={item => item.key.toString()}
renderItem={({ item }) => {
console.log("item", item);
return (
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate("ChatDetails", {
Key: item.key,
providerName: item.username
})
}
>
<View style={styles.parent}>
<Icon name="ios-contact" size={50} color="#4d8dd6" />
<View
style={{
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start",
marginHorizontal: 25
}}
>
<Text
style={{
color: "#000",
fontSize: 17
}}
>
{item.username}
</Text>
</View>
<Icon name="ios-chatboxes" size={25} color="#d6d6d6" />
</View>
</TouchableOpacity>
);
}}
// keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
parent: {
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
paddingVertical: 25,
marginHorizontal: 15,
borderBottomWidth: 1,
borderBottomColor: "#eee"
}
});
export default ListChats;
You should add extraData property to FlatList:
extraData={this.state}
In here your using usernames.push method to add the data objects to array, using this method will not indicate the state about a need of a re-render even if the state is updated with a new array.
For this usual coding pattern is using the spread operator
this.setState({ providers: [...usernames] })
Use "extraData" props of FlatList.
Im making a component and calling it in my app.js with props inside like { placeholder }, but it always returns a refrenceError: Can't find variable placeholder. I don't understand why.
Calling it:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import * as firebase from 'firebase';
import { Input } from './components/input'
import { Button } from './components/button'
export default class App extends React.Component {
state = {
email: '',
password: '',
}
render() {
return (
<View style={styles.container}>
<Input
placeholder='Enter your email'
label='Email'
onChangeText={password => this.setState({ password })}
value={this.state.password}
/>
<Input
placeholder='Enter your password'
label='Password'
secureTextEntry
onChangeText={email => this.setState({ email })}
value={this.state.email}
/>
<Button>Login</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
padding: 20,
},
});
And the component
import React from 'react';
import { View, StyleSheet, Text, TextInput } from 'react-native';
const Input = () => {
return (
<View>
<Text style={styles.label}>Label</Text>
<TextInput
style={styles.input}
placeholder={ placeholder }
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
marginTop: 10,
width: '100%',
borderColor: '#eee',
borderBottomWidth: 2,
},
label: {
padding: 5,
paddingBottom: 0,
color: '#eee',
fontSize: 17,
fontWeight: '700',
width: '100%'
},
input: {
paddingRight: 5,
paddingLeft: 5,
paddingBottom: 2,
backgroundColor: '#eee',
fontSize: 18,
fontWeight: '700',
width: '100%',
}
})
export { Input };
const Input = ({ placeholder }) => { //<==== here
return (
<View>
<Text style={styles.label}>Label</Text>
<TextInput
style={styles.input}
placeholder={ placeholder }
/>
</View>
);
}
props will not be passing in automatically. It will be passed in as an argument, and your input component doesnt accept any argument and you're trying to access a variable placeholder and hence getting the error stated
Your Input is taking no props at all. You need to pass the props as parameters of the component function:
const Input = (props) => {
return (
<View>
<Text style={styles.label}>Label</Text>
<TextInput
style={styles.input}
placeholder={ props.placeholder }
/>
</View>
);
}
Accept props as a parameter in the Input component, then use props to access placeholder. You need to change the code of Input component to
const Input = (props) => {
return (
<View>
<Text style={styles.label}>Label</Text>
<TextInput
style={styles.input}
placeholder={ props.placeholder }
/>
</View>
);
}
Hope this will help!