Get specific object in array on button click - javascript

I have to update an object in an array when I click on the button. But I can't select the object I clicked.
there is my git for better reading https://github.com/Azciop/BernamontSteven_P7_V2
Code:
data() {
return {
post: {
file: "",
content: "",
},
showModal: false,
showModifyPost: false,
user: {
firstname: "",
lastname: "",
_id: "",
},
};
},
this is the get function
getAllPost() {
axios
.get('http://127.0.0.1:3000/api/post')
.then((response) => {
console.log("getPosts", response.data);
this.post = response.data;
}).catch(error => {
console.log(error);
})
},
this is the update post function
updatePost(id) {
const formData = new FormData();
formData.append("image", this.post[1].file);
formData.append("content", this.post[1].content);
axios.put('http://127.0.0.1:3000/api/post/' + id, formData,
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
'Content-Type': 'application/json',
},
})
.then(response => {
console.log(response);
location.reload("/accueil");
}).catch(e => {
console.log(e);
}
)
},
and this is the html with the v-for to display and the modify part
<div class="post" :key="post._id" v-for="post in post">
<!-- update a post -->
<button #click="showModifyPost = true" v-if="post.userId == user._id || user.isAdmin == true"
class="button button-modify-post">Modifier</button>
<transition name="fade" appear>
<div class="modal-overlay" v-if="showModifyPost" #click="showModifyPost = false"></div>
</transition>
<transition name="slide" appear>
<div class="modifiyPostModal" v-if="showModifyPost">
<span>
<h2 class="center-text">Modifier votre publication</h2>
<div class="close-post_button" #click="showModifyPost = false">
<font-awesome-icon class="close_create_post" icon="fa-solid fa-circle-xmark" />
</div>
</span>
<form enctype="multipart/form-data">
<div>
<input class="textPost" name="createPost" placeholder="Quoi de neuf ?"
v-model="post.content" />
</div>
<div class="center-sendbutton">
<input type="file" class="publishPost" id="changePicture" v-on:change="selectFile" ref="file" />
<button type="submit" v-on:click.prevent="updatePost(post._id)" class="publishPost">Modifier</button>
</div>
</form>
</div>
</transition>
This is the create Function
selectFile() {
this.posts.file = this.$refs.file.files[0];
},
// create post
async submitCreatePost() {
const formData = new FormData();
formData.append('image', this.posts.file);
formData.append('content', this.posts.content);
formData.append('firstname', localStorage.getItem("firstname"));
formData.append('lastname', localStorage.getItem("lastname"));
formData.append('userId', localStorage.getItem("userId"));
await axios.post("http://127.0.0.1:3000/api/post",
formData,
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
}
}).then(
console.log(formData),
this.content = "",
this.file = "",
).then((response) => response.status >= 200 || response.status <= 201 ?
location.reload(true) : console.log(response.statusText))
.catch(error => console.log(error));
},
but when i update it, it does update the object 1 (because it's the one selected in the js function)
i'd like to know how can i do to select the object i clicked. Thanks

Can you try this
export default {
created(){
this.getAllPost()
},
data(){
return{
posts: [],
post: {
file: "",
content: "",
},
showModal: false,
showModifyPost: false,
user: {
firstname: "",
lastname: "",
_id: "",
},
}
},
methods:{
getAllPost() {
axios
.get('http://127.0.0.1:3000/api/post')
.then((response) => {
console.log("getPosts", response.data);
this.posts = response.data;
}).catch(error => {
console.log(error);
})
},
updatePost(id) {
//the find part
const postToBeFound=this.posts.find((post)=>post._id===id)
console.log(postToBeFound)
const formData = new FormData();
formData.append("image", postToBeFound.file);
formData.append("content", postToBeFound.content);
axios.put('http://127.0.0.1:3000/api/post/' + id, formData,
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
'Content-Type': 'application/json',
},
})
.then(response => {
console.log(response);
location.reload("/accueil");
}).catch(e => {
console.log(e);
}
)
}
}
}
Error is happening at
formData.append("image", this.post[1].file);
formData.append("content", this.post[1].content);
since post is an object post[1] will give error. In my original answer also I made the fix
formData.append("image", postToBeFound.file);
formData.append("content", postToBeFound.content);

found a way to do it, don't know if it the right way but it works so...
when i click on the modify button i store the current post's id in the local storage and then i do this.
updatePost() {
const thisPostId = localStorage.getItem("ThisPostId")
let formData = new FormData();
formData.append("image", this.post.file);
formData.append("content", this.post.content);
axios.put('http://127.0.0.1:3000/api/post/' + thisPostId, formData,
{
headers: {
Authorization: "Bearer " + localStorage.getItem("token"),
"Content-Type": "multipart/form-data",
},
})
.then(response => {
this.posts = response.data;
this.getAllPost();
this.showModifyPost = false
}).catch(e => {
console.log(e);
}
)
},

Related

Processing formData from alpine js form

I have the following html
<div class="row" x-data="pageState()" x-init="mounted()">
<form method="post" enctype="multipart/form-data" #submit.prevent="postFormData()">
<div class="col-sm-4 p-2"><label>First Name</label><input x-model="form.firstname" name="firstname" type="text" required /></div>
<div class="col-sm-4 p-2"><label>Second Name</label><input x-model="form.secondname" name="secondname" type="text" required /></div>
<div class="col-sm-4 p-2"><label>Images</label><input name="images" type="file" x-on:change="selectFile($event)" accept="image/png, image/jpg, image/jpeg" multiple required /></div>
<button class="btn btn-primary mt-5">Submit Form Data</button>
</form>
</div>
and alpine js code
<script>
function pageState(){
return {
form: {
firstname: '',
secondname: '',
},
selectFile(event) {
this.form.images = event.target.files[0];
},
postFormData(){
//Create an instance of FormData
const data = new FormData()
let url = 'http://localhost:8000/alpine_form'
// Append the form object data by mapping through them
Object.keys(this.form).map((key, index) => {
data.append(key, this.form[key])
});
fetch(url, {
method: 'POST',
/**
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
*/
body: data
})
.then(response => {
console.log(response);
})
.finally(() => {
});
/**
axios.post('https://eot1ip4i6xwine.m.pipedream.net', {
firstname: this.firstname,
secondname: this.secondname
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
*/
},
mounted(){
this.$watch('form.firstname', (value, oldValue) => this.form.firstname = value);
this.$watch('form.firstname', (value, oldValue) => console.log(value, oldValue));
console.log('mounted');
}
}
}
</script>
In the backend i have this laravel code
public function alpine_form(Request $request){
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST');
header("Access-Control-Allow-Headers: X-Requested-With");
$data = $request->all();
$firstname = $data['firstname'];
$secondname = $data['secondname'];
$images = $data['images'];
$ai = '';
$uploaded_images_array = [];
//images
if($request->hasfile('images'))
{
foreach($request->file('images') as $fil)
{
$nam = mt_rand().uniqid().'.'.$fil->extension();
$fil->move(public_path().'/uploads/', $nam);
$uploaded_images_array[] = $nam;
}
$ai = json_encode($uploaded_images_array);
DB::table('form')->insert(
array(
'firstname' => $firstname,
'secondname' => $secondname,
'images' => $ai
)
);
}
}
I am able to receive firstname and secondname but he images array is always empty when i insert the data into the database. Am i acquiring the images posted correctly?
I appended my images like this
postFormData(){
//Create an instance of FormData
const data = new FormData()
data.append('firstname', this.form.firstname);
data.append('secondname', this.form.secondname);
let input_file = document.querySelector('input[type="file"]')
Array.from(input_file.files).forEach((f) => {
data.append('images[]', f)
})
let url = 'http://localhost:8000/alpine_form'
fetch(url, {
method: 'POST',
/**
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
*/
body: data
})
.then(response => {
console.log(response);
})
.finally(() => {
});
},
and no other modification was necessary.

React Redux Thunk with callback to another function -- TypeError: Cannot read property 'then' of undefined

I am using react+redux.
I have a modal form with data and images and on success I need to close the modal else display error returned from redux. In the dispatch function I have 1 more callback function to store images to S3. I am returning promise from the redux-thunk but I keep getting "TypeError: Cannot read property 'then' of undefined".
Component
handleSubmit = e => {
e.preventDefault();
if(this.isFieldEmpty()){
this.setState({ message: "All fields are mandatory with at least 1 pic" });
return;
} else {
this.setState({ message: "" });
}
const data = {
name: this.state.name,
description : this.state.description,
points : this.state.points,
attributes : this.state.attributes,
images : this.state.images,
created_by: localStorage.getItem('id'),
}
this.props.createItem(data).then(() => {
this.hideModal();
})
}
const mapDispatchToProps = dispatch => {
return {
createItem: data => {
return dispatch(createItem(data))
},
};
};
Action
const saveItemImages = (images,successcb, failurecb) => {
if(images.length > 0){
const formData = new FormData();
for(var x = 0; x<images.length; x++) {
formData.append('image', images[x])
}
const token = localStorage.getItem('token');
fetch(`${backendUrl}/upload/item-images/`, {
method: "POST",
headers: {
'Authorization': `Bearer ${token}`
},
credentials: 'include',
body: formData
})
.then(res => {
if(res.status === 200){
res.json().then(resData => {
successcb(resData.imagesUrl);
});
}else{
res.json().then(resData => {
failurecb(resData.message);
})
}
})
.catch(err => {
console.log(err);
});
} else {
successcb([]);
}
}
export const createItem = data => { return (dispatch) => {
saveItemImages(data.images, imagesUrl => {
data.images = imagesUrl;
return fetch(`${backendUrl}/admin/createItem`, {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'Authorization': `Bearer ${data.token}`
},
credentials: 'include',
body: JSON.stringify(data)
})
.then(res => {
if(res.status === 200){
res.json().then(resData => {
dispatch({
type: ADMIN_CREATE_ITEM_SUCCESS,
payload: resData
})
return true;
});
}else{
console.log("Save failed");
res.json().then(resData => {
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: {
message: resData.message
}
})
})
}
})
.catch(err => {
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: {
message: `Internal Error -- ${err}`
}
})
});
}, failedMessage => {
let payload = {responseMessage: failedMessage}
dispatch({
type: ADMIN_CREATE_ITEM_FAILED,
payload: payload
})
});
};
};
Thanks in advance for any help
You should return a Promise to create async flow for the action like this:
export const createItem = data => dispatch => new Promise((resolve, reject) => {
// do something was a success
resolve();
// do something was a fail
reject();
});

fetch api always getting fields are blank

I am trying to login using PHP in react native so I am using fetch api but when I try to login it's always saying fields are blank whereas it's not. Can somebody help me with this?
Code:
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
Username: '',
Password: '',
}
}
login = () => {
const {
Username,
Password
} = this.state;
var payload = {
username: Username,
password: Password
};
this.state[payload];
var data = new FormData();
data.append("json", JSON.stringify(payload));
fetch("http://example.com/api.php", {
method: 'POST',
header: {
'Accept': 'application/json',
'Content-type': 'application/json'
},
body: data
})
.then(function(res) {
return res.json();
})
.then(function(data) {
alert(JSON.stringify(data))
})
.catch((error) => {
console.error(error);
});
}
}
Text input:
<TextInput
style={styles.input}
placeholder={'Username'}
placeholderTextColor={'#fff'}
underlineColorAndroid='transparent'
onChangeText={Username => this.setState({ Username })}
/>
<TextInput
style={styles.input}
placeholder={'Password'}
secureTextEntry={this.state.showPass}
placeholderTextColor={'#fff'}
underlineColorAndroid='transparent'
onChangeText={Password => this.setState({ Password })}
/>
If the name and password status value are not empty, try this.
let data = new FormData();
data.append("username", this.state.Username);
data.append("password", this.state.Password);
fetch("http://example.com/api.php",{
method: 'post',
headers: {
'Accept': 'application/json',
'Content-Type': 'multipart/form-data',
},
body: data
}).then((response) => response.json())
.then((res) => {
console.log(res);
}).catch(err => {
console.log(err)
})
});
OR
If you're trying to get him to JSON:
fetch("http://example.com/api.php",{
method: 'post',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username: this.state.Username,
password: this.state.Password,
}),
}).then((response) => response.json())
.then((res) => {
console.log(res);
}).catch(err => {
console.log(err)
})
});
Since you are sending a request of type application/json, you should send the data directly as a JSON string:
var data = JSON.stringify(payload);

React - sending the correct data to server and get error

I'm trying to create a login in react-native. For that I send the user info to the webservice. if the info is correct the server will return a json
The problem is that I send the correct user info to the server and I get an error message as if I put the incorrect info
But when I test with Postman with the same info I dont get any error message
constructor
constructor() {
super()
this.state = {
showPass: true,
press: false,
username: "",
password: ""
}
}
function that fetch the data
checkLogin = () => {
const { username, password } = this.state;
var url = 'https://xxxxxxx/xxxx/xxxx/xxxx/auth/login'
fetch(url, {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
username, password
})
})
.then((response) => response.json())
.then((responseJson) => {
if (!responseJson.errors) {
this.props.navigation.navigate('foto');
console.log(username + " 1");
console.log(password + " 1");
} else {
Alert.alert('Error', responseJson.message, [{
text: 'Fechar'
}]);
console.log(username + " 2");
console.log(password + " 2");
}
})
.catch((error) => {
console.error(error);
})
Inputs
<TextInput onChangeText={text => this.setState({ username: text })} />
<TextInput onChangeText={text => this.setState({ password: text })} />
<TouchableOpacity style={Style.btnLogin} onPress={() => this.checkLogin()} >
<Text style={Style.textoLogin}>Entrar</Text>
</TouchableOpacity>
JSON that I get from Postman with the same info from the input
{
"errors": false,
"type": "-",
"line": "-",
"message": "Login successfully!",
"user": {
"user_id": 2,
"name": "xxxxxxx",
"username": "xxxxxxxx",
"email": "xxxxx#xxxxx.pt"
},
"_token": "xxxxxxxxxxx"
}
So I solved my problem, I had to change my body to a FormData()
Here is the code:
checkLogin = () => {
var url = 'https://xxxxx/xxxx/xxx/xxx/auth/login';
const { username, password } = this.state;
/*const username1 = this.state.username;
const password1 = this.state.password;
var data = {
"username" : this.state.username,
"password" : this.state.password
}*/
var formData=new FormData();
formData.append('username', username);
formData.append('password',password);
fetch(url, {
method: 'POST',
// body: JSON.stringify(data)
body: formData
})
.then((response) => response.json())
.then((responseJson) => {
if (!responseJson.errors) {
this.storeData(JSON.stringify(responseJson.user), responseJson._token)
this.props.navigation.navigate('foto');
} else {
Alert.alert('Error', responseJson.message, [{
text: 'Fechar'
}]);
}
})
.catch((error) => {
console.error(error);
})

How to post image with fetch?

I just learning react and I create an gallery App, but I have problem with posting picture to API. The problem is that when I click on button ADD there's nothing happend just in console.log I get an error 500.
Here is my component with post request:
class AddPhoto extends Component {
constructor(props) {
super(props);
this.state = {
modal: false,
images: [],
isLoading: false,
error: null,
};
this.toggle = this.toggle.bind(this);
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
toggle() {
this.setState({
modal: !this.state.modal
});
}
handleClick(event) {
event.preventDefault();
this.setState({
modal: !this.state.modal
});
}
handleSubmit(event){
event.preventDefault();
this.setState({ isLoading: true });
let path = this.props.path;
fetch(`http://.../gallery/${path}`, {
method: 'POST',
headers: {'Content-Type':'multipart/form-data'},
body: new FormData(document.getElementById('addPhoto'))
})
.then((response) => response.json())
.then((data)=>{
this.setState({images: data.images, isLoading: false});
this.props.updateImages(data.images);
})
.catch(error => this.setState({ error, isLoading: false}));
}
render() {
return (
<Card className="add">
<div className="link" onClick={this.toggle}>
<CardBody>
<CardTitle>Add picture</CardTitle>
</CardBody>
</div>
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
<div className="modal-header">
...
</div>
<ModalBody>
<form className="addPhotoForm" id="addPhoto" onSubmit={this.handleSubmit}>
<input type="file" required />
<Button color="success" type="Submit">Add</Button>
</form>
</ModalBody>
</Modal>
</Card>
);
}
}
Do you have any idea what am I doing wrong, why is not working, why I get error 500?
Thanks for helping me.
according to this https://muffinman.io/uploading-files-using-fetch-multipart-form-data it works in different way, at least for me it works as well.
const fileInput = document.querySelector('#your-file-input') ;
const formData = new FormData();
formData.append('file', fileInput.files[0]);
const options = {
method: 'POST',
body: formData,
// If you add this, upload won't work
// headers: {
// 'Content-Type': 'multipart/form-data',
// }
};
fetch('your-upload-url', options);
You should remove the 'Content-Type': 'multipart/form-data' and it started to work.
This is part of my upload component.
Look how i do it, you can modify it, with upload button, if you need.
addFile(event) {
var formData = new FormData();
formData.append("file", event.target.files[0]);
formData.append('name', 'some value user types');
formData.append('description', 'some value user types');
console.log(event.target.files[0]);
fetch(`http://.../gallery/${path}`, {
method: 'POST',
headers: {'Content-Type': 'multipart/form-data'},
body: {event.target.files[0]}
})
.then((response) => response.json())
.then((data) => {
this.setState({images: data.images, isLoading: false});
this.props.updateImages(data.images);
})
.catch(error => this.setState({error, isLoading: false}));
}
render() {
return (
<div>
<form encType="multipart/form-data" action="">
<input id="id-for-upload-file" onChange={this.addFile.bind(this)} type="file"/>
</form>
</div>)
}
This worked fine for me, just try it:
var myHeaders = new Headers();
myHeaders.append("Accept", "application/json");
myHeaders.append("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJh");
var formdata = new FormData();
formdata.append("image", fileInput.files[0], "Your_iamge_URL");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: formdata,
redirect: 'follow'
};
fetch("YOUR_API_ToCall", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
If you need to send a request with more attributes than the image use:
document.getElementById('inputPhoto').addEventListener('change', (e) => {
let data = new FormData();
const image = e.target.files[0];
data.append('id', 'sendIDHere');
data.append('name', 'sendNameHere');
data.append('image', image);
fetch('/apiToReceiveImage', {
method: 'POST',
body: data
}).then(async (_res) => {
const result = await _res.json();
console.log(result);
});
});
Remember that all attributes should be appended BEFORE the image

Categories