is anyone able to help pass the data to the modal? The .map function returns the month names from the data [] array (needed for the slider), and I'd like to display that particular one in a modal view as well.
Current view:
and modal:
expectations:
unfortunately, only the first month from the [] is visible in the modal.
I am also putting the .js file for review:
import React, { useContext, useState } from 'react';
import { AuthenticatedUserContext } from '../AuthenticatedUserProvider';
import { Swiper } from 'react-native-swiper';
import Modal from 'react-native-modal';
import { db } from '../firebase';
import FontAwesome from 'react-native-vector-icons/FontAwesome';
import { View, Text, TouchableHighlight, StyleSheet, Button, TextInput, TouchableOpacity } from 'react-native';
const data = [
{ id: 1, name: 'Month1' },
{ id: 2, name: 'Month2' },
{ id: 3, name: 'Month3' }
];
export default function HomeScreen() {
const { user } = useContext(AuthenticatedUserContext);
const [ isModalVisible, setModalVisible ] = useState(false);
const [ months, setMonths ] = useState(data);
const [ values, setValues ] = useState({
budget: '',
month: '',
});
const toggleModal = () => {
setModalVisible(!isModalVisible);
};
const onSave = () => {
setValues({ ...values, userId: user.uid });
setModalVisible(!isModalVisible);
db.collection('Budget').add({
userId: user.uid,
budget: values.budget,
});
};
return (
<Swiper showsButtons={true} showsPagination={false} buttonWrapperStyle={{ alignItems: 'flex-start' }}>
{months.map((months, i) => (
<View key={i} style={styles.slider}>
<Text style={styles.text}> {months.name}</Text>
<View>
<View style={styles.mainCardView}>
<TouchableOpacity
onPress={
toggleModal
}
style={{ flex: 1, alignItems: 'flex-end', marginTop: 20 }}
>
<FontAwesome name="pencil-square-o" color="black" size={30} />
</TouchableOpacity>
</View>
</View>
<Modal isVisible={isModalVisible} style={{ margin: 0 }}>
<Text style= {{marginLeft: 50, color: '#fff'}}>Current month: {months.name}</Text>
<TextInput
style={{
height: 40,
borderColor: 'white',
borderWidth: 1,
color: 'white',
shadowColor: 'white',
margin: 50,
padding: 5,
marginVertical: 10,
}}
onChange={(e) => setValues({ ...values, budget: e.target.value })}
value={values.budget}
placeholder="Budget"
keyboardType="decimal-pad"
placeholderTextColor="#fff"
/>
<TouchableHighlight
style={{
height: 40,
borderRadius: 10,
backgroundColor: 'gray',
marginLeft: 50,
marginRight: 50,
marginTop: 20,
}}
>
<Button
onPress={onSave}
title="Confirm"
/>
</TouchableHighlight>
<TouchableHighlight
style={{
height: 40,
borderRadius: 10,
backgroundColor: 'gray',
marginLeft: 50,
marginRight: 50,
marginTop: 20,
}}
>
<Button
onPress={toggleModal}
title="Back"
/>
</TouchableHighlight>
</Modal>
</View>
))}
</Swiper>
);
}
Here are a couple suggestions:
{months.map((months, i) => (...))} I would not recommend using months as the current item in the map since its confusing. Instead, I would recommend something like months.map((month, i) => ())} since in actuality you are referring to just one month within the map.
You are rendering the modal within your map, so each month has its own modal. But you only render one modal at a time, so instead you can just put the modal outside of the map, and somehow point the modal to the currently active month (see below)
If you have another piece of state like const [activeMonth, setActiveMonth] = useState(). Then when you click one of the months you can set the modal state to open, and set the activeMonth state. Then in the modal, it would just display state based off the current active month. It seems like you can make use of your values state to do that probably!
Related
I am using react-native-google-places-autocomplete for a filter menu on a project. While I am inputting text into the <GooglePlacesAutocomplete/> object I want to track the text input with a state variable called 'address'. To do that I used a predefined function preProcess (ideally I would use onChangeText, but <GooglePlacesAutocomplete/> does not support it). Fortunately the state variable does update when input text is changed; however, after it updates, I receive a TypeError: undefined is not an object (evaluating 'stateText.length'). I've read every blog and stack overflow chain dealing with similar errors and haven't found why this error pops up with my specific application. Any help would be greatly appreciated.
import React, { useState, useEffect } from "react";
import {View, Text} from "react-native";
import Screen from "../../../../components/Screen";
import styles from "./LocationStyles";
import colors from "../../../../config/colors";
import { GooglePlacesAutocomplete } from "react-native-google-places-autocomplete";
import Geocoder from "react-native-geocoding";
import SuggestionRow from "./SuggestionRow";
function LocationScreen(props) {
const [address, setAddress] = useState("");
Geocoder.init("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", { language: "en" });
useEffect(() => {
console.log(`address is ${address}`);
}, [address]);
return (
<Screen style={styles.screen}>
<View style={{ marginTop: 25 }}>
<Text style={{ height: 25, fontSize: 14 }}>Street*</Text>
<View style={{ height: 100, position: "relative", zIndex: 10 }}>
<GooglePlacesAutocomplete
preProcess={(value) => setAddress(value)}
minLength={5}
debounce={200}
enablePoweredByContainer={false}
onPress={(data, details = null) => {
Geocoder.from(data.description)
.then((json) => {
var location = json.results[0].geometry.location;
})
.catch((error) => console.warn(error));
setAddress(`${data.terms[0].value} ${data.terms[1].value}`);
}}
styles={{
textInputContainer: {
borderWidth: 1,
borderRadius: 10,
overflow: "hidden",
paddingTop: 3,
borderColor: colors.transparentPrimary,
height: 45,
},
textInput: {
height: 38,
color: colors.black,
fontSize: 14,
},
}}
query={{
key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
language: "en",
types: "address",
fields: "geometry",
components: "country:us",
}}
renderRow={(item) => <SuggestionRow item={item} />}
/>
</View>
<Text style={{ color: colors.medium, fontSize: 10, marginTop: -50 }}>
e.g. 100 Larch Ave
</Text>
</View>
</Screen>
);
}
export default LocationScreen;
i showing some value list description and images on home screen using Flatlist .when i onpress Flatlist item passing image source and id .value passing getparams but error was TypeError: navigation.getParam is not a function.why??. Please solve issue and edit my code . i am a new to react native please solve my issue.
import React from 'react';
import { StyleSheet, Text, View, FlatList, TouchableOpacity, Image } from 'react-native';
import { Card, Rating } from 'react-native-elements'
import { MaterialCommunityIcons } from '#expo/vector-icons';
import { dishesData } from './DishesData';
const MenuDetailScreen = ({ navigation }) => {
const dish = dishesData.find(
(dish) => dish.id === this.navigation.getParam('id')
);
return (
<View style={styles.container}>
<Card>
<Card.Title
style={styles.titleTextStyle}>{dish.title}</Card.Title>
<Image style={{ height: 300, width: 350 }} source={{ uri: dish.imageSource }} />
</Card>
<Card>
<View style={{ flexDirection: "row" }}>
<Text style={styles.commentsTextStyle}>Comments</Text>
<View style={{ flexGrow: 1 }} />
<TouchableOpacity style={{ paddingBottom: 8 }} >
<MaterialCommunityIcons name="pencil-circle" size={40} color="blue" />
</TouchableOpacity>
</View>
<FlatList
scrollEnabled={false}
data={dish.dishDetails}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => {
return (
<View>
<Text style={styles.headerTextStyle}>{item.comment}</Text>
<Rating
readonly
imageSize={20}
startingValue={item.rating}
style={styles.ratingStyle}
/>
<Text style={styles.spacing}>- {item.author} , {item.created_by}</Text>
</View>
);
}}
/>
</Card>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
paddingBottom: 10
},
commentsTextStyle: {
fontSize: 20,
fontWeight: 'bold',
textAlign: 'left'
},
textInputStyle: {
width: "80%",
padding: 8,
marginBottom: 8,
fontSize: 16
},
submitButtonStyle: {
alignItems: 'center',
width: "80%",
borderRadius: 5,
marginBottom: 8,
padding: 8,
fontWeight: 'bold',
backgroundColor: 'rgba(0, 0, 255, 0.6)',
color: 'black'
},
cancelButtonStyle: {
alignItems: 'center',
width: "80%",
borderRadius: 5,
marginBottom: 8,
padding: 8,
fontWeight: 'bold',
backgroundColor: 'grey',
color: 'black'
},
ratingStyle: {
alignItems: 'flex-start',
paddingBottom: 8
},
titleTextStyle: {
fontSize: 20,
textAlign: 'left'
},
textStyle: {
paddingBottom: 8
},
headerTextStyle: {
fontSize: 16,
fontWeight: 'bold',
paddingTop: 8
},
spacing: {
padding: 8
},
ratingStyle: {
alignItems: 'flex-start',
paddingTop: 8
}
});
export default MenuDetailScreen;
Error place
7 | const MenuDetailScreen = ({ navigation }) =>{
8 |
9 | const dish = dishesData.find(
> 10 | (dish) => dish.id === this.navigation.getParam('id')
11 |
12 | );
13 |
enter code here
Better way is to useNavigation and useRoute from React Navigation.
Step-by-step changes
Step 1
import { useNavigation, useRoute } from '#react-navigation/native';
Step 2
const navigation = useNavigation();
const route = useRoute();
Step 3
const { id } = route.params
Step 4 - Check if you are passing params when you navigate
Example)
onPress={() => navigation.navigate('SCREEN_NAME_HERE', {
PARAM_KEY: PARAM_VALUE
})}
Full Example
import React from 'react';
...
import { useNavigation, useRoute } from '#react-navigation/native';
/*
Navigate to this screen by
navigation.navigate('MenuDetailScreen', {
id: <ID_VALUE_HERE>
})
*/
const MenuDetailScreen = () => {
const navigation = useNavigation();
const route = useRoute();
const { id } = route.params
const dish = dishesData.find(
(dish) => dish.id === id
);
return (
...
)
}
Once you get it working, I recommend you to go over Type checking
with TypeScript for safely navigating between screens in React.
Update the MenuDetailScreen >>
const dish = dishesData.find(
(dish) => dish.id === this.navigation.getParam('id')
);
I am having 2 problems using React Native and Firebase Real Time Database.
When I add something to the list with the text input, all the list itens are duplicated except the item that I just added, this problem is only solved when I refresh the app screen.
When I remove something from firebase dashboard or other client, the list is not updated real time.
import React, {useState, Component} from 'react';
import {
Text,
View,
Switch,
StyleSheet,
FlatList,
TextInput,
Button,
TouchableOpacity,
SafeAreaView,
VirtualizedList,
} from 'react-native';
import database from '#react-native-firebase/database';
class MenuBreakFastScreen extends React.Component {
state = {newItem: ''};
state = {itens: []};
componentDidMount() {
let dbRef = database().ref('/cafe/itens/');
this.listenerFirebase(dbRef);
}
listenerFirebase(dbRef) {
dbRef.on('value', dataSnapshot => {
const newItens = JSON.parse(JSON.stringify(this.state.itens));
dataSnapshot.forEach(child => {
newItens.push({
name: child.val().name,
key: child.key,
});
this.setState({itens:newItens});
});
});
}
addItem() {
if (this.state.newItem === '') {
return;
}
database().ref('/cafe/itens/').push({
name: this.state.newItem,
});
this.setState({
newItem: '',
});
}
render() {
const {itens} = this.state;
const {newItem} = this.state;
const renderItem = ( {item}) => {
return(
<ItemAsset title={item.name}/>
);
}
return (
<SafeAreaView
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<FlatList
data={itens}
renderItem={renderItem}
keyExtractor={item => item.key}
/>
<SafeAreaView style={{flexDirection: 'row'}}>
<TextInput
style={styles.input}
onChangeText={text =>
this.setState({
newItem: text,
})
}
value={newItem}
/>
<TouchableOpacity style={styles.Botao} onPress={() => this.addItem()}>
<Text style={styles.BotaoTexto}>+</Text>
</TouchableOpacity>
</SafeAreaView>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
texto: {
fontSize: 35,
},
input: {
color: '#000',
fontSize: 22,
borderWidth: 1,
flex: 8,
margin: 10,
},
BotaoTexto: {
color: '#fff',
fontSize: 22,
},
Botao: {
backgroundColor: '#000',
marginTop: 10,
padding: 10,
flex: 1,
alignItems: 'center',
margin: 10,
},
ListaContainer: {
flexDirection: 'row',
backgroundColor: '#000',
flex: 1,
},
item: {
backgroundColor: '#000',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
flexDirection: 'row',
},
title: {
color: '#ffff',
fontSize: 32,
},
});
const ItemAsset = ( {title} ) => {
return(
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
}
export default MenuBreakFastScreen;
When you are listen for real time changes on real-time database it will send all the items with snapshot when any data is changed. That happens because you are listen for whole list, not only for a single item. Therefore you do not need to get the current list from state. You just have to set the state with retrieved data.
listenerFirebase(dbRef) {
dbRef.on('value', dataSnapshot => {
const newItens = []; // This should be initially empty array. That's all.
dataSnapshot.forEach(child => {
newItens.push({
name: child.val().name,
key: child.key,
});
});
this.setState({itens:newItens});
});
}
After correcting this part the error you got when removing data will be also resolved.
I have stored the value locally using array, And I want to delete a single item by using Trash icon. But I need to delete the multi selected items from the array.
So I placed the button "Delete selected". But I am not able to select multiple items and I don't know how to write the functionality to delete multiple items. I'm new for the React Native so kindly help.
Here is my code
import React, { Component } from "react"
import { View, Text, TouchableOpacity, TouchableHighlight, TextInput, StyleSheet, FlatList,onRemove } from 'react-native'
import {Card,CardItem,Right} from 'native-base';
import Swipeout from 'react-native-swipeout'
import Icon from 'react-native-vector-icons/FontAwesome';
import MultiSelect from 'react-native-multiple-select';
class Screen3 extends Component{
constructor(props) {
super(props);
this.state = {
loading: false,
firstname:[],
onPress:true,
unique1:[],
unique:[],
selectedItems : [],
renderData:item,
key1:0
};
}
componentDidMount=()=>{
const{navigation}=this.props
const data=navigation.getParam('data','')
const unique=data.filter((value,index,self)=>self.indexOf(value)===index)
var key=0
const unique1=[]
for(var i=0;i<unique.length;i++){
key=key+1
var result={"name":unique[i],"key":key}
this.state.unique1.push(result)
this.state.key1=this.state.key1+1
this.setState({key1:this.state.key1})
}
}
onPressHandler(item) {
let renderData=[...this.state.renderData];
for(let data of renderData){
if(data.item==item){
data.selected=(data.selected==null)?true:!data.selected;
break;
}
}
this.setState({renderData});
}
deleteItem = (item,index) => {
console.log(item.name,index)
this.state.unique=this.state.unique1
let filtered=this.state.unique.filter((item1) => item1.key !== item.key)
console.log(filtered)
this.setState({unique1:filtered})
}
render(){
return (
<View>
<Text style={styles.heading}>
Manage Screen
</Text>
<TouchableOpacity style = {styles.Button}
onPress={()=>this.deleteItem(item,index) } >
<Text style={styles.button}>Delete selected</Text>
</TouchableOpacity>
<FlatList
data={this.state.unique1}
showsVerticalScrollIndicator={false}
extraData={this.state.key1}
style={{ marginTop: 16 }}
renderItem={({ item, index }) => (
// <TouchableOpacity onPress={() => this.handleData(item)}>
<TouchableOpacity onPress={() => this.onPressHandler(item,index)}>
item!=null?
<Card
style={{
elevation: 10,
marginBottom: 15,
}}
>
<View style={{ flex: 1 }}></View>
<CardItem bordered >
style={
item.selected==true
? {
padding: 10,
borderRadius: 5,
backgroundColor: '#000000',
}
: {
borderRadius: 5,
backgroundColor: '#a1a1a1',
}}
<Text>{item.name}</Text>
<Right style={{alignSelf:'flex-end' } }>
<TouchableOpacity onPress={() => this.deleteItem(item,index)}>
<Icon size={25} name={Platform.OS ==='android' ? "trash" : "ios-trash"} color="red"/>
</TouchableOpacity>
</Right>
</CardItem>
</Card>:null
// </TouchableOpacity>
)
}
/>
</View>
)
}
}
export default Screen3
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
heading: {
fontSize: 23,
paddingVertical:80,
textAlign: 'center',
marginBottom: 30,
marginTop: -40,
},
button:{
width:('39%'),
height:('4%'),
alignItems:'center',
borderWidth:1,
borderRadius:2,
marginTop:-80,
marginHorizontal:10,
marginLeft:110,
justifyContent:'center',
backgroundColor: '#b0c4de',
padding: 9,
fontSize: 15,
margin: 15,
height: 40,
width: 160,
alignItems: 'center'
}
}
)
You would need a different function to delete multiple items and that function would call your deleteItem() function. A simple, but not so efficient way would be to loop through your selectedItems and find them in your data array and then remove each selected item with deleteItem(). You can then improve from there if it's not efficient enough.
I have this code, where on ChangeText in react native, i am inserting multiple field values in the state, item. For some reason, the output in the console log shows alphabetical order. Since the logic is, that on ChangText, the function EnterValue inserts the value in item state. it finds the property name and then matches that to the text value, I think something gets wrong along the way. Please see below the code
import { StatusBar } from "expo-status-bar";
import React from "react";
import { StyleSheet, Text, View, Button, TextInput } from "react-native";
class App extends React.Component {
constructor() {
super();
this.state = {
step: 1,
TotalItem: [],
item: {
Brand: null,
Quantity: null,
Instructions: null,
},
};
}
// remember this logig since take names, it adds property values in alphabetical order, and thus change the order
EnterValue = (name) => {
return (text) => {
this.setState((prevState) => ({
item: { ...prevState.item, [name]: text },
}));
};
};
submit = (e) => {
e.preventDefault(e);
const { step } = this.state;
this.setState({
step: step + 1,
});
this.setState(
{
TotalItem: [...this.state.TotalItem, this.state.item],
},
() => {
console.log("updated state", this.state.TotalItem);
}
);
};
render() {
return (
<View style={{ flex: 1, margin: 20 }}>
<TextInput
placeholder="enter name"
onChangeText={this.EnterValue("Brand")}
style={{ borderWidth: 2, borderColor: "skyblue", margin: 20 }}
/>
<TextInput
placeholder="Quantity"
onChangeText={this.EnterValue("Quantity")}
style={{ borderWidth: 2, borderColor: "skyblue", margin: 20 }}
/>
<TextInput
placeholder="Instructions"
onChangeText={this.EnterValue("Instructions")}
style={{ borderWidth: 2, borderColor: "skyblue", margin: 20 }}
/>
<View style={styles.container}>
<View style={{ flex: 1 }}>
<Button
style={{ flex: 1, backgroundColor: "red" }}
title="add"
onPress={this.add}
/>
</View>
<View style={{ flex: 1 }}>
<Button
style={{ flex: 1, backgroundColor: "blue" }}
title="submit"
onPress={this.submit}
/>
</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
},
});
export default App;
Change
onChangeText={this.EnterValue("Quantity")}
onChangeText={this.EnterValue("Brand")}
onChangeText={this.EnterValue("Instructions ")}
To
onChangeText={() => this.EnterValue("Quantity")}
onChangeText={() => this.EnterValue("Brand")}
onChangeText={() => this.EnterValue("Instructions ")}