I'm working on a RestFulApi using Laravel and Vuejs, now want upload a photo using RestfulApi and vuejs. Here comes my sample code:
<div class="form-group form-group-default float-left required">
<label for="photo">Photo</label>
<input class="file-input" type="file" ref="photo" name="photo" v-
on:change="addFile($event)">
</div>
data(){
return{
films_info:
{
photo: null,
}
}
},
methods: {
addFile: function(e){
let that = this;
that.films_info.photo = this.$refs.photo.files[0];
},
saveFilms: function(){
let that = this;
axios.post('/api/films/save_films',that.films_info)
.then(function (response) {
location.reload(true);
})
.catch(function (error) {
that.errors = error.response.data.errors;
console.log("Error Here: "+error.response.data);
});
}
}
protected function saveFilms(Films $request)
{
if ( $request->photo ) {
$extension = $filmsObj->photo->getClientOriginalExtension();
$request->photo = 'films_'.\Carbon\Carbon::now().'.'.$extension; // renaming image
$request->photo->move($dir_path, $request->photo);
}
}
Here in this code I get error in getClientOriginalExtension() method call. It says:
getClientOriginalExtension() method called on string.
Finally I managed to solved the photo upload issue using VueJS and Laravel Api call.
<div class="form-group form-group-default float-left required">
<label for="file">File</label>
<input class="file-input" type="file" ref="file" name="file" v-
on:change="addFile($event)">
</div>
data(){
return{
films_info:
{
file: null,
}
}
},
methods: {
addFile(e){
this.films_info.file = this.$refs.file.files[0];
},
saveFilms(){
let formData = new FormData();
formData.append('file', this.films_info.file);
axios.post('/api/films/save_films',formData,{
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(response => {
location.reload(true);
})
.catch(error => {
that.errors = error.response.data.errors;
console.log("Error Here: "+error.response.data);
});
}
}
$dir_path = 'uploads/films/images';
$dir_path_resize = 'uploads/films/images/45x45';
if( $request ){
$filmsObj = new Film();
if (!File::exists($dir_path))
{
File::makeDirectory($dir_path, 0775, true);
}
if (!File::exists($dir_path_resize))
{
File::makeDirectory($dir_path_resize, 0775, true);
}
if ( $request->file ) {
$file = $request->file;
$extension = $file->getClientOriginalExtension(); // getting image extension
$file_name = 'films_'.\Carbon\Carbon::now().'.'.$extension; // renaming image
$file->move($dir_path, $file_name); // uploading file to given path
// Start : Image Resize
$image = Image::make(public_path($dir_path.'/'.$file_name));
// resize the image to a height of 45 and constrain aspect ratio (auto width)
$image->resize(null, 45, function ($constraint) {
$constraint->aspectRatio();
});
$image->save(public_path($dir_path_resize.'/'.$file_name));
// End : Image Resize
}
Related
My Code is below but it's not working. I can upload Image with base64 formate and successfully store on Laravel backend but I'm struggling to upload other file formates in Laravel and vue.js. Anyone can help please?
.vue file
<template>
<div>
<form enctype="multipart/form-data" #submit.prevent="handleSubmit">
<div class="form-group mb-4">
<label>Institute Prospectus</label>
<label class="custom-file-container__custom-file">
<input
type="file"
class="form-control-file"
#change="onChangeProspectus"
/>
</label>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
institute_prospectus: "",
};
},
methods: {
handleSubmit() {
let data = {
institute_prospectus: this.institute_prospectus,
};
axios.post(data, "/add-institute")
.then(() => {
console.log("Success");
})
.catch((err) => {
console.log(err);
});
},
onChangeProspectus(event) {
let file = event.target.files[0];
this.institute_prospectus = file.name;
},
},
};
</script>
InstituteController.php
public function add_institute(Request $request) {
$prospectus_file = $request->institute_prospectus;
if ($prospectus_file) {
$ext = substr($prospectus_file, strrpos($prospectus_file, '.', -1), strlen($prospectus_file));
$name = time().'-'.$slug.".".$ext;
$upload_path = 'backend/files/institute/';
$prospectus_url = $upload_path.$name;
$prospectus_file->move($upload_path,$prospectus_url);
}
}
I have my upload html form like this
<div class="album_single_data settings_data">
<div class="album_single_img">
<figure class="thumbnail thumbnail-rounded">
<img class="main-profile" :src="getprofilepicture()" alt="">
</figure>
</div>
<div class="album_single_text">
<div class="album_btn profile_image">
<div class="btn btn-primary">
<input class="settings-file-upload" type="file" #change="updateProfilePic" ref="file" accept="image/*">
<div class="settings-file-icon">
<span class="material-icons">camera_alt</span>
Upload Profile Picture. (Note: Must Be Less Than 2MB)
</div>
</div>
</div>
</div>
</div>
<div class="form-group">
<button #click="updateInfo" class="btn btn-primary">Update Profile</button>
</div>
This is the vuejs code that handles the form submit/upload method which means anytime i click on the upload button the image uploads. but the problem is that it does not submit
export default {
name: 'Settings',
components: {
//
},
data() {
return{
form: new Form ({
id: '',
username:'',
email: '',
password: '',
name: '',
bio: '',
twitter_handle: '',
facebook_handle: '',
instagram_handle: '',
backgroundPicture: ''
}),
pic: ({
profilePicture: '',
})
}
},
created(){
axios.get("profile")
.then(({ data })=>(this.form.fill(data)))
.then(()=>(this.pic.data))
;
},
methods: {
getprofilepicture()
{
//default avatar pic if there is no photo of user
let profilePicture = "http://localhost:8000/img/profile/user.png";
//returns the current path of the
if (this.pic.profilePicture) {
if (this.pic.profilePicture.indexOf('base64') != -1) {
profilePicture = this.pic.profilePicture;
} else {
profilePicture = 'http://localhost:8000/img/profile/' + this.pic.profilePicture;
}
return profilePicture;
}
return profilePicture;
//let profilePicture = (this.form.profilePicture.length > 200) ? this.form.profilePicture : "http://localhost:8000/img/profile/"+ this.form.profilePicture ;
//return profilePicture;
},
// getBackgroundPic(){
// let backgroundPicture = "http://localhost:8000/img/profile/background.jpg";
// if(this.form.backgroundPicture){
// if(this.form.backgroundPicture.indexOf('base64') != -1){
// backgroundPicture = this.form.backgroundPicture;
// }else {
// backgroundPicture = 'http://localhost:8000/img/profile/'+ this.form.backgroundPicture;
// }
// return backgroundPicture;
// }
// return backgroundPicture;
// },
updateInfo(){
this.$Progress.start();
this.form.put('profile')
.then(()=> {
this.$Progress.finish();
this.$router.go('/profile')
})
.catch(()=>{
this.$Progress.fail()
})
},
updateProfilePic(e){
let file = e.target.files[0];
//console.log(file);
let reader = new FileReader();
if(file['size'] < 2097152){
reader.onloadend = () => {
//console.log('RESULT', reader.result)
this.pic.profilePicture = reader.result;
}
reader.readAsDataURL(file);
}else{
Toast.fire({
icon: 'error',
title: 'Ooops...',
text: 'The file you are trying to upload is more than 2MB',
})
}
},
updateBackgroundPic(e){
let file = e.target.files[0];
//console.log(file);
let reader = new FileReader();
if(file['size'] < 2097152){
reader.onloadend = () => {
this.form.backgroundPicture = reader.result;
}
reader.readAsDataURL(file);
}else{
Toast.fire({
icon: 'error',
title: 'Ooops...',
text: 'The file you are trying to upload is more than 2MB'
})
}
}
}
}
</script>
Anytime i click on the submit button i have this error message: "Undefined offset: 1", exception: "ErrorException",…}
exception: "ErrorException"
and i really do not know the cause of this error.
Below is the PHP Code that handles the server side part of the upload
public function updateProfile(Request $request)
{
$user = auth('api')->user();
$this->validate($request,[
'username' => 'required|string|max:255|unique:users,username,'.$user->id,
'name' => 'max:255',
'email' => 'required|string|email|max:255|unique:users,email,
'.$user->id,
'password' => 'sometimes|required|min:8'
]);
$currentProfilePicture = $user->profilePicture;
if($request->profilePicture != $currentProfilePicture){
$name = time().'.' . explode('/', explode(':', substr($request->profilePicture, 0, strpos($request->profilePicture, ';')))[1])[1];
Image::make($request->profilePicture)->save(public_path('img/profile/').$name);
$request->merge(['profilePicture' => $name]);
$userPhoto = public_path('img/profile/').$currentProfilePicture;
if(file_exists($userPhoto)){
#unlink($userPhoto);
}
}
$user->update($request->all());
}
Files don't get uploaded when I hit the upload method.
I believe this issue is due to the axios interceptors 'cause when I make a new axios instance and set the headers to
headers: {'Authorization': 'Bearer ' + this.user.api_token }
it works like a charm.
Is there any way to get this to work without creating a new axios instance? 'cause I don't have access to the user object in my ImageUploader component?
ImageUploader.vue
<template>
<div>
<label for="file">Select a file</label>
<input type="file" id="file" #change="onInputChange" multiple>
</div>
<div class="upload-control" v-show="images.length">
<label for="file">Select a file</label>
<button #click="upload">Upload</button>
</div>
<template/>
<script>
export default {
data: () => ({
files: [],
images: []
}),
methods: {
onInputChange(e) {
const files = e.target.files;
Array.from(files).forEach(file => this.addImage(file));
},
addImage(file) {
if (!file.type.match('image.*')) {
this.$toastr.e(`${file.name} is not an image`);
return;
}
this.files.push(file);
const img = new Image(),
reader = new FileReader();
reader.onload = (e) => this.images.push(e.target.result);
reader.readAsDataURL(file);
},
upload() {
const formData = new FormData();
this.files.forEach(file => {
formData.append('images[]', file, file.name);
});
axios.post('/api/products', formData)
.then(response => {
this.images = [];
this.files = [];
})
},
},
}
App.vue
<script>
import SearchBar from "./SearchBar";
export default {
name: "App",
props: [
'user'
],
components: {
SearchBar
},
created() {
this.title = this.$route.meta.title;
window.axios.interceptors.request.use(config => {
if (config.method === "get") {
config.url = config.url + "?api_token=" + this.user.api_token;
} else {
config.data = {
...config.data,
api_token: this.user.api_token
};
}
return config;
});
},
}
</script>
I have 2 of the same components in my laravel blade view, but they are conflicting.
What i'm trying to accomplish:
I've made a vue component that uploads a file to firebase and stores it in my database. In my blade view i have 2 places where i want to use this component. I configure the component with props so the component knows where to store the file.
What going wrong:
Every time i try to upload a file with the second component, i fire the function in the first component. How do i fix that the components can't conflict?
My laravel balde view:
component 1
<uploadfile
:key="comp100"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
component 2
<uploadfile
:key="comp200"
:user_data="{{ Auth::user()->toJson() }}"
store_path="/users/{{ Auth::user()->username }}/settings/email_backgrounds"
:store_route="'settings.project_email'"
:size="1000"
fillmode="cover"
></uploadfile>
The Vue component:
<template>
<div class="vue-wrapper">
<FlashMessage position="right top"></FlashMessage>
<div v-if="loading" class="lds-dual-ring"></div>
<div class="field">
<div class="control">
<label class="button main-button action-button m-t-20" for="uploadFiles"><span style="background-image: url('/images/icons/upload.svg')"></span>Kies bestand</label>
<input type="file" name="uploadFiles" id="uploadFiles" class="dropinput" #change="selectFile">
</div>
</div>
</div>
</template>
<script>
import { fb } from '../../firebase.js';
export default {
data() {
return {
fileObject: {
filePath: null,
url: null,
file: null,
resizedPath: null
},
loading: false
};
},
mounted() {
console.log(this.size)
console.log(this.fillmode)
},
props: [
'user_data',
'store_path',
'store_route',
'size',
'fillmode'
],
methods: {
selectFile(event)
{
var file = event.target.files[0];
this.fileObject.file = file
this.fileObject.filePath = this.store_path + '/' + file.name
this.fileObject.resizedPath = this.store_path + '/resized-' + file.name
if(file.type == 'image/png' || file.type == 'image/jpeg')
{
this.uploadFile(this.fileObject)
} else {
this.flashMessage.success({
title: 'Oeps!',
message: 'De afbeelding moet een png of een jpeg zijn!',
blockClass: 'success-message'
});
}
},
uploadFile(fileObject)
{
var vm = this
console.log(fileObject)
var storageRef = fb.storage().ref(fileObject.filePath)
var uploadTask = storageRef.put(fileObject.file)
this.loading = true
uploadTask.on('state_changed', function(snapshot){
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
},function(error) {
}, function() {
var resizeImage = fb.functions().httpsCallable('resizeImage')
resizeImage({filePath: fileObject.filePath, contentType: fileObject.file.type, watermark: false, size: vm.size, fit: vm.fillmode}).then(function(result){
var downloadRef = fb.storage().ref(fileObject.resizedPath);
downloadRef.getDownloadURL().then(function(url){
fileObject.url = url
vm.loading = false
vm.storeImage(fileObject)
}).catch(function(error){
console.log(error)
})
}).catch(function(error){
});
});
},
storeImage(file)
{
axios.post('/api/app/store_file', {
api_token: this.user_data.api_token,
user: this.user_data,
file: file,
storeRoute: this.store_route
}).then((res) => {
location.reload()
}).catch((e) => {
});
}
}
}
</script>
Does someone know how to fix this?
About
I am submitting the image with plain text using vue.js and Laravel 5.8.
Error Details
When I submit the data using axios, it gives validation error message that product name is required. I am submitting both name and image. Everything works when I disable the code to submit image.
Request Header - Please click the image to view more details clearly
Payload - Please click the image to view more details clearly
Html
<template>
<div>
<input name="Product Name" type="text" v-model="saveForm.product_name">
<input type="file" accept="image/*" name="product_image" />
<button type="button" #click="store()">Save</button>
</div>
</template>
Script
<script>
export default {
data() {
return {
saveForm: {
product_name: '', product_image: null
}
};
},
methods: {
store() {
var config = {
headers : {
'Content-Type': 'multipart/form-data', 'processData': false
}
};
var fileData = new FormData();
fileData.append("product_image", this.saveForm.product_image);
fileData.append("product_name", this.saveForm.product_name);
axios.post("my route", this.saveForm, config).then(response => {
if(response.data.Status) {}
})
.catch(error => { //console.log(error);
});
}
}
}
</script>
Laravel Controller Action Method
public function Create(CreateProductRequest $request) {
//Code here
}
Laravel Request class
class CreateProductRequest extends Request
{
public function wantsJson() {
return true;
}
public function rules() {
return [
'product_name' => 'required',
'product_image' => "image|mimes:bmp,png,jpg,gif,jpeg"
];
}
}
Ok, let's review your code step by step.
1) You need add "boundary" to header. It's small important, but needed for the server.
headers: {
"Content-type":
"multipart/form-data; charset=utf-8; boundary=" +
Math.random()
.toString()
.substr(2),
processData: false,
Accept: "application/json"
}
2) Why do you prepare data through "new FormData()", but sending with "this.saveForm"? Correct code:
axios.post("my route", fileData, config)
.then(response => {
if (response.data.Status) {}
})
.catch(error => { //console.log(error);
});
3) When you do everything as I said above, you will get an error with the image, because you didn't pass it. I added functionality to send images.
summary:
Html
<div>
<input
name="Product Name"
type="text"
v-model="saveForm.product_name"
>
<input
type="file"
accept="image/*"
name="product_image"
#change="uploadImage"
/>
<button
type="button"
#click="store()"
>Save</button>
</div>
Script
export default {
data() {
return {
saveForm: {
product_name: "",
product_image: null
}
};
},
methods: {
store() {
var config = {
headers: {
"Content-type":
"multipart/form-data; charset=utf-8; boundary=" +
Math.random()
.toString()
.substr(2),
processData: false,
Accept: "application/json"
}
};
var fileData = new FormData();
fileData.append("product_image", this.saveForm.product_image);
fileData.append("product_name", this.saveForm.product_name);
axios
.post("my route", fileData, config)
.then(response => {
if (response.data.Status) {
}
})
.catch(error => {
console.log(error);
});
},
uploadImage(e) {
this.saveForm.product_image = e.target.files[0];
}
}
};