Multiple file upload with angular being deleted before sending files - javascript

I'm trying to upload multiple files to server.
The file is being stored in a variable.
When I click upload the client is sending that variable empty.
Here is my html
<div class = "control-group form-group col-md-12"
ng-class = "{'has-error':newAsset.OSGImages.$invalid && newAsset.OSGImages.$dirty}" ng-if = "showUploadFile(4)">
<label>OSG Images (max 3 MB)</label>
<input type="file" multiple ngf-select="" ng-model="newAssetForm.OSGImages" name = "OSGImages" ngf-max-size="3 MB">
<p ng-repeat="image in newAssetForm.OSGImages">
{{image.name}}
</p>
<span class = "help-block has-error" ng-if="newAsset.OSGImages.$dirty">
</span>
</div>
Here is my js code:
enter code var fileReader = new FileReader();
fileReader.readAsArrayBuffer($scope.newAssetForm.OSGImages[0]);
fileReader.onload = function(e) {
console.log(e);
Upload.upload({
url: '/api/uploadAsset',
headers: {
'Content-Type': 'multipart/form-data'
},
data: {
'projectId': $scope.projectId,
'loadValueType' : $scope.newAssetForm.loadValueType,
'outputVideoLink': $scope.newAssetForm.outputVideoLink,
'isActive': $scope.newAssetForm.isActive,
'PImageSet': PImageSet,
inputImageUrl: $scope.newAssetForm.inputImageUrl,
markerPattFile: $scope.newAssetForm.markerPattFile,
cinema: $scope.newAssetForm.cinema,
objFile: $scope.newAssetForm.objFile,
mtlFile: $scope.newAssetForm.mtlFile,
PImage: $scope.newAssetForm.PImage,
osgFile: $scope.newAssetForm.OSGFile,
osgImage: e.target.result,
},
})
.then(function onSuccess(result){
$scope.$emit('create_asset', result.data);
$modalInstance.close();
})
I tried uploading with postman and the server is getting the files.
Also, the console logs print the files correctly.
Why the client is sending empty variable?

Related

How can I set input file picked image by using Vue?

I'm using Quasar framework and Vue
I have input element that gets picked image after that I send It to servlet where I process that image and storing in a folder.If It was successfully I send simple message which will be displayed on page.Servlet works fine, I only need to know how to set image If response was without error.
<div id="q-app">
<input type="file" id="file"
ref="file" accept=".jpg, .jpeg, .png"
style="display:none"
#change="handleFileUpload()"/>
<div class="q-ma-md row justify-start">
<div class="col-auto">
<q-btn style="width:1000px;height:1000px;" #click="tclick">
<q-img height="100%" width="100%" :src="imageSrc">
</q-img>
</q-btn>
</div>
</div>
<div class="col-auto">
<q-btn class="q-ma-md" size="md" #click="submitFile()" color="primary" label="changeProfilePicture"></q-btn>
</div>
</div>
And javascript
I have methods that catch the selected image and send it to the servlet
<script>
new Vue({
el: '#q-app',
data () {
return {
file: '',
imageSrc:'${pageContext.request.contextPath}/images/profile.jpg',
}
},
methods:{
tclick(){
this.$refs.file.click()
},
handleFileUpload(){
this.file = this.$refs.file.files[0];
},
submitFile(){
let formData = new FormData();
formData.append('file', this.file);
axios.post( "${pageContext.request.contextPath}"+"/hello-servlet",
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(response => {
this.$q.notify({
type: 'positive',
message: response.data,
position:'center',
icon: 'check'
})
}).catch(error => {
console.log(error);
})
},
},
})
</script>
How can I set picked image to q-img tag?

How do I upload both images and form content in a vue?

Upload images and form content? How to upload? The idea is to upload it to the client and then upload it to the server along with the form content, right?
I want to upload the form content and the image to the server when I click submit, instead of uploading the image separately when I upload the image.
But I don't know how to upload at the same time. Can you help me?
<template>
<form>
<input type="text" v-model="test">
<img :src="previewImage" class="uploading-image" />
<input type="file" accept="image/jpeg" #change=uploadImage>
<input type="submit"></input>
</form>
</template>
export default {
data(){
return{
previewImage:null,
test: ''
}
},
methods:{
uploadImage(e){
const image = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(image);
reader.onload = e =>{
this.previewImage = e.target.result;
console.log(this.previewImage);
};
const URL = 'http://xxxx';
let data = new FormData();
data.append('name', 'my-picture');
data.append('file', event.target.files[0]);
let config = {
header : {
'Content-Type' : 'image/png'
}
}
axios.put(URL, data,config).then(response => {
console.log('image upload response > ', response)
})
}
}
You need to add this to the form
<form #submit.prevent="uploadImage">
<input type="text" v-model="test">
<img :src="previewImage" class="uploading-image" />
<input type="file" accept="image/jpeg" >
<input type="submit"></input>
</form>

Current request is not a multipart request

I'm trying to send an image to my server. I'm keep getting the error: Current request is not a multipart request. When i test it in Postman it works fine.
This is my html form:
function saveImageToProduct() {
var formData = new FormData(document.querySelector("#newImagesForm"));
var encData = new URLSearchParams(formData.entries());
fetch("/uploadFile", { method: 'POST', body: encData })
.then(response => Promise.all([response.status, response.json()]))
.then(function([status, myJson]) {
if (status == 200) {
console.log("succeed!");
} else {
console.log("failed!");
}
})
.catch(error => console.log(error.message));
return false;
}
<form enctype="multipart/form-data" novalidate="novalidate" id="newImagesForm" method="post">
<div>
<p>Selecteer een afbeelding:</p>
<input id="file" name="file" type="file"/>
</div>
<br>
<div>
<button id="button" onclick="return saveImageToProduct()" class="btn btn-lg btn-info btn-block">
<span>Voeg aanbieding toe</span>
</button>
</div>
</form>
Backend Java code:
#PostMapping("/uploadFile")
public ProductImage uploadFile(#RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/uploads/")
.path(fileName)
.toUriString();
return new ProductImage(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
When i try to send the image i'm getting a 500 error in the backend:
2019-03-10 19:40:33.588 ERROR 5668 --- [io-9001-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause org.springframework.web.multipart.MultipartException: Current request is not a multipart request
When i do it in Postman it works fine like the following image shows:
Any idea what i'm doing wrong here? Thanks in advance
The code below should do the job:
You basically create a new Form object and append the file data to it.
You are able to add multiple data attributes to it by adding more "data.append" lines.
function uploadPicture() {
var input = document.querySelector('input[type="file"]')
console.log(productID);
var data = new FormData()
data.append('file', input.files[0])
fetch('/uploadFile/', {
method: 'POST',
body: data
})
.then(response => Promise.all([response.status, response.json()]))
.then(function([status, myJson]) {
if (status == 200) {
console.log("succeed!");
} else {
console.log("failed!");
}
})
.catch(error => console.log(error.message));
}
HTML:
<input type="file" name="file" id="fileinput">
<input type="submit" value="Upload" onclick="uploadPicture()">
You can try modifying it -
var formData = new FormData(document.querySelector("#newImagesForm")[0]);

Angular get CSV file in browser by calling URL

I have made a Java micro service to export a table from a database into a CSV file and get it in browser by following this: Downloading a CSV File in Browser by using Java
It works well and I get the file in the browser when I call the URL (by copying and pasting in the browser) :
http://localhost:8080/api/fileDownload/2
In the Angular part when I call the URL in my app I see in the console :
Request URL:http://localhost:8080/api/fileDownload/2
Request Method:GET
Status Code:200
In the preview and the response of the console, I also have the content of my file. So it seems everything looks good but the problem is that my browser doesn't download the file automatically.
My controller :
vm.downloadFunction=function(){
FileDownload.download.query({id:2},function(data){
});
};
My view :
<label data-ng-click="addModule.downloadFunction()" class="btn btn-link btn-file">
Download <input type="button" class="hidden">
</label>
And the service :
voltApp.factory('FileDownload', function ($resource) {
return{
download: $resource('/api/fileDownload/:id', {}, {
query: {method: 'GET', params: {id:'#id'},isArray:false},
update:{method: 'PUT'}
})
};
});
What am I doing wrong?
Consider using ngFileSaver
Example:
JS
function ExampleCtrl(FileSaver, Blob) {
var vm = this;
vm.val = {
text: 'Hey ho lets go!'
};
vm.download = function(text) {
var data = new Blob([text], { type: 'text/plain;charset=utf-8' });
FileSaver.saveAs(data, 'text.txt');
};
}
angular
.module('fileSaverExample', ['ngFileSaver'])
.controller('ExampleCtrl', ['FileSaver', 'Blob', ExampleCtrl]);
HTML
<div class="wrapper" ng-controller="ExampleCtrl as vm">
<textarea
ng-model="vm.val.text"
name="textarea" rows="5" cols="20">
Hey ho let's go!
</textarea>
<a href="" class="btn btn-dark btn-small" ng-click="vm.download(vm.val.text)">
Download
</a>
</div>

Angularjs how to upload multipart form data and a file?

I'm a beginner to angular.js but I have a good grasp of the basics.
What I am looking to do is upload a file and some form data as multipart form data. I read that this isn't a feature of angular, however 3rd party libraries can get this done. I've cloned angular-file-upload via git, however I am still unable to post a simple form and a file.
Can someone please provide an example, html and js of how to do this?
First of all
You don't need any special changes in the structure. I mean: html input tags.
<input accept="image/*" name="file" ng-value="fileToUpload"
value="{{fileToUpload}}" file-model="fileToUpload"
set-file-data="fileToUpload = value;"
type="file" id="my_file" />
1.2 create own directive,
.directive("fileModel",function() {
return {
restrict: 'EA',
scope: {
setFileData: "&"
},
link: function(scope, ele, attrs) {
ele.on('change', function() {
scope.$apply(function() {
var val = ele[0].files[0];
scope.setFileData({ value: val });
});
});
}
}
})
In module with $httpProvider add dependency like ( Accept, Content-Type etc) with multipart/form-data. (Suggestion would be, accept response in json format)
For e.g:
$httpProvider.defaults.headers.post['Accept'] = 'application/json, text/javascript';
$httpProvider.defaults.headers.post['Content-Type'] = 'multipart/form-data; charset=utf-8';
Then create separate function in controller to handle form submit call.
like for e.g below code:
In service function handle "responseType" param purposely so that server should not throw "byteerror".
transformRequest, to modify request format with attached identity.
withCredentials : false, for HTTP authentication information.
in controller:
// code this accordingly, so that your file object
// will be picked up in service call below.
fileUpload.uploadFileToUrl(file);
in service:
.service('fileUpload', ['$http', 'ajaxService',
function($http, ajaxService) {
this.uploadFileToUrl = function(data) {
var data = {}; //file object
var fd = new FormData();
fd.append('file', data.file);
$http.post("endpoint server path to whom sending file", fd, {
withCredentials: false,
headers: {
'Content-Type': undefined
},
transformRequest: angular.identity,
params: {
fd
},
responseType: "arraybuffer"
})
.then(function(response) {
var data = response.data;
var status = response.status;
console.log(data);
if (status == 200 || status == 202) //do whatever in success
else // handle error in else if needed
})
.catch(function(error) {
console.log(error.status);
// handle else calls
});
}
}
}])
<script src="//unpkg.com/angular/angular.js"></script>
This is pretty must just a copy of that projects demo page and shows uploading a single file on form submit with upload progress.
(function (angular) {
'use strict';
angular.module('uploadModule', [])
.controller('uploadCtrl', [
'$scope',
'$upload',
function ($scope, $upload) {
$scope.model = {};
$scope.selectedFile = [];
$scope.uploadProgress = 0;
$scope.uploadFile = function () {
var file = $scope.selectedFile[0];
$scope.upload = $upload.upload({
url: 'api/upload',
method: 'POST',
data: angular.toJson($scope.model),
file: file
}).progress(function (evt) {
$scope.uploadProgress = parseInt(100.0 * evt.loaded / evt.total, 10);
}).success(function (data) {
//do something
});
};
$scope.onFileSelect = function ($files) {
$scope.uploadProgress = 0;
$scope.selectedFile = $files;
};
}
])
.directive('progressBar', [
function () {
return {
link: function ($scope, el, attrs) {
$scope.$watch(attrs.progressBar, function (newValue) {
el.css('width', newValue.toString() + '%');
});
}
};
}
]);
}(angular));
HTML
<form ng-submit="uploadFile()">
<div class="row">
<div class="col-md-12">
<input type="text" ng-model="model.fileDescription" />
<input type="number" ng-model="model.rating" />
<input type="checkbox" ng-model="model.isAGoodFile" />
<input type="file" ng-file-select="onFileSelect($files)">
<div class="progress" style="margin-top: 20px;">
<div class="progress-bar" progress-bar="uploadProgress" role="progressbar">
<span ng-bind="uploadProgress"></span>
<span>%</span>
</div>
</div>
<button button type="submit" class="btn btn-default btn-lg">
<i class="fa fa-cloud-upload"></i>
<span>Upload File</span>
</button>
</div>
</div>
</form>
EDIT: Added passing a model up to the server in the file post.
The form data in the input elements would be sent in the data property of the post and be available as normal form values.
It is more efficient to send the files directly.
The base64 encoding of Content-Type: multipart/form-data adds an extra 33% overhead. If the server supports it, it is more efficient to send the files directly:
Doing Multiple $http.post Requests Directly from a FileList
$scope.upload = function(url, fileList) {
var config = {
headers: { 'Content-Type': undefined },
transformResponse: angular.identity
};
var promises = fileList.map(function(file) {
return $http.post(url, file, config);
});
return $q.all(promises);
};
When sending a POST with a File object, it is important to set 'Content-Type': undefined. The XHR send method will then detect the File object and automatically set the content type.
Working Demo of "select-ng-files" Directive that Works with ng-model1
The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:
angular.module("app",[]);
angular.module("app").directive("selectNgFiles", function() {
return {
require: "ngModel",
link: function postLink(scope,elem,attrs,ngModel) {
elem.on("change", function(e) {
var files = elem[0].files;
ngModel.$setViewValue(files);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-ng-files ng-model="fileList" multiple>
<h2>Files</h2>
<div ng-repeat="file in fileList">
{{file.name}}
</div>
</body>
You can check out this method for sending image and form data altogether
<div class="form-group ml-5 mt-4" ng-app="myApp" ng-controller="myCtrl">
<label for="image_name">Image Name:</label>
<input type="text" placeholder="Image name" ng-model="fileName" class="form-control" required>
<br>
<br>
<input id="file_src" type="file" accept="image/jpeg" file-input="files" >
<br>
{{file_name}}
<img class="rounded mt-2 mb-2 " id="prvw_img" width="150" height="100" >
<hr>
<button class="btn btn-info" ng-click="uploadFile()">Upload</button>
<br>
<div ng-show = "IsVisible" class="alert alert-info w-100 shadow mt-2" role="alert">
<strong> {{response_msg}} </strong>
</div>
<div class="alert alert-danger " id="filealert"> <strong> File Size should be less than 4 MB </strong></div>
</div>
Angular JS Code
var app = angular.module("myApp", []);
app.directive("fileInput", function($parse){
return{
link: function($scope, element, attrs){
element.on("change", function(event){
var files = event.target.files;
$parse(attrs.fileInput).assign($scope, element[0].files);
$scope.$apply();
});
}
}
});
app.controller("myCtrl", function($scope, $http){
$scope.IsVisible = false;
$scope.uploadFile = function(){
var form_data = new FormData();
angular.forEach($scope.files, function(file){
form_data.append('file', file); //form file
form_data.append('file_Name',$scope.fileName); //form text data
});
$http.post('upload.php', form_data,
{
//'file_Name':$scope.file_name;
transformRequest: angular.identity,
headers: {'Content-Type': undefined,'Process-Data': false}
}).success(function(response){
$scope.IsVisible = $scope.IsVisible = true;
$scope.response_msg=response;
// alert(response);
// $scope.select();
});
}
});

Categories