I'm using AngularJS with my pages, and I have a doubt: when I do post with my form, how can I pass some selected file to my ASP.NET MVC 3 Controller?
Check this out:
My form:
<form enctype="multipart/form-data" ng-controller="FilesController" ng-submit="submitingForm()">
<div>
Choose the file:
<input type="file" onchange="angular.element(this).scope().setSelectedFile(this)" />
</div>
<input type="submit" value="Confirm" />
</form>
And the AngularJS Controller:
var module = angular.module('application', []);
(function (ang, app) {
function FilesController($scope, $http) {
$scope.setSelectedFile = function (element) {
$scope.$apply(function($scope) {
$scope.selectedFile = element.files[0];
});
};
$scope.submitingForm = function() {
$http.post(url, ???????).success(function() {
// How to pass that selected file for my ASP.NET controller?
});
}
}
app.controller("FilesController", FilesController);
})(angular, module);
Thank you!!!
I am not quite familiar with AngularJS but if you are attempting to upload a file using an AJAX request you can forget about it. That's not something that could be done. You could use the HTML5 File API if you want to upload files asynchronously to the server. There's an entire section dedicated to this.
And if your client browsers do not support the HTML5 File API you could use a File Upload plugin such as FineUploader or Uploadify (there are quite many others, just google).
My Approach is to use FormData.
Create a input tag like this.
<input id="imgInp" type="file" aria-label="Add photos to your post" class="upload" name="file" onchange="angular.element(this).scope().LoadFileData(this.files)" multiple="" accept="image/*" style="margin-top: -38px; opacity: 0; width: 28px;">
And in your Angular Controller create a method LoadFileData(inputFiles) as bellow:
var formData = new FormData();
$scope.LoadFileData = function (files) {
for (var file in files) {
formData.append("file", files[file]);
}
};
Now in formData variable you will have the uploaded files. Just send it to asp.net mvc controller.
$scope.submit = function () {
$http.post("/YourController/Method", formData, {
withCredentials: true,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity
}).success(function (response) {
}
In Server side, Asp.NET MVC 4 controller you will have the files
var files = Request.Files;
Related
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 upload a file (File can be anything i.e. an image or pdf or doc, absolutely anything) . For that, I made a test form into my Vue component that is below
<form class="mt-5" method="post" enctype="multipart/form-data" id="uploadForm">
<div class="form-group">
<input type="file" id="test" name="test" class="form-control">
</div>
<button #click.prevent="uploadFile" type="button" class="btn btn-sm btn-primary">Upload</button>
</form>
Now when I submit form (click the upload button), I am running a function below
uploadFile() {
let something = $('#test').prop('files')[0];
console.log(something);
let form_data = new FormData();
form_data.append('file', something);
console.log(form_data);
axios.post('/upload/file', { form_data })
.then(() => {
console.log("done");
})
},
So when I console.log(something), it shows me the info of uploaded file but when I send data to server using axios and dd($request->all()) there, it shows me something => [] an empty array, that means, I am not getting the file and hence cant process it further to save it into my folders (upload).
What am I doing wrong here?
This happens because you are not setting the header Content-Type as multipart/form-data (and by default the application/json is being used) when making the request with axios, and the enctype attribute has no effect, since your not using the default form submit action. So try to pass a third argument in the post method, specifying the correct Content-Type header.
const uploadAvatar = ({ id, file }) => {
const formData = new FormData();
formData.append('avatar', file);
return axios.post(`users/${id}/avatar`, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
};
After upgrading Spring Security to the 3.2.x version, the Ajax file upload function in my application is no longer working. Based on the SS 3.2 documentation, I append ${_csrf.parameterName}=${_csrf.token} on the ajax URL. That doesn't help. I also try SS post method setting as the followings without any luck either.
var token = $("meta[name='_csrf']").attr("value");
var header = $("meta[name='_csrf_header']").attr("value");
//...
$(document).ready(function() {
new AjaxUpload('#uploadButton', {
action: "/shop/admin/products/images/upload",
name: 'uploadData',
beforeSend : function(xhr) {
xhr.setRequestHeader("Accept","application/json");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader(header, token);
},
onSubmit: function(file , ext) {
this.disable();
if (! (ext && /^(jpg|png|jpeg|gif|JPG|PNG|JPEG|GIF)$/.test(ext))){
alert('Error: invalid file extension');
return false; // cancel upload
}else {
// change button text, when user selects file
button.text(msg);
// If you want to allow uploading only 1 file at time,
// you can disable upload button
this.disable();
// Uploding -> Uploading. -> Uploading...
interval = window.setInterval(function(){
var text = button.text();
if (text.length < 13){
button.text(text + '.');
} else {
button.text(msg);
}
}, 200);
}
},
onComplete: function(file, response) {
button.text(msg);
window.clearInterval(interval);
this.enable();
}
});
});
And a html related code:
<button id="uploadButton" type="button" class="btn btn-default" th:text="#{label.upload}"></button>
The other option mentioned in the SS documentation is a filter configuration order. The Java configuration of the application doesn't come with any filter configuration. So this option can't be applied.
How to deal with this problem?
According to the latest Spring Security documentation, the code should be $("meta[name='_csrf']").attr("content") instead of $("meta[name='_csrf']").attr("value") which seems to make sense because the HTML meta tag has a content attribute instead of a value attribute.
Could you make this change and try again?
A normal form, but note the hidden CSRF:
<form id="myForm" action="upload" method="post">
<input type="file" name="file">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">
<input type="submit" value="Upload file!">
</form>
Ajaxify with jQuery Form Plugin:
$(document).ready(function() {
$('#myForm').ajaxForm(function() {
alert("File was uploaded!");
});
});
Last step for success: Make sure you have MultipartFilter before Spring Security in your web.xml, as described in Spring Security reference, section CSRF Caveats.
jQuery Form Plugin has different strategies for file upload depending on browser, but the above should work regardless.
I am trying to look for a good comprehensive example of multiple file upload with asp.net mvc3 & knockout.js. I been looking around but nothing that shows the solution from start to finish! There examples that show what the knockout binding needs to be, but doesn't show how to read the files in the "Controller". Goal is upload and save files to db. Example of saving to a AWS S3 storage is a plus. Please help.
ko binding:
<input type="file" data-bind="value: fileToUpload, fileUpload: fileToUpload, url : 'Client/Upload' " />
ko.bindingHandlers.fileUpload = {
update: function (element, valueAccessor, allBindingsAccessor) {
var value = ko.utils.unwrapObservable(valueAccessor())
if (element.files.length && value) {
var file = element.files[0];
var url = allBindingsAccessor().url
xhr = new XMLHttpRequest();
xhr.open("post", url, true);
xhr.setRequestHeader("Content-Type", "image/jpeg");
xhr.setRequestHeader("X-File-Name", file.name);
xhr.setRequestHeader("X-File-Size", file.size);
xhr.setRequestHeader("X-File-Type", file.type);
console.log("sending")
// Send the file (doh)
xhr.send(file);
}
}
}
[HttpPost]
public ActionResult Upload()
{
//Not sure what to do here.
}
Also need to do multiple file upload? Not sure how to set the viewmodels.
On the javascript side I would suggest using fineuploader http://fineuploader.com/. you can create a custom binding for updating the viewmodel with the response.
<div data-bind="fileupload: viewModel.fileName"></div>
ko.bindingHandlers.fileUpload = {
init: function (element, valueAccessor) {
var $element = $(element);
var fileNameVal = valueAccessor;
var uploader = new qq.FineUploader({
element: $element[0],
request: {
endpoint: 'server/your_upload_service'
},
multiple: true,
validation: {
allowedExtensions: ['jpeg', 'jpg', 'txt']
},
callbacks: {
onComplete: function(id, fileName, responseJSON) {
if (responseJSON.success) {
// update your value
valueAccessor(fileName)
//may need to change this if you pass a reference back
// in your responseJSON such as an s3 key
}
}
}
});
}
};
as for the server side I am not familiar with ASP.net but you should be able to interact with the request data on your endpoint and extract the multipart encoded form parts that contain the image data.
might want to look at these answers
MVC 3 file upload and model binding
File Upload ASP.NET MVC 3.0
also note that fineuploader sends the file in the request with the key "qqfile"