I want to achieve the data rendering in a form of table something like this:
I have a data (stored in variable 'myData') of form:
{
"id":0,
"name": ["wheat", "Rice", "Sugar"],
"Quality":["Good", "good","good"],
"Quantity":["200","200","200"]
}
I tried mapping the and together to implement this, but it renders the data horizontally in a single row.
This is what I tried to achieve so far with minimum test code.
return (
<View style={{flexDirection:'column'}}>{myData.map( (item) => {
return (
<View key={item.id}>
<View>
<Text>
{item.name}
</Text>
</View>
<View>
<Text >
{item.Quality}
</Text>
</View>
</View>
)
})}
</View>
)
Please help to achieve this
map each array into it's own View and use flexDirection: "row"
const list = myData.map(item => {
return (
<View style={{ flexDirection: 'row'}}>
<View style={{ flex: 1}}>
{item.name.map((name, i) => (
<Text>{i + 1}</Text>
))}
</View>
<View style={{ flex: 1}}>
{item.name.map((name, i) => (
<Text>{name}</Text>
))}
</View>
<View style={{ flex: 1}}>
{item.Quality.map((quality, i) => (
<Text>{quality}</Text>
))}
</View>
<View style={{ flex: 1}}>
{item.Quantity.map((quantity, i) => (
<Text>{`${quantity} Bags`}</Text>
))}
</View>
</View>
);
});
Try this,
return (
<View style={{flexDirection:'column'}}>{myData.name.map( (item, index) => {
return (
<View key={item.id}>
<View>
<Text>
{item}
</Text>
</View>
<View>
<Text >
{myData.Quality[index]}
</Text>
</View>
<View>
<Text >
{myData.Quantity[index]}
</Text>
</View>
</View>
)
})}
</View>
)
Related
I can increase and decrease item quantity from the app in sync with the graphql without any issue. the problem here is when i add a new item it appears in the graphql but it doesn't show up on the app unless i press save ctrl + s, and the same happens when i delete item it gets deleted on the graphql but it disappears from the app only when i press save or ctrl + s.
this is the product details screen and how i add items to cart, and it works fine without any issue and items get added to graphql when i call onAddToCart function
import React, {useState, useEffect} from "react";
import { View, Text, Image, StyleSheet, FlatList, TouchableOpacity, Alert} from 'react-native';
import Icon from 'react-native-vector-icons/AntDesign';
import Colors from "../../constants/Colors";
import { Auth , Hub} from "aws-amplify";
import { API, graphqlOperation } from 'aws-amplify';
import {getProduct } from '../graphql/queries';
import Card from "../../component/Card";
import {createCartItems} from '../graphql/mutations';
const [getProducts, setGetProducts] = useState([])
const [user, setUser] = useState(undefined)
const prodId = route.params;
const [quantity, setQuantity] = useState(1);
useEffect(()=>{
fetchProducts();
},[])
const fetchProducts = async ()=>{
const productsData = await API.graphql(graphqlOperation(getProduct, {id: prodId.productId}))
setGetProducts(productsData.data.getProduct)const checkUser = async ()=>{
try {
const authUser = await Auth.currentAuthenticatedUser({bypassCache: true})
// console.log(authUser)
setUser(authUser)
} catch (error) {
setUser(null)
}
}
useEffect(()=>{
checkUser();
},[])
useEffect(() => {
const listener = data => {
if (data.payload.event === 'signIn' || data.payload.event === 'signOut') {
checkUser();
}
};
Hub.listen('auth', listener);
return () => Hub.remove('auth', listener);
}, []);
const onAddToCart = async ()=>{
const userData = await Auth.currentAuthenticatedUser();
const newCartItem = {
userId: userData.attributes.sub,
productId: getProducts.id,
productPrice: getProducts.price,
productTitle: getProducts.title,
productImage: getProducts.image,
quantity: quantity,
}
API.graphql(graphqlOperation(createCartItems, {input: newCartItem}))
if(user === undefined || !user){
Alert.alert(
'خطأ تسجيل الدخول',
'لابد من تسجيل الدخول للأستمرار',
[
{
text : 'سجل الدخول',
onPress: ()=> navigation.navigate('SignIn')
},
{
text: 'اغلاق'
}
]
)
}else{
navigation.navigate('CartItem')
}
}
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
setQuantity(1);
});
return unsubscribe;
}, [navigation]);
return(
<View style={styles.container}>
<View style={styles.headerImageView}>
<Card image={{uri: getProducts.image}} promotion={getProducts.promotionRate} />
</View>
<View style={styles.descriptionPriceView}>
<Text style={styles.price}>{getProducts.price} ج.م </Text>
<Text style={styles.descriptionText}>{getProducts.description}</Text>
</View>
<View style={styles.quantity}>
<Text style={styles.quantityText}>الكمية</Text>
<Text style={styles.quantityText}>{quantity}</Text>
</View>
<View style={styles.share}>
<TouchableOpacity>
<Image style={{width: 30, height: 30, margin: 10}} source={{uri: 'https://firebasestorage.googleapis.com/v0/b/test-5c03d.appspot.com/o/NakoA%2FLogos%2Ffacebook.png?alt=media&token=6ba4cb45-4f42-42f5-b5c7-2063eeffd1a8'}}/>
</TouchableOpacity>
<TouchableOpacity>
<Image style={{width: 30, height: 30, margin: 10}} source={{uri: 'https://firebasestorage.googleapis.com/v0/b/test-5c03d.appspot.com/o/NakoA%2FLogos%2Finstagram.png?alt=media&token=f06f3b53-f026-43f0-a855-8ace6ed7b1b8'}}/>
</TouchableOpacity>
<TouchableOpacity>
<Icon name="sharealt" size={30} color="black" />
</TouchableOpacity>
</View>
<View style={styles.bottomAddToCartView}>
<View>
<TouchableOpacity onPress={onAddToCart}>
<Text style={styles.bottomAddToCartText}>أضف للسلة</Text>
</TouchableOpacity>
</View>
<View style={styles.addQuantity}>
<TouchableOpacity onPress={()=>{
setQuantity(Math.max(quantity - 1, 1))
}}>
<Text style={styles.minProd}>-</Text>
</TouchableOpacity>
<Text style={styles.numProd}>{quantity}</Text>
<TouchableOpacity onPress={()=>{
setQuantity(Math.min(quantity + 1, 100))
}}>
<Text style={styles.plusProd}>+</Text>
</TouchableOpacity>
</View>
</View>
</View>
)};
this is the CartItem screen
import React, {useEffect, useState} from "react";
import { View, Text, Image, StyleSheet, FlatList } from 'react-native';
import { Auth } from "aws-amplify";
import Colors from "../../constants/Colors";
import { DataStore} from "aws-amplify";
import ItemQuantity from '../../component/ItemQuantity';
import {CartItems} from '../models'
const CartItem = ()=>{
const [cartItem, setCartItem] = useState([]);
const [user, setUser] = useState('');
useEffect(()=>{
fetchCartItem();
userData();
},[])
const fetchCartItem = async ()=>{
try {
const cartitemsData = await DataStore.query(
CartItems, c=>c.userId("eq", user).quantity("gt", 0)
)
setCartItem(cartitemsData)
} catch (error) {
console.log(error)}}
return(
<View style={styles.screen}>
<FlatList data={cartItem} renderItem={({item})=>{
return(
<View style={styles.container}>
<View style={styles.cardView}>
<View style={styles.imageView}>
<Image style={styles.image} source={{uri: item.productImage}} />
</View>
<View style={styles.detailsView}>
<Text style={styles.titl}>{item.productTitle}</Text>
<Text style={styles.price}>{item.productPrice} ج.م </Text>
</View>
</View>
<ItemQuantity quantityItem={item.quantity}
updatedItemId={item.id}
userId={item.userId}
productID={item.productID}
productPrice={item.productPrice}
productTitle={item.productTitle}
productImage={item.productImage}
/>
</View>)}}/>
</View>)};
this is itemQuantity componenet
import React, {useState, useEffect} from "react";
import {View, Text, TouchableOpacity, StyleSheet} from 'react-native'
import { AntDesign } from '#expo/vector-icons';
import { DataStore } from "aws-amplify";
import { CartItems } from "../src/models";
const ItemQuantity = ({quantityItem, updatedItemId})=>{
const [quantity, setQuantity] = useState(quantityItem);
const onMinusPressed = ()=>{
setQuantity(Math.max(1, quantity - 1))
};
useEffect(()=>{fetchUpdatedCartItemPlus();},[quantity])
const fetchUpdatedCartItemPlus= async()=>{
const original = await DataStore.query(CartItems, updatedItemId)
await DataStore.save(CartItems.copyOf(original, updated=>{
updated.quantity = quantity
}))};
return(
<View style={styles.quantity}>
<TouchableOpacity onPress={onMinusPressed}>
<AntDesign name={'minuscircleo'} size={24} color="black" />
</TouchableOpacity>
<TouchableOpacity onPress={cartitemDelete}>
<AntDesign name={'delete'} size={24} color="black" />
</TouchableOpacity>
<Text style={styles.itemQuantity}>{quantity}</Text>
<TouchableOpacity onPress={onPlusPressed}>
<AntDesign name="pluscircleo" size={24} color="black" />
</TouchableOpacity>
</View>
)};
I am trying to achieve two column layout if i click something inside tab (for example list of Chats) chat should show in right, now its appears inside left column
can you point me to correct way?
if someone needs this is how I make this
/* eslint-disable react-native/no-inline-styles */
import * as React from 'react';
import {Button, Text, View} from 'react-native';
import {NavigationContainer} from '#react-navigation/native';
import {createStackNavigator} from '#react-navigation/stack';
import {createBottomTabNavigator} from '#react-navigation/bottom-tabs';
function ContactScreen({route}) {
const {contactId} = route.params;
return (
<View style={{flexDirection: 'row', flex: 1}}>
<Tab.Navigator
initialRouteName="Contacts"
style={{flex: 1}}>
<Tab.Screen name="Chats" component={ChatsTab} />
<Tab.Screen name="Contacts" component={ContactsTab} />
</Tab.Navigator>
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Contact {contactId}</Text>
</View>
</View>
);
}
function ChatScreen({route}) {
const {chatId} = route.params;
return (
<View style={{flexDirection: 'row', flex: 1}}>
<Tab.Navigator
initialRouteName="Chats"
style={{flex: 1}}>
<Tab.Screen name="Chats" component={ChatsTab} />
<Tab.Screen name="Contacts" component={ContactsTab} />
</Tab.Navigator>
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>Chat {chatId}</Text>
</View>
</View>
);
}
function ChatsTab({navigation}) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>chats tab</Text>
<Button
title="open chat 1"
onPress={() =>
navigation.navigate('Chat', {
screen: 'Chats',
chatId: 1,
})
}
/>
<Button
title="open chat 2"
onPress={() =>
navigation.navigate('Chat', {
screen: 'Chats',
chatId: 2,
})
}
/>
<Button
title="open chat 5"
onPress={() =>
navigation.navigate('Chat', {
screen: 'Chats',
chatId: 5,
})
}
/>
</View>
);
}
function ContactsTab({navigation}) {
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Text>contacts tab</Text>
<Button
title="open contact 4"
onPress={() =>
navigation.navigate('Contact', {
screen: 'Contacts',
contactId: 4,
})
}
/>
<Button
title="open contact 3"
onPress={() =>
navigation.navigate('Contact', {
screen: 'Contacts',
contactId: 3,
})
}
/>
</View>
);
}
const HomeStack = createStackNavigator();
const Tab = createBottomTabNavigator();
export default function App() {
return (
<NavigationContainer>
<HomeStack.Navigator screenOptions={{headerShown: false}}>
<HomeStack.Screen
initialParams={{chatId: 0}}
name="Chat"
options={{animationEnabled: false}}
component={ChatScreen}
/>
<HomeStack.Screen
initialParams={{contactId: 0}}
options={{animationEnabled: false}}
name="Contact"
component={ContactScreen}
/>
</HomeStack.Navigator>
</NavigationContainer>
);
}
I am using react native and AWS for my backend. I am trying to add a feature that allows users to be able to change their password after they have logged into the app. I believe I should be able to do this using the Auth.changePassword function (AWS doc). For some reason, I am getting an error that the username or password is incorrect.
When testing, the user returns a CognitoUser, the oldPassword is definitely correct, and the newPassword throws errors if it does not meet the character settings. I am lost as to what the issue could be. Should I also be using completeChangePassword in conjunction?
import React from 'react';
import {Auth} from '#aws-amplify/auth';
export default class ChangePassword extends React.Component {
constructor(props) {
super(props);
this.state = {
oldPassword: '',
newPassword: '',
};
}
handleChangePassword = async () => {
const { oldPassword, newPassword } = this.state;
await Auth.currentAuthenticatedUser()
.then(user => {
return Auth.changePassword(user, oldPassword, newPassword)
})
.then(data => console.log(data))
.then(user => this.props.navigation.navigate('Home'))
.catch(err => console.log(err))
}
render() {
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.text_header}>Change Password</Text>
</View>
<Animatable.View
animation='bounceInUp'
style={styles.footer}
>
<View style={styles.footer}>
<Text style={styles.text_footer}>Old Password</Text>
<View style={styles.action}>
<Feather
name='lock'
color='#05375a'
size={20}
/>
<TextInput
placeholder='Enter old password'
style={styles.textInput}
autoCapitalize='none'
onChangeText={(val) => this.setState({ oldPassword: val })}
/>
</View>
<Text style={styles.text_footer}>New Password</Text>
<View style={styles.action}>
<Feather
name='lock'
color='#05375a'
size={20}
/>
<TextInput
placeholder='Enter new password'
style={styles.textInput}
autoCapitalize='none'
onChangeText={(val) => this.setState({ newPassword: val })}
/>
</View>
<View style={styles.button}>
<TouchableOpacity
style={styles.signIn}
onPress={this.handleChangePassword}
>
<LinearGradient
colors={['#55B142', '#155843']}
style={styles.signIn}
>
<Text style={[ styles.textSign, { color: '#fff' }]}>Submit</Text>
</LinearGradient>
</TouchableOpacity>
</View>
<View style={{ alignItems: 'center'}}>
<View style={{flexDirection: 'row', alignItems: 'center', paddingTop: 5 }}>
<TouchableOpacity
onPress={() => this.props.navigation.navigate('EditProfile')}
style={[styles.signUp, {
//borderColor: '#155843',
//borderWidth: 1,
marginTop: 15,
}]}
>
<Text style={[styles.textSign, {
color: '#155843'
}]}>Go Back</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Animatable.View>
</View>
);
}}
Turns out the problem was that the account that was logged in wasn't verified which is why it would reject the email address.
In my react-native app I'm returning data from an api, everything is working except for my layout it got messed up, i have an albums list and i need to display each 2 albums next to each other, but all of them are getting displayed under each other, here is my code:
Album detail:
const AlbumDetails= (props) => {
return(
<Album>
<Image source={{ uri: props.album.thumbnail_image }}/>
<Text>{props.album.title}</Text>
</Album>
);
};
export default AlbumDetails;
Album:
const Album= (props) => {
return(
<View style={{flex: 1}}>
<View style={{display: "flex", flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<View style={styles.albumContainer}>
<View>{props.children}</View>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
albumContainer: {
backgroundColor: 'red',
width: '50%',
height: 180,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 20,
flexDirection: 'column'
},
});
export default Album;
I suggest to use FlatList component with numColumns param equal 2. Check Expo Snack or code below.
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<FlatList
style={{ margin: 5 }}
data={data}
numColumns={2}
keyExtractor={(item, index) => item.id}
renderItem={dataItem => (
<AlbumDetails
album={{
title: dataItem.item.title,
thumbnail_image: dataItem.item.image,
}}
/>
)}
/>
</View>
);
}
}
i need to display a scrollview in react native application, after a condition using if. In fact, i have a list of items in firebase that contain text and title but sometimes they may contain images also. I need to display that list of text and titles in the exact same order and also the images if there is any. here the code i used
_renderScrollViewContent() {
const data = this.state.items
if (data.image) {
return (
<View>
{data.map((item, i) =>
<View key={i}>
<Image source={require('path')}/>
<Text>{item.image}</Text>
<Text>{item.title}</Text>
<Text>{item.text} </Text>
</View>
)}
</View>
);
}
else
{
return (
<View>
{data.map((item, i) =>
<View key={i} style={styles.row}>
<Text>{item.image}</Text>
<Text>{item.title}</Text>
<Text>{item.text} </Text>
</View>
)}
</View>
);
}
}
render() {
const headerHeight = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [HEADER_MAX_HEIGHT, HEADER_MIN_HEIGHT],
extrapolate: 'clamp',
});
const imageOpacity = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE / 2, HEADER_SCROLL_DISTANCE],
outputRange: [1, 1, 0],
extrapolate: 'clamp',
});
const imageTranslate = this.state.scrollY.interpolate({
inputRange: [0, HEADER_SCROLL_DISTANCE],
outputRange: [0, -50],
extrapolate: 'clamp',
});
return (
<View style={styles.fill}>
<ScrollView
style={styles.fill}
scrollEventThrottle={16}
onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: this.state.scrollY}}}]
)}
>
{this._renderScrollViewContent()}
</ScrollView>
);
}
I Now it seems that it's not even checking for the condition (data.image) and it seems that it always goes directly to the else condition and displays only the text.
PS: i'm using this tutorial to make a scrollable header and it's working perfectly fine in displaying text but not images inside them https://medium.com/appandflow/react-native-scrollview-animated-header-10a18cb9469e.
Also, if delete the if condition, i always get the blank spaces between items .. any suggestion
so that's the code that finally worked for me ..i hope it will help someone else in the future
_renderScrollViewContent() {
var productList = [];
this.state.items.forEach(function (item) {
if (!item.image) {
productList.push(
<View key={item.key}>
<Text>{item.title}</Text>
<Text>{item.text}</Text>
<Text>{item.image}</Text>
</View>
);
}
else {
productList.push(
<View key={item.key}>
<Text>{item.title}</Text>
<Text>{item.text}</Text>
<Text>{item.image}</Text>
<Image source={require('path')}>
<View>
<Text>{item.legend}</Text>
</View>
</Image>
</View>
);
}
}.bind(this));
return (
<View>
{productList }
</View>
);
}