I searched on google and nothing...
i have a form in my view on vueJS :
<form #submit.prevent="avatar()" method="POST" enctype="multipart/form-data">
<input type="file" name="profilePicture" id="profilepicture" >
<button type="submit">Valider mon avatar?</button>
</form>
The user send an image.
My question is,
i want to send the image (sending by user with the form) in a function, and this function send the image to Http Request in headers ...
the api request begin with :
app.post('/myupload/:iduser', async (req, res) => {
try{
var { iduser } = req.params ;
const { image } = req.file ;
[...]
my function in my view on vuejs is actually :
async function avatar() {
console.log(document.getElementById("profilepicture").value);
// for having the image sending src
let response = await fetch(`http://localhost:196/myupload/${MyTokenStore.myid}`, {
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
},
body: JSON.stringify(document.getElementById("profilepicture").value)
})
.then((response) => response.json())
.catch((error) => {
console.log("Failed", error)
});
if(response.error){
alert(response.message);
return
}
}
But the only parameter i make in request is the string of the src image, and the error servor is :
TypeError: Cannot destructure property 'image' of 'req.files' as it is undefined.
Please, i need help, the request run when I go directly to the url of the request (but the browser directly displays the server response):
<form :action="`http://localhost:196/myupload/${MyTokenStore.myid}`"
method="POST" enctype="multipart/form-data">
<input type="file" name="image"/>
<button type="submit">Valider mon avatar</button>
</form>
but I fail to put it in a function...
thank you.
To send an image from Vue doing a request you have to use a FormData object. For example:
/**
* #description - register user
*/
const register = async () => {
try {
const fd = new FormData();
Object.keys(user.value).forEach((key) => {
fd.append(key, user.value[key]);
});
const res = await axios.post('/register', fd, {
headers: {
'Content-Type': 'multipart/form-data',
},
});
toast.success(res.data);
} catch (err) {
console.log(err);
toast.error(err.response.data);
}
};
In the previous code, in register I'm using a FormData to send the user object to the backend. Previously, you should set it. I made it like the following example:
const setProfileImage = (e) => {
image_preview.value = URL.createObjectURL(e.target.files[0]);
document.getElementById('image_preview').style.height = '150px';
document.getElementById('image_preview').style.width = '150px';
user.value.profile_image = e.target.files[0]; // this is important for you.
user.value.image = e.target.files[0].name;
};
setProfileImage is receiving an event from an Input file. If you see the comment I write in the code, user.value.profile_image = e.target.files[0] is the entire file. The rest is to display the image and send the name to store into the database.
<div class="mb-3">
<label
for="profile_image"
class="bg-primary text-white rounded-3 text-center w-100 p-2 profile_image"
>
Seleccione su foto de perfil <i class="ps-1 bi bi-card-image"></i>
</label>
<input
type="file"
class="form-control d-none"
id="profile_image"
placeholder="Adjunte su foto de perfil"
#change="setProfileImage"
/>
</div>
This is the Input file what I was talking. The event is an #change to catch correctly the file.
Hope it works for you.
I am trying to send form data to a graphql server using fetch-api
<div>
<!-- HTML5 Input Form Elements -->
<h4>GraphQL API Upload Test</h4>
<input id="fileUpload" type="file" name="fileUpload" />
<input id="fileDetail" type="text" name="fileDetail" />
<button id="upload-button" onclick="uploadFile()"> Upload </button>
<!-- Ajax JavaScript File Upload Logic -->
<script>
var queryTest = `mutation Header($input: Upload!) {
testUploadMutation( file: $input) {
response
}
}`;
async function uploadFile() {
let img = {};
img.file = fileUpload.files[0];
let formData = new FormData();
formData.append("operations",JSON.stringify( { query: queryTest}));
formData.append('map', { "0": ["variables.input"] });
formData.append('0', img.file);
await fetch("/graphql/", {
method: "POST",
body: formData
}).then(response => response.json()).then(data => console.log(data));
}
</script>
</div>
but I keep getting "Invalid JSON in the map multipart field; Expected type of Dictionary<string, string[]> from the server even though the mutation works fine on Banana Cake Pop. I have been using fetch-api to run all other queries and mutation successfully.
This is only code using formData with fetch-api for file upload and its not working . Anybody know what's going on?
Mutaion on Banana Cake Pop
mutation Header($input: Upload!) {
testUploadMutation( file: $input) {
response
}
}
#variables sent using the Banana Cake Pop Variables feature
{
"input": "somefile.jpg"
}
I have also tried sending formData.append('0', img)
instead of formData.append('0', img.file) but the same error
I'm trying to upload images from a Vue frontend via Illuminate/Http/Request to WinterCMS.
Vue finds the file and i can console.log the File object, but I'm unsure how to get this over the api. for example I've tried
public function saveImage(Request $req){
$images = $req->files('images');
}
which doesn't work, nor does
public function saveImage(Request $req){
$images = $req['images'];
}
I'm using a controller to handle my routes eg:
Route::post('/saveImage', 'Author\Project\Controllers\ProductControl#saveImage');
I've added an attachOne relation to the plugin as usual and my form has enctype="multipart/form-data"
I've had this problem before and got around it by converting images to base64 but this project will have quite a few images and I don't want to go down that route again.
Any suggestions greatly appreciated
You can send images as regular post and use regular $request->file('images') method in your Laravel controller.
You can use Javascript FormData object. For example;
<div>
<input type="file" #change="handleImages" multiple>
<button #click="uploadImages">Upload!</button>
</div>
data: () => ({
images: []
}),
methods: {
handleImages (event) {
this.images = event.target.files
},
uploadImages () {
const formData = new FormData();
for (const i of Object.keys(this.images)) {
formData.append('images', this.images[i])
}
axios.post('/saveImage', formData, {
}).then((res) => {
console.log(res)
})
}
}
I am trying to use a Vue component in my view for the first time. I have created a file assets/js/components/ImageUpload.vue that looks like this:
<template>
<div>
<div v-if="!image">
<h2>Select an image</h2>
<input type="file" #change="onFileChange">
</div>
<div v-else>
<img :src="image" />
<button #click="removeImage">Remove image</button>
</div>
</div>
</template>
<script>
export default {
data: { image: '' },
methods: {
onFileChange: function onFileChange(e) {
var files = e.target.files || e.dataTransfer.files;
if (!files.length)
return;
this.createImage(files[0]);
},
createImage: function createImage(file) {
var image = new Image();
var reader = new FileReader();
var vm = this;
reader.onload = function (e) {
vm.image = e.target.result;
};
reader.readAsDataURL(file);
},
removeImage: function removeImage(e) {
this.image = '';
}
}
}
</script>
My app.js looks like this:
require('./bootstrap');
var VueResource = require('vue-resource');
Vue.component('image-upload', require('./components/ImageUpload.vue'));
Vue.use(VueResource);
const app = new Vue({
el: 'body'
});
In my view I am inserting the component like this:
<image-upload></image-upload>
My gulpfile looks like this:
const elixir = require('laravel-elixir');
require('laravel-elixir-vue-2');
elixir(mix => {
mix.copy('resources/assets/img', 'public/img');
mix.copy('resources/assets/css', 'public/css');
mix.copy('resources/assets/js', 'public/js');
mix.sass('app.scss')
.webpack('app.js');
});
But nothing happens in the view. There is an element <image-upload></image-upload> but nothing from the template is being shown and the only error in the console is:
[Vue warn]: Do not mount Vue to or -
mount to normal elements instead.
Since I am a not a javascript expert and a total Vue beginner I have no idea where can I change the mounting of Vue and why the template is not being displayed.
You are mounting Vue into the body which is not recommended.
From the Vue docs:
The provided element merely serves as a mounting point. Unlike in Vue 1.x, the mounted element will be replaced with Vue-generated DOM in all cases. It is therefore not recommended to mount the root instance to <html> or <body>.
Try to mount it in some other HTML element like a wrapper <div>
I'm using the Kendo UI File Upload for MVC and it works great. On my edit page, I want to show the files that were previously uploaded from the Create page. For visual consistency, I would like to re-use the upload widget on my edit page so the user can use the "remove" functionality, or add additional files if they choose. Does the upload widget support this?
Thanks!
So, I realize this is question pretty old, but I recently figured out how to do this reliably. While the other answer on here will certainly display the files, it doesn't really wire it up to any of the events (specifically the "remove" event). Also, rather than manually setting all of this up, I figured I'd much rather have Kendo do all of the real dirty work.
Note, this only applies if your file upload is not set to autosync. If you use the auto upload feature, you can find examples in the Kendo documentation here: http://docs.kendoui.com/api/web/upload#configuration-files
So anyway, let's assume we have a file input that we've made into a Kendo Upload:
<input id="files" name="files" type="file" multiple="multiple" />
$(document).ready(function () {
var $upload = $("#files");
var allowMultiple = Boolean($upload.attr("multiple"));
$upload.kendoUpload({
multiple: allowMultiple,
showFileList: true,
autoUpload: false
});
}
Then, we just need to get the information about the files to our jQuery. I like to jam it into JSON strings in hidden fields, but you can do it however you want.
Here's an example using the Mvc HtmlHelpers and Newtonsoft's JSON.NET (I don't use Razor, but you should get the general idea):
if (Model.Attachments.Count > 0)
{
var files = Model.Attachments.Select(x => new { name = x.FileName, extension = x.FileExtension, size = x.Size });
var filesJson = JsonConvert.SerializeObject(files);
Html.Render(Html.Hidden("existing-files", filesJson));
}
Note, the format there is incredibly important. We're tying to match the structure of the JavaScript object that Kendo is expecting:
{
relatedInput : sourceInput,
fileNames: [{ // <-- this is the collection we just built above
name: "example.txt",
extenstion: ".txt",
size: 1234
}]
}
So, then all that's left to do is put it all together. Basically, we're going to recreate the onSelect function from Kendo's internal syncUploadModule:
$(document).ready(function () {
// setup the kendo upload
var $upload = $("#files");
var allowMultiple = Boolean($upload.attr("multiple"));
var upload = $upload.kendoUpload({
multiple: allowMultiple,
showFileList: true,
autoUpload: false
}).getKendoUpload();
// initialize the files
if (upload) {
var filesJson = $("[name$='existing-files']").val();
if (filesJson) {
var files = JSON.parse(filesJson);
var name = $.map(files, function (item) {
return item.name;
}).join(", ");
var sourceInput = upload._module.element.find("input[type='file']").last();
upload._addInput(sourceInput.clone().val(""));
var file = upload._enqueueFile(name, {
relatedInput : sourceInput,
fileNames : files
});
upload._fileAction(file, "remove");
}
}
});
And that's pretty much it!
I came up with a way to do this.
Basically, you need HTML that mimics what the Upload control generates, and you use a bit of JavaScript to hook each item up. I initially render the HTML as hidden, then after you initialize the Kendo Upload control, you append the HTML list to the parent container that Kendo creates.
This is my MVC view:
#if (Model.Attachments != null && Model.Attachments.Count > 0)
{
<ul id="existing-files" class="k-upload-files k-reset" style="display: none;">
#foreach (var file in Model.Attachments)
{
<li class="k-file" data-att-id="#file.Id">
<span class="k-icon k-success">uploaded</span>
<span class="k-filename" title="#file.Name">#file.Name</span>
<button type="button" class="k-button k-button-icontext k-upload-action">
<span class="k-icon k-delete"></span>
Remove
</button>
</li>
}
</ul>
}
and here is the JavaScript (note, it was generated from CoffeeScript):
var $fileList, $files, item, _fn, _i, _len;
$fileList = $("#existing-files");
if ($fileList.length > 0) {
$(".k-upload").append($fileList);
$files = $(".k-file");
_fn = function(item) {
var $item, fileId, filenames;
$item = $(item);
fileId = $item.data("att-id");
filenames = [
{
name: fileId
}
];
return $item.data("fileNames", filenames);
};
for (_i = 0, _len = $files.length; _i < _len; _i++) {
item = $files[_i];
_fn(item);
}
$fileList.show();
}
You can find the full write up on my blog where I go into depth on the topic. I hope this helps you!
Some additional searches gave me the answer I wasn't looking for - According to this and this, Telerik does not support pre-populating an upload widget with previously uploaded documents.
It has been added in the options since this question has been asked.
Check out http://docs.telerik.com/kendo-ui/api/web/upload#configuration-files
It only works in async mode.
Try this...
#(Html.Kendo().Upload()
.Name("files")
.Async(a => a
.Save("SaveFile", "Home")
.Remove("RemoveFile", "Home")
.AutoUpload(true))
.Files(files =>
{
foreach (var file in Model.FundRequest.Files)
{
files.Add().Name(file.Name).Extension(Path.GetExtension(file.Name)).Size((long)file.SizeKb * 1024);
}
}))
My Model has a reference to my "FundRequest" object that has a List of "File" objects, so I just loop through each "File" and add.
Check this out!
<script>
var files = [
{ name: "file1.doc", size: 525, extension: ".doc" },
{ name: "file2.jpg", size: 600, extension: ".jpg" },
{ name: "file3.xls", size: 720, extension: ".xls" },
];
$("#upload").kendoUpload({
async: {
saveUrl: "Home/Save",
removeUrl: "Home/Remove",
autoUpload: true
},
files: files
});
</script>
<input type="file" name="files" id="upload" />
Check this out, this is it.
Below code is copied and adapted from kendo-ui documentation:
<div id="example">
<div>
<div class="demo-section">
<input name="files" id="files" type="file" />
</div>
</div>
<script>
$(document).ready(function () {
if (sessionStorage.initialFiles === undefined) {
sessionStorage.initialFiles = "[]";
}
var initialFiles = JSON.parse(sessionStorage.initialFiles);
$("#files").kendoUpload({
showFileList: true,
multiple: true,
async: {
saveUrl: "save",
autoUpload: false,
batch: true
},
files: initialFiles,
success: onSuccess
});
function onSuccess(e) {
var currentInitialFiles = JSON.parse(sessionStorage.initialFiles);
for (var i = 0; i < e.files.length; i++) {
var current = {
name: e.files[i].name,
extension: e.files[i].extension,
size: e.files[i].size
}
if (e.operation == "upload") {
currentInitialFiles.push(current);
} else {
var indexOfFile = currentInitialFiles.indexOf(current);
currentInitialFiles.splice(indexOfFile, 1);
}
}
sessionStorage.initialFiles = JSON.stringify(currentInitialFiles);
}
});
</script>
</div>