Posting to a server multiple parameters at once - React Native - react-native

I have a project where I am fetching from an API some data and I am rendering those data in React Native. After rendering, I am displaying a list of documents and when I click in one of them I pass some values to next page which includes Name, Description of the document and input fields. Then I sign the document.
So, I want to log all these values (Title, description, user input values and user signature) and POST them using fetch() to my server.
Please let me know if you need further explanation, thanks for any suggestion!
Here is the code of the class where I am displaying everything, I dont think you will need the homepage code:
class DetailScreen extends React.Component {
state = {
isModalVisible: false
};
_toggleModal = () =>
this.setState({ isModalVisible: !this.state.isModalVisible });
constructor(props) {
super(props);
this.state = {
signature: null,
}
this.postToBmp();
}
static navigationOptions = {
title: 'Content of selected'
};
handleSignature = signature => {
this.setState({ signature }), this.setState({ isModalVisible: false });
};
postToBmp = () => {
fetch('https://myurl', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Connection': 'Keep-Alive',
},
credentials: 'include',
body: JSON.stringify({
from: 'test#test.dk',
attachmentName: 'The PDF file name',
recipientFullName: 'My name',
to: [
'<test#test.com>'
]
})
})
}
renderTextandInputs = (obje) => {
console.log("KEYVALUES:", obje.keyValues)
var keyvalue_to_json = JSON.parse(obje.keyValues);
var foundTextFields = [];
for (let i = 0; i < keyvalue_to_json.length; i++) {
if (keyvalue_to_json[i].type === 'textfield') {
foundTextFields.push(<TextInput style={{ borderWidth: 1, flex: 1, alignItems: 'flex-start' }}>{keyvalue_to_json[i].placeholderText}</TextInput>)
}
}
return (
<View>
<ListItem
title={obje.name}
subtitle={obje.description}
/>
<View >
{foundTextFields}
</View>
</View>
)
}
render() {
const style = `.m-signature-pad--footer
.button {
background-color: red;
color: #FFF;
}`;
const obj = this.props.navigation.state.params.item;
var propsArray = [];
const itemArray = Object.assign(obj)
propsArray.push(itemArray)
keyExtractor = (item, index) => {
return index.toString();
}
return (
<View style={{ flex: 1, justifyContent: "center" }}>
<View style={{ flex: 1, alignItems: 'stretch' }}>
<FlatList
key={propsArray.key}
data={propsArray}
renderItem={({ item }) => this.renderTextandInputs(item)}
/>
</View>
<View >
{this.state.signature ? (
<Image
resizeMode={"contain"}
style={{ width: 150, height: 114 }}
source={{ uri: this.state.signature }}
/>
) : null}
</View>
<Modal isVisible={this.state.isModalVisible}
onBackdropPress={() => this.setState({ isModalVisible: false })}
>
<View style={{ flex: 1 }}>
</View>
<Signature
width="100"
onOK={this.handleSignature}
descriptionText="Please draw your signature"
clearText="Clear"
confirmText="Save"
webStyle={signature_styles}
/>
</Modal>
<View>
<Button title="SIGN" onPress={this._toggleModal} />
</View>
</View>
);
}
Here is a screenshot of the home page where I am displaying a list of documents from API:
This is a screenshot of second page where I displaying name, description, textinputs from API and I sign the document using a component:

Related

Add a button "see more" in FlatList?

I use flatList to make a list of elements. I would like to show 15 elements and then add a button "see more" to show the next 15 etc.
I was about tu use this tutorial : https://aboutreact.com/react-native-flatlist-pagination-to-load-more-data-dynamically-infinite-list/
But I don't need to use fetch, I already have set up the data (state.listData) and in fact, I'm a little lost on how to adapt it...
I thought that maybe anyone could help me a little.
Thanks a lot
this.state = {
selectedId: '',
setSelectedId:'',
listData:''
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<Item
item={item}
onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
style={{ backgroundColor }}
/>
<Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
</View>
);
};
initListData = async () => {
let list = await getFlights(0);
if (list) {
this.setState({
listData: list
});
}
};
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.listData}
renderItem={this.renderItem}
maxToRenderPerBatch={15}
keyExtractor={(item) => item.id}
extraData={this.selectedId}
/>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
);
};
}
I just tried this thanks to #Pramod 's answer :
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.flightsListitem, style]}>
<Text style={styles.h4}>{item.id}</Text>
</TouchableOpacity>
);
export default class FlightsList extends Component {
constructor(props) {
super(props);
this.state = {
selectedId: '',
setSelectedId:'',
listData:'',
page:1,
perPage:2,
loadMoreVisible:true,
displayArray:[]
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<Item
item={item}
onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
style={{ backgroundColor }}
/>
<Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
</View>
);
};
initListData = async () => {
let list = await getFlights(0);
if (list) {
this.setState({
listData: list
});
}
};
componentDidMount(){
this.setNewData()
// console.log(tempArray)
}
setNewData(){
var tempArray=[]
if(this.state.listData.length == this.state.displayArray.length){
this.setState({
loadMoreVisible:false
})
}else{
for(var i=0; i<(this.state.page*this.state.perPage); i++){
tempArray.push(this.state.listData)
}
this.setState({
displayArray: tempArray,
loadMoreVisible:true
})
}
}
loadMore(){
this.setState({
page: this.state.page+1
},()=>{
this.setNewData()
})
}
async UNSAFE_componentWillMount() {
this.initListData();
}
render() {
return (
<ImageBackground
source={require("../../assets/images/background.jpg")}
style={styles.backgroundImage}
>
<Header
backgroundImage={require("../../assets/images/bg-header.png")}
backgroundImageStyle={{
resizeMode: "stretch",
}}
centerComponent={{
text: i18n.t("mytrips.title"),
style: styles.headerComponentStyle,
}}
containerStyle={[styles.headerContainerStyle, { marginBottom: 0 }]}
statusBarProps={{ barStyle: "light-content" }}
/>
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.displayArray}
renderItem={this.renderItem}
keyExtractor={(item) => item.id}
extraData={this.selectedId}
/>
{this.state.loadMoreVisible == true?
<Button style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}}
title = 'load more'
onPress={()=>{this.loadMore()}}>
</Button>:null}
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
</ImageBackground>
);
};
}
the flatlist is not displayed : I get :
You can user pagination method with per page limit so that you can have granular control
Load the array per page when component mount
On every click increase the per page and based on per page update data of your flat list
And also put a flag which will check when the data has ended which will help to hide the load more button when data ends
Working example: https://snack.expo.io/#msbot01/suspicious-orange
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
SafeAreaView,
SectionList,
Switch,
FlatList
} from 'react-native';
import Constants from 'expo-constants';
import Icon from 'react-native-vector-icons/FontAwesome';
import AwesomeIcon from 'react-native-vector-icons/FontAwesome';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
page:1,
perPage:2,
loadMoreVisible:true,
DATA: [{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'fourth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29sd72',
title: 'sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29dr72',
title: 'seventh Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d7w2',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29ad72',
title: 'Nineth Item',
},
{
id: '58694a0f-3da1-471f-bd96-14557d1e29d72',
title: 'Tenth Item',
}],
displayArray:[]
}
}
componentDidMount(){
this.setNewData()
// console.log(tempArray)
}
setNewData(){
var tempArray=[]
if(this.state.DATA.length == this.state.displayArray.length){
this.setState({
loadMoreVisible:false
})
}else{
for(var i=0; i<(this.state.page*this.state.perPage); i++){
tempArray.push(this.state.DATA[i])
}
this.setState({
displayArray: tempArray,
loadMoreVisible:true
})
}
}
loadMore(){
this.setState({
page: this.state.page+1
},()=>{
this.setNewData()
})
}
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={this.state.displayArray}
renderItem={({item})=>
<View style={{flexDirection:'row'}}>
<Text style={{fontSize:20}}>{item.title} </Text>
</View>
}
keyExtractor={item => item.id}
/>
{this.state.loadMoreVisible == true?
<View style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}} onClick={()=>{this.loadMore()}}>Load more</View>:null
}
</View>
);
}
}
Set data in state (already done ==> this.state.listData)
Set counter in state (initialize with 1)
Set 15 first elements in state (you can name it "renderedData" or something like that) and then increase cuonter to 1
Add a function that increases the "renderedData" by 15 items by increasing the counter by one
Add Footer component to the list which will call the function you created in stage 3
To take only 15( or 30/45/60 etc..) items from the list you can do something like this:
this.setState({ renderedItem: listData.slice(0, counter*15) })

Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is not an object (evaluating '_this.props.navigation.navigate')

I'm trying to display an image I have captured using expo-camera, from the camera component I'm trying to navigate to a new file which will display the image but after I took the image it won't navigate to the new page.
I tried importing the file and then navigate it but it still won't work and give me the warning instead.
This is the code where I tried to navigate to the new file.
export default class CameraExample extends React.Component {
state = {
hasCameraPermission: null,
type: Camera.Constants.Type.back,
};
async componentDidMount() {
const { status } = await Permissions.askAsync(Permissions.CAMERA);
this.setState({ hasCameraPermission: status === 'granted' });
}
snap = async() => {
if(this.camera) {
console.log('Taking photo');
const options = {quality: 1, base64: true, fixOrientation: true, exif: true};
const photo = await this.camera.takePictureAsync(options);
this.props.navigation.navigate("Show", {photouri: photo.uri})
}
}
render() {
const { hasCameraPermission } = this.state;
if (hasCameraPermission === null) {
return <View />;
} else if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
} else {
return (
<View style={{ flex: 1 }}>
<Camera style={{ flex: 1 }} type={this.state.type}
ref = {ref => {
this.camera = ref;
}}
>
<View
style={{
flex: 1,
backgroundColor: 'transparent',
flexDirection: 'row',
}}>
<TouchableOpacity onPress={this.snap.bind(this)}>
<Ionicons
name = "md-camera"
color = "white"
size = {30}
/>
</TouchableOpacity>
<TouchableOpacity
style={{
flex: 0.1,
alignSelf: 'flex-end',
alignItems: 'center',
}}
onPress={() => {
this.setState({
type:
this.state.type === Camera.Constants.Type.back
? Camera.Constants.Type.front
: Camera.Constants.Type.back,
});
}}>
<Ionicons
name = "md-reverse-camera"
color = "white"
size = {30}
/>
</TouchableOpacity>
</View>
</Camera>
</View>
);
}
}
}
And this is the code where I try to display the image.
export default class ShowImages extends React.Component{
render(){
console.log('OK')
const { navigation } = this.props;
const paramm = navigation.getParam('photouri');
return(
<Content>
<View>
<Text>
paramm: {JSON.stringify(paramm)}
</Text>
<Image style={{height: 700, width: 850, alignSelf: "center"}}
source={{uri: this.props.navigation.state.paramm.photouri}}
resizeMode="contain"/>
</View>
</Content>
)
}
}
I expect it to navigate to the new page and display the captured
image but it gave me the warning. I can't seem to find what is wrong with my code. Can anyone suggest what I should do? Thank you.
change this
<TouchableOpacity onPress={this.snap.bind(this)}> => <TouchableOpacity onPress={this.snap}>
Put it in the status value and pass it on.
export default class ShowImages extends React.Component{
constructor(props) {
super(props);
this.state = {
paramm: this.props.navigation.state.params.photouri
};
}
...
<Image style={{height: 700, width: 850, alignSelf: "center"}}
source={{uri: this.state.paramm }}
resizeMode="contain"/>

How to pass data from screen to screen from flat list item

How do i able to pass the list items from first screen to the third screen, i am able to pass data on to the second screen but not the third screen. What i'm trying to achieve is how do i able to edit the list item on the third screen and inside the edit text input get the data and update. By the way, i'm using flat list item, because list view is deprecated. Below are my codes and screenshots.
First Screenshot
Second screenshot
Third screenshot
First screenshot coding
class SecondScreen extends Component {
constructor(props){
super(props);
this.state = {
loading: true,
email: '',
name: '',
title: '',
description: '',
error: '',
dataSource: [],
isFetching: false
}
}
onPress(item){
this.props.navigation.navigate(
'DetailsScreen',
{item},
);
}
renderItem = ({ item }) => {
return (
<TouchableOpacity style={{ flex: 1, flexDirection: 'row',
marginBottom: 3}}
onPress={() => { this.onPress(item) }}>
<View style={{ flex: 1, justifyContent: 'center', marginLeft:
5}}>
<Text style={{ fontSize: 18, color: 'green', marginBottom:
15}}>
{"ID - "+item.id}
</Text>
<Text style={{ fontSize: 18, color: 'green', marginBottom:
15}}>
{"Title - "+item.title}
</Text>
<Text style={{ fontSize: 16, color: 'red'}}>
{"Description - "+item.description}
</Text>
</View>
</TouchableOpacity>
)
}
renderSeparator = () => {
return (
<View
style={{height: 1, width: '100%', backgroundColor: 'black'}}>
</View>
)
}
ListEmptyView = () => {
return (
<View style={styles.container}>
<Text style={{textAlign: 'center'}}> No job available.</Text>
</View>
);
}
handleBackButton = () => {
Alert.alert(
'Exit App',
'Exiting the application?', [{
text: 'Cancel',
onPress: () => console.log('Cancel Pressed'),
style: 'cancel'
}, {
text: 'OK',
onPress: () => BackHandler.exitApp()
},],{
cancelable: false
}
)
return true;
}
componentDidMount(){
this.getAvailableJob()
BackHandler.addEventListener('hardwareBackPress',
this.handleBackButton);
}
getAvailableJob() {
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + this.props.token
};
axios({
method: 'GET',
url: 'http://192.168.1.201:8000/api/jobs',
headers: headers,
}).then((response) => {
console.log('response3',response)
console.log('response4',this.props.token)
this.setState({
dataSource: response.data,
isFetching: false
});
}).catch((error) => {
console.log(error);
this.setState({
error: 'Error retrieving data',
loading: false
});
});
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress',
this.handleBackButton);
}
onRefresh() {
this.setState({ isFetching: true }, function() { this.getAvailableJob()
});
}
render() {
const { container, emailText, errorText } = styles;
const { loading, email, name, error, title, description } = this.state;
return(
<View style={container}>
<FlatList
data={this.state.dataSource}
onRefresh={() => this.onRefresh()}
refreshing={this.state.isFetching}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
ListEmptyComponent={this.ListEmptyView}
ItemSeparatorComponent={this.renderSeparator}
/>
</View>
);
}
}
export default withNavigation(SecondScreen);
Second screenshot coding
class DetailsScreen extends React.Component {
handleBackButton = () => {
this.props.navigation.popToTop();
return true;
}
componentDidMount(){
BackHandler.addEventListener('hardwareBackPress',
this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress',
this.handleBackButton);
}
onPress(item){
this.props.navigation.push(
'EditDetailsScreen',
{item},
);
}
render() {
const { backButton } = styles;
let item = this.props.navigation.state.params.item;
return (
<View style={styles.container}>
<View style={[styles.container2, { backgroundColor: 'yellow' },
styles.hiddenContainer]}>
<Text style = { styles.TextStyle }> ID {
this.props.navigation.state.params.item.id }</Text>
</View>
<Text style = { styles.TextStyle }> Title {
this.props.navigation.state.params.item.title }</Text>
<Text style = { styles.TextStyle }> Description {
this.props.navigation.state.params.item.description }</Text>
<TouchableOpacity
style = {styles.submitButton}
onPress = {() => { this.onPress(item) }}>
<Text style = {styles.submitButtonText}> Edit </Text>
</TouchableOpacity>
</View>
);
}
}
export default withNavigation(DetailsScreen);
Third screenshot coding
class EditDetailsScreen extends React.Component {
handleTitle = (text) => {
this.setState({ title: text })
}
handleDescription = (text) => {
this.setState({ description: text })
}
handleBackButton = () => {
this.props.navigation.popToTop();
return true;
}
componentDidMount(){
BackHandler.addEventListener('hardwareBackPress',
this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress',
this.handleBackButton);
}
updateJobDetails = () => {
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + this.props.token
};
axios({
method: 'PUT',
url: 'http://192.168.1.201:8000/api/jobs',
headers: headers,
}).then((response) => {
this.setState({
title: response.data,
description: response.data,
loading: false
});
}).catch((error) => {
console.log(error);
this.setState({
error: 'Error retrieving data',
loading: false
});
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.container2, { backgroundColor: 'yellow' },
styles.hiddenContainer]}>
<Text style = { styles.TextStyle }> ID {
this.props.navigation.state.params.item.id }</Text>
</View>
<Text style = { styles.TextStyle }> Title {
this.props.navigation.state.params.item.title }</Text>
<Text style = { styles.TextStyle }> Description {
this.props.navigation.state.params.item.description }</Text>
<TextInput style = {styles.input}
underlineColorAndroid = "transparent"
placeholder = "Edit Title"
placeholderTextColor = "#9a73ef"
autoCapitalize = "none"
onChangeText = {this.handleTitle}/>
<TextInput style = {styles.input}
underlineColorAndroid = "transparent"
placeholder = "Edit Description"
placeholderTextColor = "#9a73ef"
autoCapitalize = "none"
onChangeText = {this.handleDescription}/>
<TouchableOpacity
style = {styles.submitButton}
onPress = {this.updateJobDetails}>
<Text style = {styles.submitButtonText}> Submit </Text>
</TouchableOpacity>
</View>
);
}
}
export default withNavigation(EditDetailsScreen);
I can update using postman but not in react native, and also in postman i had to set the Body to use x-www-form-urlencoded instead of form-data. So how do i able to update in react native? Any help would be much appreciated. Below is my postman screenshot.
Postman
A suggestion is to use a state container like react-redux, but if you don't want: you can pass a function in the props like
<renderedItem update={(newVal) => this.setState({ val: newVal})}>
and then in the renderedItem you can call this function with new value like so:
this.props.update(this.state.newVal)
I've solved the problem by using qs.stringify(data). Below is my updated code.
updateJobDetails = () => {
url = 'http://192.168.1.201:8000/api/jobs/' + this.props.navigation.state.params.item.id;
const qs = require('qs');
const data = {title:this.state.TextInput_Title,
description:this.state.TextInput_Description};
const options = {
method: 'PUT',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + this.props.token
},
data: qs.stringify(data),
url
}
axios(options).then((response) => {
console.log('update response',response)
Alert.alert(
'Update successful',
'Your details has been updated', [{
text: 'OK',
onPress: () => this.props.navigation.popToTop()
},]
,{
cancelable: false
}
)
this.setState({
loading: false,
});
}).catch((error) => {
Alert.alert("Please Enter All the Values.");
console.log(error);
this.setState({
error: 'Error retrieving data',
loading: false
});
});
}
render() {
return (
<View style={styles.container}>
<View style={[styles.container2, { backgroundColor: 'yellow' },
styles.hiddenContainer]}>
<Text style = { styles.TextStyle }> ID {
this.props.navigation.state.params.item.id }</Text>
</View>
<Text style = {styles.TextStyle2}>
Title:
</Text>
<TextInput style = {styles.input}
underlineColorAndroid = "transparent"
placeholder = "Edit Title"
placeholderTextColor = "#9a73ef"
autoCapitalize = "none"
value={this.state.TextInput_Title}
onChangeText = { TextInputValue => this.setState({TextInput_Title: TextInputValue})}/>
<Text style = {styles.TextStyle2}>
Description:
</Text>
<TextInput style = {styles.input}
underlineColorAndroid = "transparent"
placeholder = "Edit Description"
placeholderTextColor = "#9a73ef"
autoCapitalize = "none"
value={this.state.TextInput_Description}
onChangeText = { TextInputValue =>
this.setState({TextInput_Description: TextInputValue})}/>
<TouchableOpacity
style = {styles.submitButton}
onPress = {this.updateJobDetails}>
<Text style = {styles.submitButtonText}> Submit </Text>
</TouchableOpacity>
</View>
);
}

Pass function in react native prop

I currently have a screen that lists items with star ratings on them.
This is created due to the following JSX being returned by a _renderItem function for a FlatList component. :
<TouchableOpacity
delayPressIn={70}
activeOpacity={0.8}
onPress={() => {
navigate("WellbeingBreakdown", {
id: info.item.id,
});
}}
>
<RkCard rkType="horizontal" style={styles.card}>
<Image
rkCardImg
source={info.item.icon}
/>
<View rkCardContent>
<RkText rkType="small">{info.item.title}{' '}<Ionicons name="ios-information-circle-outline" size={18} color="gray"/></RkText>
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Rating
type='custom'
onFinishRating={this.ratingCompleted}
imageSize={20}
ratingColor={RkTheme.current.colors.primary}
ratingImage={STAR_IMAGE}
style={{paddingVertical: 8}}
startingValue={2} /*I want to change this to be dynamic */
/>
<RkButton
rkType="rounded small"
style={{backgroundColor: RkTheme.current.colors.primary, marginLeft: 15}}
onPress={() => navigate("DynamicActivityAssessor", {
id: info.item.title
})
}
>Assess</RkButton>
</View>
</View>
</RkCard>
</TouchableOpacity>
What i would like to do, is dynamically fetch data (from an API) and pass the user's ratings for each item into the startingValue prop of the Rating component.
The API if called returns an array. So accessing response[0] gives you an object similar to this (values depending on if its an activity or diet rating etc):
{
"ActivityTotalScore": null,
"DietTotalScore": 1,
},
So i thought a function roughly like so would work, but i can't figure out how to pass it to that prop. Note - info.item.id is the title of the rendered item in question. So it is equal to 'Activity' or 'Weight' etc
getScore(info){
fetch(`${server_url}data/Wellbeing?where=type%3D`+info.item.id, {
method: "GET", // or 'PUT' // data can be `string` or {object}!
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.catch(error => console.error("Error:", error))
.then(response => {
return response[0][info.item.id+'TotalScore'] ;
}
)
}
The simple way is to create a new Component that representents your card. It could be
// In AssessCard.js
import React from 'react';
// Others imports
export default class AssessCard extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
rating: 0,
item: props.item
};
}
componentDidMount() {
this._loadRating();
}
_loadRating() {
fetch(`${server_url}data/Wellbeing?where=type%3D`+info.item.id, {
method: "GET", // or 'PUT' // data can be `string` or {object}!
headers: {
"Content-Type": "application/json"
}
})
.then(res => res.json())
.catch(error => console.error("Error:", error))
.then(response => {
this.setState({ rating: response[0][info.item.id+'TotalScore'] }); // HERE WE'RE SAVING THE RATING
}
)
}
render() {
const { rating, item } = this.state;
return (
<TouchableOpacity
delayPressIn={70}
activeOpacity={0.8}
onPress={() => {
navigate("WellbeingBreakdown", {
id: item.id,
});
}}
>
<RkCard rkType="horizontal" style={styles.card}>
<Image
rkCardImg
source={item.icon}
/>
<View rkCardContent>
<RkText rkType="small">{item.title}{' '}<Ionicons name="ios-information-circle-outline" size={18} color="gray"/></RkText>
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Rating
type='custom'
onFinishRating={this.ratingCompleted}
imageSize={20}
ratingColor={RkTheme.current.colors.primary}
ratingImage={STAR_IMAGE}
style={{paddingVertical: 8}}
startingValue={rating} // HERE WE USE RATING PROP OF THIS COMPONENT
/>
<RkButton
rkType="rounded small"
style={{backgroundColor: RkTheme.current.colors.primary, marginLeft: 15}}
onPress={() => navigate("DynamicActivityAssessor", {
id: item.title
})
}
>Assess</RkButton>
</View>
</View>
</RkCard>
</TouchableOpacity>
);
}
}
//in file contening your _renderItem function
import AssessCard from './somewhere/AssessCard';
/* CODE */
_renderItem (info) => {
return <AssessCard item={info.item} />
}

how to target exact item in react native flat list and hide something?

i am using flatList in react native . i want to hide only perticular item from the list. current when i am hiding a button every button is hidden from the list.
when i am pressing the bid now button . then all the button is hidden if success. i want to hide the particular items bid now button.
/////////////// main.js
constructor (props){
super(props);
this.state = {
access_token: null,
user : null,
biddata: [],
totalBid : null,
page: 0,
showbidmodel: false,
bidValue: '',
biditem : '',
hideButton: false
}
}
placeBid = (e) => {
if (this.state.bidValue.length < 2) {
Toast.show({
text: ' please enter a valid bid!',
position: 'top',
buttonText: 'Okay'
})
}
else {
var url = `...............`;
const { params } = this.props.navigation.state;
console.log("all paramssssssssf ---> ", params.token);
console.log("check state-------------->>>>",this.state)
var data = {
price: this.state.bidValue,
material_type: this.state.biditem.material_type,
truck_type: this.state.biditem.truck_type,
material_name: this.state.biditem.material_name,
num_of_trucks: this.state.biditem.num_of_trucks,
truck_name: this.state.biditem.truck_name,
_id: this.state.biditem._id,
weight: this.state.biditem.weight,
extra_notes: this.state.biditem.extra_notes,
order_no: this.state.biditem.order_no,
staff: 'no',
created_by: this.state.biditem.created_by
};
console.log("post body ----------------->>>>>", JSON.stringify(data))
fetch(url, {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
Accept: "application / json",
Authorization: "Bearer " + params.token
}
}).then(res => res.json())
.catch(error => {
console.log("bid error :", error)
})
.then(response => {
console.log("all BID SUCCESs response---> ", response);
const SUCCESS = 'Quotation Saved'
if (response.status === SUCCESS) {
Toast.show({
text: ' SUCCESS !!!! BID is placed . ',
position: 'top',
buttonText: 'Okay'
})
this.setState({ showbidmodel: false , hideButton: true })
}
else
return;
});
}
}
renderItem = ({ item }) => {
return (
<ListItem
id={item.index}
selected={() => { alert(item + "selected")}}
onPressItem ={ this.onPressItem }
onPressDetails ={ this.onPressDetails }
title={item.index}
hideButton = {this.state.hideButton}
items = { item }
/>
);
}
return (
<View style = {styles.container}>
<View style={styles.innerContainer} >
<Header title="Home" navigation={this.props.navigation} />
<Modal
animationType="slide"
transparent={false}
visible={this.state.showbidmodel}
onRequestClose={() => {
this.setState({ showbidmodel: false });
}}>
<KeyboardAvoidingView style={styles.modalStyle}>
<View style={styles.modalInnerStyle }>
<Text style={{ color: "white", fontWeight: "bold", textAlign: "center", fontSize: 20 }}>
Place your bid Here.
</Text>
<InputLocal
placeholder=" your bid "
onChange={(e) => { this.setState({ bidValue: e }); } }
value={this.state.bidValue}
/>
<TouchableOpacity
style={styles.login}
onPress={ this.placeBid }
>
<Text style={{ color: "white", fontWeight: 'bold' }}> Submit </Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
</Modal>
{typeof this.state.biddata !== "undefined" && this.state.biddata.length > 0 ?
<FlatList
data={this.state.biddata}
keyExtractor={this.keyExtractor}
extraData={this.state}
renderItem={this.renderItem}
onEndReached = { this.loadMoreTripData }
onEndReachedThreshold = {1}
/> : <ActivityIndicator
style = {styles.loading}
size="large" color="#0000ff"
/> }
</View>
</View>
);
//////////////// listItem.js
onPressDetail = () => {
this.props.onPressDetails( this.props.items._id.$oid );
};
onPressBid = () => {
this.props.onPressItem(this.props.items._id.$oid);
};
<View style={{ flex: 1, flexDirection: 'row',}} >
<MyIcon name="airport-shuttle" />
<Text style={styles.textStyle}>Truck Type: {this.props.items.truck_type}</Text>
</View>
{ !this.props.hideButton ? (
<View style={styles.buttonView}>
<View style={styles.flex} >
<TouchableOpacity
style={styles.detail}
onPress={this.onPressDetail}
>
<Text style={{ color: "white", fontWeight: 'bold', textAlign: "center" }}> Details </Text>
</TouchableOpacity>
</View>
<View style={styles.flex} >
<TouchableOpacity
style={styles.bid}
onPress={this.onPressBid}
>
<Text style={{ color: "white", fontWeight: 'bold', textAlign: "center", backgroundColor: '#ED4C67' }}> Bid Now </Text>
</TouchableOpacity>
</View>
</View>
) : null }
</View>
You can store index of the item on which you want to hide button. For that you have to pass index in your renderItem() and from there to your ListItem
renderItem={({ item, index }) => this. renderItem(item, index)}
or
You can have variable inside your each item, which indicates to show or hide button