Processing formData from alpine js form - javascript

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.

Related

Get specific object in array on button click

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);
}
)
},

How do I Add Text to a form pull

So I'm trying to make an API Fetch from a Form Input (The Search bar of my site), I Want to add Text to whatever was inputted to the Text Field and then send it trough to be pulled.
<form id="SearchBoxMainNav" style="display: flex;">
<input class="nav-button" type="submit" name="search" value="" >
<input id="SearchTerm" type="search" class="search" name="search" value="" placeholder="I Draw...!" autocomplete="off" />
</form>
Java Script
const apiUrl = 'https://db.ygoprodeck.com/api/v7/cardinfo.php';
SearchBoxMainNav.addEventListener('submit', async (event) => {
event.preventDefault();
const formData = new FormData(SearchBoxMainNav);
const formDataSerialized = Object.fromEntries(formData);
const jsonObject = { ...formDataSerialized};
console.log(formDataSerialized, "formDataSerialized");
try {
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify("fname" + jsonObject),
Headers: {
'Contnent-Type': 'application/json'
},
});
const json = await response.json();
console.log(json);
} catch(event) {
console.error(event)
alert("there was an Error")
}
});
so what I Would like to do is as they submit it Text is added to the Front and then It goes trough the whole javascript Prosccess
Concatenate the text with jsonObject.search, not jsonObject.
Object.fromEntries() returns a new object, there's no need to duplicate it with {...formDataSerialized}
const apiUrl = 'https://db.ygoprodeck.com/api/v7/cardinfo.php';
SearchBoxMainNav.addEventListener('submit', async(event) => {
event.preventDefault();
const formData = new FormData(SearchBoxMainNav);
const jsonObject = Object.fromEntries(formData);
jsonObject.search = 'fname ' + jsonObject.search;
try {
const response = await fetch(apiUrl, {
method: 'POST',
body: JSON.stringify(jsonObject),
Headers: {
'Content-Type': 'application/json'
},
});
const json = await response.json();
console.log(json);
} catch (event) {
console.error(event)
alert("there was an Error")
}
});

how can i submit form data and file using fetch in react?

At first, the task was set to send data from the form. The problem was solved in the following way:
export let useRequest = () => {
let request = async (url, method = "Post", body = null, headers = {}) => {
try {
if (body) {
body = JSON.stringify(body);
headers["Content-Type"] = "application/json";
}
let res = await fetch(url, { method, body, headers });
let data = await res.json();
return data;
} catch (e) {
throw e;
}
};
form:
<form>
<input name="name" class="help-input" placeholder="name" type="text" value=""/>
<input name="email" class="help-input" placeholder="email" type="text" value=""/>
<textarea name="message" class="help-input"placeholder="message"></textarea>
<input name="file" type="file" value="">
<input name="agree" type="checkbox" value="" checked/>
<button type="submit" onClick="props.send">send</button>
</form>
Form container(form wrapper):
export let HelpBlock = (props) => {
let { request } = useRequest();
let reqFromForm = async (values) => {
let data = await request("/api/message", "POST", props.values);
console.log(data.message)
};
return (
<>
<Form send={reqFromForm}></Form>
</>
);
};
After clicking on the button, data comes with the following structure:
{
name:name,
email:email,
message:message,
file:file
}
In this case I think that you can render the body according to the content type:
export let useRequest = () => {
let request = async (url, method = "Post", body = null, headers = {}, contentType="application/json" ) => {
try {
if (body) {
body = renderBodyFormat(body, contentType);
headers["Content-Type"] = contentType;
}
let res = await fetch(url, { method, body, headers });
let data = await res.json();
return data;
} catch (e) {
throw e;
}
};
return { request };
};
const renderBodyFormat = (data, type) => {
const formats = {
"application/json": ()=> JSON.stringify(body),
"multipart/form-data": ()=> {
const form = new FormData();
Object.keys(data).forEach(key => form.append(key, data[key]));
return form;
}
}
return formats[type]();
}
EDIT: //using the hook:
const Component = ()=> {
const {request} = useRequest();
useEffect(()=> {
const data = {
//...other props
file: new File(["file"], "file.txt", { type: "text/plain"});
}
request(url, "Post", data, {}, "multipart/form-data")
.then(()=> {
//...
})
})
}
Here you can find more info https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch

Vue and Laravel Form Validation not returning 422 response

I'm trying to validate form data on the backend with Laravel and Vue, but I'm not getting the 422 response.
This is in my controller function:
$this->validate($request, [
'name' => 'required',
'city' => 'required',
'state' => 'required'
]);
$location = $request->isMethod('put') ?
Locations::findOrFail($request->id) : new Locations;
$location->id = $request->input('id');
$location->name = $request->input('name');
$location->address = $request->input('address');
$location->city = $request->input('city');
$location->state = $request->input('state');
$location->zip = $request->input('zip');
$location->phone = $request->input('phone');
if($location->save())
{
return new LocationsResource($location);
}
Here is the Vue method:
addLocation() {
if (this.edit === false) {
// Add
fetch('api/location', {
method: 'post',
body: JSON.stringify(this.location),
headers: {
'content-type': 'application/json'
}
})
.then(res => res.json())
.then(data => {
this.clearForm();
alert('Location Added');
this.fetchArticles();
});
} else {
// Update
fetch('api/location', {
method: 'put',
body: JSON.stringify(this.location),
headers: {
'content-type': 'application/json'
}
})
.then(res => res.json())
.then(data => {
this.clearForm();
alert('Locations Updated');
this.fetchArticles();
})
}
}
Here is the form:
<form #submit.prevent="addLocation" class="mb-3">
<div class="form-group">
<input type="text" class="form-control" placeholder="Name" v-model="location.name">
<input type="text" class="form-control" placeholder="City" v-model="location.city">
<input type="text" class="form-control" placeholder="State" v-model="location.state">
</div>
<button type="submit" class="btn btn-light btn-block">Save</button>
</form>
When I open up the inspector and go into Network->XHR I get all the correct status codes back for CRUD, however when the form is supposed to fail I do not get back 422 HTTP status code. When I submit the form with no data, it doesnt save, but no status code gets sent, there is no response to give feedback to the user. Thanks for the help.
I had to add "accept": "application/json" to the header of the addLocation method.
$this->validate($request, [
'name' => 'required',
'city' => 'required',
'state' => 'required'
]);
I've never seen such usage. I don't think controller have the validate function. Try this:
$request->validate([
'name' => 'required',
'city' => 'required',
'state' => 'required'
]);
The following code what i have tried
const form_data = new FormData(document.querySelector('#form_data'));
fetch("{{route('url')}}", {
'method': 'post',
body: form_data,
}).then(async response => {
if (response.ok) {
window.location.reload();
}
const errors = await response.json();
var html = '<ul>';
for (let [key, error] of Object.entries(errors)) {
for (e in error) {
html += `<li>${error[e]}</li>`;
}
}
html += '</ul>';
//append html to some div
throw new Error("error");
})
.catch((error) => {
console.log(error)
});
Controller
use Illuminate\Support\Facades\Validator;//Use at top of the page
$rules = [
'file' => 'image|mimes:jpeg,png,jpg|max:1024',
'field1' => 'required',
'field2' => 'required'
];
$validator = Validator::make($request->post(), $rules);
if ($validator->fails()) {
return response()->json($validator->errors(), 400);
}
session()->flash('flahs', ['status' => 'status', 'message' => 'message']);

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