Using Vue, Inertia, Laravel, how do I update a file object in an edit component? - laravel

I currently have an edit page, which hits an update function to update the Itinerary object when changed.
On this page, if I click submit straight away, and dd() the $request from the ItineraryController, it returns all of the existing form data, as expected.
If I edit the data in the fields, then submit it, it returns successfully with a full request object as expected.
If, however, I choose a file in the "replace file" selector, the entire request object shows as null when the form is submitted, and thus can't be submitted.
How can I adjust this so that the "replace file" input is operational, and fills the request object with the existing itinerary data?
Component:
<template>
<form #submit.prevent="submit">
<div class="row w-75 m-auto">
<h1>Edit Itinerary</h1>
<div class="col-md-6">
<label for="title">Title</label>
<input v-model="form.title" class="form-control" name="title" placeholder="Itinerary Title" type="text" />
</div>
</div>
<div class="row w-75 m-auto">
<div class="col-md-6">
<label for="gen_narrative">Narrative</label>
<textarea v-model="form.gen_narrative" class="form-control" name="gen_narrative" placeholder="Itinerary Narrative"></textarea>
</div>
</div>
<div class="row w-75 m-auto">
<div class="col-md-6">
<label>Current Photo</label>
<img :src="assetUrl(props.itinerary.f_photo)" alt="featured photo" />
</div>
</div>
<br />
<div class="row w-75 m-auto">
<div class="col-md-6">
<label for="f_photo">Replace Photo</label>
<input class="form-control" name="f_photo" type="file" #input="fileChange" />
</div>
</div>
<div class="row w-75 m-auto">
<div class="col-md-6">
<label for="authorid">Author Name</label>
<input v-model="form.authorid" class="form-control" name="authorid" placeholder="Author Name" type="text" />
</div>
</div>
<div class="row w-75 m-auto">
<div class="col-md-6">
<button class="btn btn-primary" type="submit">Edit Itinerary</button>
</div>
</div>
</form>
</template>
<script setup>
import { useForm } from "#inertiajs/inertia-vue3";
function assetUrl(path) {
return process.env.MIX_BASE_URL + "storage/" + path;
}
function fileChange(event) {
form.f_photo = event.target.files[0];
}
let props = defineProps({
itinerary: {
type: Object,
required: true,
},
});
let form = useForm({
title: props.itinerary.title,
gen_narrative: props.itinerary.gen_narrative,
f_photo: null,
authorid: props.itinerary.authorid,
stops: props.itinerary.stops,
});
let submit = () => {
console.log(form.title);
form.patch("/itineraries/" + props.itinerary.id);
form.reset();
};
console.log(form);
</script>
<style scoped></style>
Controller:
public function edit($id)
{
$itinerary = Itinerary::find($id);
return Inertia::render('Itineraries/Edit', [
'itinerary' => $itinerary,
]);
}
public function update(Request $request, $id)
{
$itinerary = Itinerary::find($id);
$itinerary->title = $request->title;
$itinerary->gen_narrative = $request->gen_narrative;
//upload the photo
if ($request->hasFile('f_photo')) {
$itinerary->f_photo = $request->f_photo->store('public/itinerary_photos');
}
$itinerary->authorid = $request->authorid;
$itinerary->save();
return redirect('/itineraries');
}

let form = useForm({
forceFormData: true,
title: props.itinerary.title,
gen_narrative: props.itinerary.gen_narrative,
f_photo: null,
authorid: props.itinerary.authorid,
stops: props.itinerary.stops
})

The best I can come up with is writing your file upload inline
<div class="row w-75 m-auto">
<div class="col-md-6">
<label for="f_photo">Replace Photo</label>
<input class="form-control" name="f_photo" type="file" #input="form.f_photo = event.target.files[0]"/>
</div>
</div>

Based on this example in official documentation you can do
<input type="file" #input="form.f_photo = $event.target.files[0]" />

Your issue is probably because Inertia does not natively support uploading files using a multipart/form-data request for the put, patch or delete methods, as is stated here (in the "Multipart limitations" section).
An alternative way is to submit without form helper using post method with the _method attribute of 'put', like:
Inertia.post("/itineraries/" + props.itinerary.id", {
_method: 'put',
f_photo: form.f_photo,
})

Related

Laravel upload image using AJAX POST method

I tried to upload an image into the form using ajax method, here the my form code in blade file:
<form action="#" id="form" enctype='multipart/form-data' class="form-horizontal">
{{ csrf_field() }}
<div class="modal-header">
<h4 class="modal-title">Data Form</h4>
</div>
<div class="modal-body">
<div class="form-body">
<div class="form-group">
<label class="control-label col-md-4">Description</label>
<div class="col-md-8">
<input name="description" id="description" class="form-control" type="textarea">
<small class="errorDescription hidden alert-danger"></small>
</div>
</div>
<div class="form-group">
<label class="control-label col-md-4">Price</label>
<div class="col-md-8">
<input name="price" id="price" class="form-control" type="number">
<small class="errorPrice hidden alert-danger"></small>
</div>
</div>
<div class="form-group">
<input type="file" name="image" id="image">
</div>
</div>
</div>
</form>
And the Ajax POST method is:
function save()
{
var url;
url = "{{ URL::route('editor.data-wh.store') }}";
$.ajax({
type: 'POST',
url: url,
data: {
'description': $('#description').val(),
'price': $('#price').val(),
'image': $('#image').val()
},
success: function(data) {
console.log(data);
}
}
}
And here my controller:
public function store(Request $request){
// if request has file
if($request->hasFile('image')){
$filenameWithExt=$request->file('image')->getClientOriginalName();
$filename=pathinfo($filenameWithExt,PATHINFO_FILENAME);
$extension=$request->file('image')->getClientOriginalExtension();
$fileNameToStore= date('mdYHis') . uniqid() .$filename.'.'.$extension;
request()->image->move(public_path('img'), $fileNameToStore);
}else{
$fileNameToStore='no-image.jpeg';
}
$post = new WhData();
$post->description = $request->description;
$post->price = $request->price;
$post->image=$fileNameToStore;
$post->save();
return redirect()->back();
}
But the data never save the uploaded image to the DB, the Database always stored no-image.jpeg (my else condition in controller) for image value. Here my form request in the Header request data in browser console:
description: Watermelon
price: 45
image: C:\fakepath\thumbnail.jpg
Almost 3 days now to solved this and look over the net too, but still no luck. Any idea how to solved this?
Thanks,
You could just change the data with data:new FormData(document.getElementById('form'));
This way you can send binary files (files) to the server.

How to show specific image from the database when doing a edit function in a vue component?

I'm making a SPA using laravel and vue. I dont know how to show the specific image of the news when Im making a update/edit function. In laravel I know how to do it by using a #foreach and asset something like that. But in the vue component I'm having a hard time figuring it out. I'm using the vform package btw so that my form is filled automatically with the data which I want to edit but the my problem is how to show the image like i filled the text field by using fill function from the vform package. What do I need to do in order to fix my problem?
News.vue
<!-- show/edit modal extra large -->
<div class="modal fade" id="editNews" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h4> <strong>Edit</strong> </h4>
</div>
<div class="modal-body">
<!-- Vform -->
<form #submit.prevent="updateNews()">
<div class="form-group">
<label>News Title</label>
<input
v-model="form.title"
type="text" name="title"
placeholder="Title"
class="form-control" :class="{ 'is-invalid': form.errors.has('title') }">
<has-error :form="form" field="title"></has-error>
</div>
<div class="form-group">
<label>Subtitle</label>
<input
v-model="form.subtitle"
type="text"
name="subtitle"
placeholder="Subtitle"
class="form-control" :class="{ 'is-invalid': form.errors.has('subtitle') }">
<has-error :form="form" field="subtitle"></has-error>
</div>
<div class="form-group">
<label>News Content</label>
<textarea
v-model="form.body"
type="text"
name="body"
placeholder="News Content"
class="form-control" :class="{ 'is-invalid': form.errors.has('body') }">
</textarea>
<has-error :form="form" field="body"></has-error>
</div>
<div class="form-group">
<label>Picture</label>
<input type="file" id="image" #change="addImage"
class="form-control" :class="{ 'is-invalid': form.errors.has('image') }">
<has-error :form="form" field="image"></has-error>
</div>
<div>
<h4>Currently Displayed News Image</h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-success">Submit Changes</button>
</div>
</form>
<!-- vform -->
</div>
</div>
</div>
</div>
<!-- modal edit/show -->
The script below the News.vue
<script>
export default {
data(){
return{
editmode:false,
news: {},
form: new Form({
id:"",
title: "",
subtitle:"",
body:"",
image:"",
postedby:""
})
}
},
methods: {
loadNews(){
axios.get('api/news')
.then(({data}) => (this.news = data))
},
createNews(){
// console.log('hello')
this.$Progress.start()
this.form.post("api/news")
.then(()=>{
$("#addNews").modal("hide")
$(".modal-backdrop").remove()
swal.fire("Created!", "", "success")
Fire.$emit("UpdateTable");
})
this.$Progress.finish()
},
addImage(e){
// console.log(e.target.files[0])
var fileReader = new FileReader()
fileReader.readAsDataURL(e.target.files[0])
fileReader.onload = (e) => {
this.form.image = e.target.result
}
// console.log(this.form)
},
editForm(newsdata){
//shows the modal for edit and fills the data in it.
this.editmode = true
this.form.reset()
$('#editNews').modal('show')
this.form.fill(newsdata)
},
updateNews(){
//update the news based on the modal inputs (not working need few codes in controller #update method)
this.form.put('api/news/' + this.form.id)
.then(()=>{
$('#editNews').modal('hide')
$(".modal-backdrop").remove()
swal.fire("Updated!", "", "success")
Fire.$emit('UpdateTable')
this.$Progress.finish()
})
},
},
created() {
console.log('Component mounted.')
this.loadNews();
Fire.$on("UpdateTable",()=>{
this.loadNews();
})
}
}
</script>
Add this for img:
<img src="" id="imagepreview">
Then you can simply do:
$('#imagepreview').attr('src', "IMAGEDIRECTORYHERE" + newsdata.image);

How to set if else statement in script

-I wan't to do like this: if(!editMode) show create page else show update page because my create and edit using same form so I combine it.
-I'm learning online tutorial but the tutorial show create and edit seperately.
-Please Helps and Thank/.\
<template>
<div v-if="!edit">
<h1>Create Post</h1>
<form #submit.prevent="addPost">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Title:</label>
<input type="text" class="form-control" v-model="post.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Body:</label>
<textarea class="form-control" v-model="post.body" rows="5"></textarea>
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Create</button>
</div>
</form>
</div>
<div v-else>
<h1>Update Post</h1>
<form #submit.prevent="updatePost">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Title:</label>
<input type="text" class="form-control" v-model="post.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Body:</label>
<textarea class="form-control" v-model="post.body" rows="5"></textarea>
</div>
</div>
</div><br />
<div class="form-group">
<button class="btn btn-primary">Update</button>
</div>
</form>
</div>
</template>
<script>
export default {
data(){
return {
edit:false,
post:{}
}
},
},
//this is for create
methods: {
addPost(){
let uri = 'http://localhost:8000/post/create';
this.axios.post(uri, this.post).then((response) => {
this.$router.push({name: 'posts'});
});
},
},
//this is for get data before update
created() {
let uri = `http://localhost:8000/post/edit/${this.$route.params.id}`;
this.axios.get(uri).then((response) => {
this.post = response.data;
});
},
//this is for update post
updatePost() {
let uri = `http://localhost:8000/post/update/${this.$route.params.id}`;
this.axios.post(uri, this.post).then((response) => {
this.$router.push({name: 'posts'});
});
}
</script>
**I also set this in my app.js**
{
name: 'create',
path: '/create',
component: PostForm,
props: {editMode: false}
},
{
name: 'edit',
path: '/edit/:id',
component: PostForm,
props: {editMode: true}
}
My Error--->when I press edit btn show create page and using addPost function.
Result--> how to use if else to solve this.... Sorry I'm rookie in programming.
I believe you can simply have the js figure out the add or update.
<template>
<div>
<h1 v-if="!edit">Create Post</h1>
<h1 v-else>Update Post</h1>
<form #submit.prevent="postSomething">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Title:</label>
<input type="text" class="form-control" v-model="post.title">
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label>Post Body:</label>
<textarea class="form-control" v-model="post.body" rows="5"></textarea>
</div>
</div>
</div><br />
<div class="form-group">
<button v-if="!edit" class="btn btn-primary">Create</button>
<button v-else class="btn btn-primary">Update</button>
</div>
</form>
</div>
</template>
and the js:
methods: {
postSomething(){
if(!this.edit){
this.addPost()
}else{
this.updatePost()
}
},
addPost(){
console.log('should add')
},
updatePost(){
console.log('should update')
}
}

Laravel : Insert data into database using Bootstrap Modal

I want to insert some data into database using Bootstrap Modal. But the problem is Save button doesn't work properly on Bootstrap Modal as I couldn't insert the data into database through form. If anyone could help me to find it please!?
Here is the form part in blade:
<div id="myAlert" class="modal hide">
<div class="modal-header">
<button data-dismiss="modal" class="close" type="button">×</button>
<h3>Create User</h3>
</div>
<div class="modal-body">
<div class="row-fluid">
<div class="span12">
<div class="widget-box">
<div class="widget-content nopadding">
<form action="#" method="get" id="userForm" class="form-horizontal">
<div class="control-group">
<label class="control-label">Name :</label>
<div class="controls">
<input class="span11" placeholder="Name" type="text">
</div>
</div>
<div class="control-group">
<label class="control-label">Email :</label>
<div class="controls">
<input class="span11" placeholder="Email" type="email">
</div>
</div>
<div class="control-group">
<label class="control-label">Password</label>
<div class="controls">
<input class="span11" placeholder="Enter Password" type="password">
</div>
</div>
<div class="control-group">
<label class="control-label">Confirm Password</label>
<div class="controls">
<input class="span11" placeholder="Confirm Password" type="password">
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer"><a data-dismiss="modal" class="btn btn-primary" href="#">Confirm</a> <a
data-dismiss="modal" class="btn" href="#">Cancel</a>
</div>
</div>
Here is the Ajax Part :
$('#userForm').on('success.form.fv', function(e) {
e.preventDefault();
$.ajax({
method: 'POST',
action:"{{ url('/register') }}",
data: $form.serialize()
});
});
You need the submit button. Try to put this code inside your form.
<button type="submit" class="btn btn-primary">Register</button>
Problem with your current Confirm button is: 1) he don't have type=submit; 2) he is outside the form.
first of all add type="submit" to your button
secondly check your network tab in the dev tools in your browser and check the request does it go to /register or not ?
if the request is hitting /register what's the parameters ?
Change form method get to post
I answer here for ajax call
Laravel ajax internal servor 500 (internal server-error)
Your input type elements are missing name attribute
<input class="span11" placeholder="Name" name="name" type="text">
<input class="span11" placeholder="Email" name="email" type="email">
<input class="span11" placeholder="Enter Password" name="password" type="password">
<input class="span11" placeholder="Confirm Password" name ="confirm_password" type="password">
You then retrieve the content using Request or Input by passing the value of the name attribute
At first change your form method from get to post. Then add save button with id btnSave.
Ajax :
$("#btnSave").click(function(e){
e.preventDefault()
var $form = $("#userForm");
$.ajax({
type: $form.attr('method'),
url: $form.attr('action'),
data: $form.serialize(),
success: function (data, status) {
if(data.error){
return;
}
alert(data.success); // THis is success message
$('#myModal').modal('hide'); // Your modal Id
},
error: function (result) {
}
});
});
In controller :
public function store(Request $request)
{ try {
$inputs = $request->all();
ModelName::create($inputs);
$data = ['success' =>'Data saved successfully'];
} catch (\Exception $e) {
$data = ['error' =>$e->getMessage()];
}
return Response::json($data);
}
Form part in blade:
<div class="modal-footer"><a data-dismiss="modal" class="btn btn-primary" id="btnAdd">Confirm</a></div>
Ajax Part
$('#btnAdd').click(function () {
$.ajax({
url: '{{url('/register')}}',
type: 'POST',
data: $('#userForm').serialize(),
success: function (object) {
},
error: function (result) {
}
});
});

AJAX within a modal inserting a form in CodeIgniter

Been struggling with this for about 4 hours, I'm attempting to have a modal drop down (Twitter bootstrap modal) that contains a form to create a Company. This is built in CodeIgniter.
I'm having issues with input type="submit" and input type="button".
I only have 1 required field, which is Company Name. If I use input type="button", the validation will fire correctly inside of the modal, however the form will only INSERT just the company name, along with company_id, user_id, active, and cdate.
Now if I use input type="submit", all the data inserts fine. However, the validation breaks and I get a "Page cannot be found" after clicking "Create Company", the data is still inserting though.
Any ideas? Thanks! New to AJAX...
My AJAX function:
$(document).ready(function(){
$('#create_btn').live('click', function(){
//we'll want to move to page specific files later
var name = $('#name').val();
$.ajax({
url: CI_ROOT + "members/proposals/add_client",
type: 'post',
data: {'name': name },
complete: function(r){
var response_obj = jQuery.parseJSON(r.responseText);
if (response_obj.status == 'SUCCESS')
{
window.location = CI_ROOT + response_obj.data.redirect;
}
else
{
$('#error_message2').html(response_obj.data.err_msg);
}
},
});
});
});
My controller function which handles the insert:
function add_client()
{
$this->form_validation->set_rules('name', 'Company Name', 'trim|required|xss_clean');
load_model('client_model', 'clients');
load_model('industry_model');
$user_id = get_user_id();
$company_id = get_company_id();
if (!$user_id || !$company_id) redirect('home');
if ($_POST)
{
if ($this->form_validation->run() == TRUE)
{
$fields = $this->input->post(null , TRUE);
$fields['user_id'] = $user_id;
$fields['company_id'] = $company_id;
$fields['active'] = 1;
$fields['cdate'] = time();
$insert = $this->clients->insert($fields);
if ($insert)
{
$this->message->set('alert alert-success', '<h4>Company has been added</h4>');
header('location:'.$_SERVER['HTTP_REFERER']);
}
else
{
$this->message->set('alert alert-error', '<h4>There was an issue adding this Company, please try again</h4>');
}
}
else
{
$err_msg = validation_errors('<div class="alert alert-error">', '</div>');
$retval = array('err_msg'=>$err_msg);
$this->ajax_output($retval, false);
}
}
$this->data['industries'] = array(0=>'Select Industry...') + $this->industry_model->dropdown('industry');
$this->insertMethodJS();
$this->template->write_view('content',$this->base_path.'/'.build_view_path(__METHOD__), $this->data);
$this->template->render();
}
And finally, my view:
<div class="modal hide fade" id="milestone" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="width: 600px !important;">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h3 id="myModalLabel">Add a Company</h3>
</div>
<div class="modal-body">
<?php echo form_open_multipart(base_url().'members/proposals/add_client', array('class' => '', 'id' => 'client_form'));?>
<div id="error_message2"></div>
<div class="row-fluid">
<div class="span5">
<input type="hidden" name="cdate" id="cdate" value="" />
<div class="control-group">
<label class="control-label">Company Name: <span style="color: red;">*</span></label>
<div class="controls">
<input type="text" id="name" name="name" value=""/>
</div>
</div>
<div class="control-group">
<label class="control-label">Company Abbreviation:<span style="color: red;">*</span></label>
<div class="controls">
<input type="text" id="abbreviation" name="abbreviation" value=""/>
</div>
</div>
<div class="control-group">
<label class="control-label">Company Image: </label>
<div class="controls">
<input type="file" name="client_image" size="20" />
</div>
</div>
</div>
<div class="span5">
<div class="control-group">
<label class="control-label">Website:</label>
<div class="controls">
<input type="text" id="website" name="website" value=""/>
</div>
</div>
</div>
</div>
<div class="row-fluid">
<div class="span5" style="margin-top: 25px;">
<div class="control-group">
<div class="controls">
<p><strong>Client</strong></p>
</div>
</div>
<div class="control-group">
<label class="control-label">Address 1:</label>
<div class="controls">
<input type="text" id="address1" name="address1" value=""/>
</div>
</div>
<div class="control-group">
<label class="control-label">Address 2:</label>
<div class="controls">
<input type="text" id="address2" name="address2" value=""/>
</div>
</div>
<div class="control-group">
<label class="control-label">City:</label>
<div class="controls">
<input type="text" name="city" id="city" value=""/>
</div>
</div>
<div class="control-group">
<label class="control-label">State:</label>
<div class="controls">
<?= form_dropdown('state', usa_state_list(), set_value('state'), 'id=state'); ?>
</div>
</div>
<div class="control-group">
<label class="control-label">Zip:</label>
<div class="controls">
<input type="text" id="zip" name="zip" value=""/>
</div>
</div>
<div class="control-group">
<label class="control-label">Country:</label>
<div class="controls">
<?= form_dropdown('country', country_list(), set_value('country'), 'id=country'); ?>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
<button type="submit" class="btn btn-primary" id="create_btn">Create Company</button>
</div>
</form>
</div>
So again, to summarize. With input type="button", my validation works great within the modal and only the Company Name is inserting into the database along with company_id, user_id, active, and cdate.
Now, with input type="submit", all data inserts great, however validation fails and I get a redirect to a page cannot be found.
Again, thanks!
The issue is with your ajax function call.
You need to prevent the form from firing (and thus submitting via post to the url in action):
Change:
$('#create_btn').live('click', function(){
To:
$('#create_btn').live('click', function(e){
e.preventDefault();
This should fix the issue. If it doesn't, let me know and I'll do more digging. I would also recommend switching live to on so that you future-proof yourself. on handles the same stuff as live, bind, etc. in a single function with more efficiency.
Edit: To explain what's going on (and why you must use e.preventDefault();), it is because <input type="submit"> will actually submit the form to the url specified in the <form> tag's action attribute. Thus, what's happening with your code is that your javascript is running as soon as you click the button, and then the native browser submit event is occurring immediately afterwards.

Resources