How can i update my existing image in react native - javascript

well first i need to display the existing image that comes from API in react native.
then i need to update the existing image and replace with new picture.
Code:
<FlatList
data={filePath}
keyExtractor={(item, index) => index}
renderItem={({item}) => {
setImageName(item.fileName);
setImageType(item.type);
setImageUri(item.uri);
return (
<View>
<Image source={{uri: item.uri}} style={styles.imageStyle} />
</View>
);
}}
/>
button where i set my new picture
<GlobalButton
onPress={() => {
chooseFile('photo');
}}
text={'Add Image'}
/>
const chooseFile = type => {
let options = {
mediaType: type,
maxWidth: 300,
maxHeight: 550,
quality: 1,
};
launchImageLibrary(options, response => {
if (response.didCancel) {
showError('User cancelled camera picker');
return;
} else if (response.errorCode == 'camera_unavailable') {
showError('Camera not available on device');
return;
} else if (response.errorCode == 'permission') {
showError('Permission not satisfied');
return;
} else if (response.errorCode == 'others') {
showError(response.errorMessage);
return;
}
setFilePath(response.assets);
});
};
i get the image uri from API . i have showed it in return but it shows me two picture the existing one and new one

well first you need to make a state and set it to true like this one
const [newImageSelected, setNewImageSelected] = useState(false)
when you pick a new image from image picker then set this state to
true
const chooseFile = type => {
let options = {
mediaType: type,
maxWidth: 500,
maxHeight: 500,
quality: 1,
};
launchImageLibrary(options, response => {
if (response.didCancel) {
showError('User cancelled camera picker');
return;
} else if (response.errorCode == 'camera_unavailable') {
showError('Camera not available on device');
return;
} else if (response.errorCode == 'permission') {
showError('Permission not satisfied');
return;
} else if (response.errorCode == 'others') {
showError(response.errorMessage);
return;
}
setFilePath(response.assets);
setNewImageSelected(true);
});
};
then in return write set the condition if image is already existed
then it only shows the one picture which you are getting from the. and
when you select the new image the existing image replaced with the new
one check the below code maybe it helps you:
{newImageSelected ? (
<FlatList
data={filePath}
keyExtractor={(item, index) => index}
renderItem={({item}) => {
setImage(item.fileName);
setImageUri(item.uri);
setImageType(item.type);
return (
<View>
<Image
source={{uri: item.uri}}
style={styles.imageStyle}
/>
</View>
);
}}
/>
) : (
<Image
source={{uri: `existing image URL`}}
style={styles.imageStyle}
/>
)}

To update your screen with your data , you need to use state
To understand how it works first refer this link so you can understand how it works and how you can use it
https://reactnative.dev/docs/state.html
After that you can check how flatlist work because as per your code , you are not much aware with react native ..
FlatList accept array as data not object
here you can refer documentation
https://reactnative.dev/docs/flatlist

Related

How to get previous selected rating in React Native

I'm working on a tours app which has a ratings component in the details screen, whenever an user votes it gets saved using a device token as ID, i need to make it work in a way that when i go back to the tours list and then click the on tour i already voted (or another one i haven't) it needs to show me the previous rating i gave, say if i gave it 3 stars i want to have those 3 stars painted the next time i click on said tour, or show 0 if i haven't rated yet. This is what im currently doing:
const [defaultRating, setdefaultRating] = useState(0);
const starImageFilled = 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/star_filled.png';
const starImageCorner = 'https://raw.githubusercontent.com/AboutReact/sampleresource/master/star_corner.png';
const CustomRatingBar = () => {
return (
<View style={styles2.customRatingBarStyle}>
{maxRating.map((item, key) => {
return (
<TouchableOpacity
activeOpacity={0.7}
key={item}
onPress={() => {
setdefaultRating(item);
attempVotation(detail, item)
previousRate.current = item;
console.log(previousRate.current)
}}>
<Image
style={styles2.starImageStyle}
source={
item <= defaultRating
? { uri: starImageFilled }
: { uri: starImageCorner }
}
/>
</TouchableOpacity>
);
})}
</View>
);
}
const attempVotation = (tour, votacion) => {
setIsLoadingVote(true);
wretch(`${Config.API_URL}${Endpoints.tourVotacion}`)
.post({
"TourId" : tour.Id,
"DeviceId" : deviceToken,
"Clasificacion" : votacion
})
.json((json) => {
setIsLoadingVote(false);
Alert.alert('Informacion', json, [
{text: 'OK'},
]);
})
.catch((error) => {
Alert.alert('Error', 'There was an error saving your rating, try again.', [
{text: 'OK'},
]);
setIsLoadingVote(false);
});
};
Right now everything works fine, i just need to do what i previously mentioned.

API call with React Native and axios

I'm new to React, what I'm trying to do is call my API with a GET request to change the status of an elevator to "Operational" and it's color status from red to green. The problem is that it doesnt seem to call the API and brings me back to my previous screen when I click CONFIRM.
the function for my call to the API looks like this
function ElevatorStatusScreen({navigation, route}) {
const { Elevator } = route.params;
const [elevatorStatus, setEleStatus] = React.useState(Elevator.status);
const [statusColor, setColorStatus] = React.useState('red');
// Call to the api to update the status of an elevator
const endtask = () => {
axios.get(`https://apilink/api/Elevators/update/${Elevator.id}/Operational`)
.then(response => {
if(response.status == 200){
Alert.alert('Status has been changed to Operational!')
setColorStatus('green')
setEleStatus('Operational');
}
})
}
return (
<ImageBackground
style={styles.background}
source={require('../assets/white.jpg')}
>
<Text style={styles.title}>Elevator: {Elevator.id}</Text>
<Text style={{ color: statusColor }}>{elevatorStatus}</Text>
{elevatorStatus === 'Stopped' ? (
<TouchableOpacity style={styles.endTask} onPress={() => endtask()}>
<Text style={styles.endText}>END TASK</Text>
</TouchableOpacity>
)
:
<TouchableOpacity style={styles.confirm} onPress={() => {
navigation.goBack()
}}>
<Text style={styles.endText}>CONFIRM</Text>
</TouchableOpacity>
}
</ImageBackground>
);
}
Not sure what I'm doing wrong. This is my endpoint in a C# project coming from my elevators controller. (I tested it and it works)
[HttpGet("update/{id}/{status}")]
public async Task<dynamic> test(string status, long id)
{
var elevator = await _context.elevators.FindAsync(id);
elevator.Status = status;
await _context.SaveChangesAsync();
return elevator;
}
the endpoint: //apilink/api/Elevators/update/1/Operational returns a JSON like this in my browser
{ "id":1, "status":"Operational", "columnId":1, "serialNumber":"666999990867" }
let me know if you need more code and thanks for your help.
The problem was that my elevatorStatus was 'offline' and NOT 'Stopped' in my database...sorry about that

TypeError: undefined is not an object (evaluating 'n._viewer.saveDocument')- React Native

I am getting TypeError: undefined is not an object (evaluating 'n._viewer.saveDocument') when I click on save button. I think the filepath to save document is not passing inside the overlay. I could be wrong. Can anyone tell me what am I doing wrong here?
render() {
var filepath;
if (this.props.dsType == "fileDocument") {
if (path == fileContent.value) {
filepath = path.uri;
} else {
<h1>Unable to render document.</h1>;
}
}
//value in filepath
console.info("filepath =", filepath);
return (
<View style={{ flex: 1 }}>
<DocumentView
//ref={(c) => this._viewer = c}
document={filepath}
onDocumentLoaded={path => {
console.info("The document has finished loading:", path);
}}
/>
<View style={styles.button}>
<Button
onPress={() => {
// Manual Save
this._viewer.saveDocument().then((filePath) => {
console.log('saveDocument:', filePath);
});
}}
title="Save"
/>
</View>
</View>
);
}
return null;
}
It seems you have commented out the line that should assign the viewer instance. As mentioned, that line should be uncommented so that this._viewer can be assigned a reference. If you are unsure, you can refer to the example code that is available on GitHub: https://github.com/PDFTron/pdftron-react-native/blob/e19b4970357f9ed2443696eb989f1c91c1905911/example/App.js#L82.

Using a local img in flatlist (React-Native)

My problem is probably very basic, but im new to programming.
Basically I want to see a flatlist with for each category the title and the img
This is my category constructor:
class Category{
constructor(id, title, catImg){
this.id = id;
this.title = title;
this.catImg = catImg;
}
}
these are my 3 categories:
export const CATEGORIES = [
new Category('c1', 'Studeren', require('../assets/studeren.png')),
new Category('c2', 'Wonen', require('../assets/wonen.png')),
new Category('c3', 'EersteVoertuig', require('../assets/voertuig.png'))
];
this is where I want to call the elements:
const CategoryGridTile = props => {
return(
<TouchableOpacity style = {styles.gridItem} onPress = {props.onSelect}>
<View >
<Text>{props.title}</Text>
</View>
<Image source ={props.catImg} style={‌{width: 150, height: 150}}/>
</TouchableOpacity>
);
};
It does work for the props.title part, but it doesnt for the props.catImg part
(Meaning I can see the title, but no image. I have tried to directly put the img path instead of props.catImg, and that works, but thats not how I want to do it)
EDIT: I figured this code is also needed to understand my mistake?
const CategoryScreen = props => {
const renderGridItem = (itemData) => {
return <CategotyGridTile
title ={itemData.item.title}
onSelect={() =>{
props.navigation.navigate({
routeName: 'CategorieVragen',
params: {
categoryId: itemData.item.id
}});
}}/>;
};
return(
<FlatList
data={CATEGORIES}
renderItem ={renderGridItem}
numColums = {2}
/>
)
}
you have to send CATEGORIES as props to CategotyGridTile
in CategoryScreen
return <CategotyGridTile
categories={CATEGORIES}
{...props}
/>
in CategoryGridTile
<Image source ={props.categories.catImg} style={‌{width: 150, height: 150}}/>

React native - open multiple modals one after the other inside for loop

I first make an Ajax call (to an API) which provides me some data, a list of achievements (array of objects). I would like to loop through this array, show the first achievement as a Modal and on click of a button close the modal then show the next one (next achievement) and so on.
Ajax call providing the data:
getAchievements = () => {
fetch(url + '/achievements', {
method: 'get',
headers: {
Accept: 'application/json',
'Content-type': 'application/json'
}
})
.then((data) => data.json())
.then((data) => {
this.props.addData({
achievements: data.achievements
})
if(this.props.store.achievements.length > 0) {
this.setState({
showAchievementModal: true
})
}
})
.catch((error) => {
console.error(error)
})
}
Here I show the modals:
render() {
return (
{this.state.showAchievementModal &&
<Modal
animationType={'fade'}
visible={this.props.store.isModalAchievementVisible}
>
{this.props.store.achievements.map((data,index)=>{
return(
<View key={index}>
<View style={styles.container}>
<Text>{data.title}</Text>
<Text>{data.description}</Text>
<TouchableOpacity onPress={this.closeModal}>
<Text>Collect</Text>
</TouchableOpacity>
</View>
</View>
)
})}
</Modal>
}
)
}
At the moment all the Modals open at the same time. How could I open them one after the other after clicking the Collect button?
This is the updated version of my code that works:
Initialising activeModalIndex in the constructor:
constructor(props) {
super(props)
this.state = {
activeModalIndex: 0
}
}
Get achievements:
getAchievements = () => {
if(this.props.store.achievements.length > 0) {
this.setState({
showAchievementModal: true,
activeModalIndex: 0,
})
}
}
Render function:
render() {
return this.props.store.achievements.map((data,index) => this.state.activeModalIndex === index &&
<Modal>
<View key={index}>
<View style={styles.container}>
<Text>{data.title}</Text>
<Text>{data.description}</Text>
<TouchableOpacity onPress={this.closeModal}>
<Text>Collect</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
)
}
Close Modal:
closeModal = () => {
const maxIndex = this.props.store.achievements.length - 1
const currentIndex = this.state.activeModalIndex
const isLastModal = currentIndex === maxIndex
const newIndex = isLastModal? -1: currentIndex +1
this.setState({
activeModalIndex: newIndex
})
}
The problem is that you have multiple Modals on your page and they all use the same boolean to check if they should be rendered. Initially, showAchievementModal is set to true, so all modals are rendered. Furthermore, after you set showAchievementModal to false in closeModal, it will permanently stay false, so no additional modals will get rendered.
render() {
return (
{this.state.showAchievementModal &&
<Modal
...
</Modal>
}
)
}
Instead of showAchievementModal you should be keeping track of index of active modal. So, after you fetch the list of achievements from your API, set the activeModalIndex to 0. After the user dismisses this first modal, set the activeModalIndex to 1 inside the closeModal method, then set it to 2 after the second modal is closed and so on.
Now, for every modal to correspond to a single achievement, we must map each element of the achievements array to a single Modal and conditionally render it only if its corresponding index is the active one.
render() {
const achievements = this.props.store.achievements;
const { activeModalIndex } = this.state;
return achievements.map((data, index) => activeModalIndex === index &&
<Modal key={index}>
<View>
<View style={styles.container}>
<Text>{data.title}</Text>
<Text>{data.description}</Text>
<TouchableOpacity onPress={this.closeModal}>
<Text>Collect</Text>
</TouchableOpacity>
</View>
</View>
</Modal>
)
}
When the users dismisses the currently active modal, simply increment the index of the active modal and the next modal will appear instead of the current one. If the new incremented value is equal or larger than the array length, nothing will get rendered, so no need to check for max index value before setting new state.
closeModal = () => {
this.setState(previousState => ({
activeModalIndex: previousState.activeModalIndex + 1,
}))
}
Also, please read about the dangers of setting index as key when rendering lists. If you happen to need ordering achievements by some value/priority and users can retrieve multiple pages of their achievements, it might cause rendering wrong components.

Categories