I have a form with two input text and one upload. I have to send it to the server but I have some problem concatenating the file with the text. The server expects this answer:
"title=first_input" "text=second_input" "file=my_file.pdf"
This is the html:
<input type="text" ng-model="title">
<input type="text" ng-model="text">
<input type="file" file-model="myFile"/>
<button ng-click="send()">
This is the Controller:
$scope.title = null;
$scope.text = null;
$scope.send = function(){
var file = $scope.myFile;
var uploadUrl = 'my_url';
blockUI.start();
Add.uploadFileToUrl(file, $scope.newPost.title, $scope.newPost.text, uploadUrl);
};
This is the Directive fileModel:
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
And this is the Service which call the server:
this.uploadFileToUrl = function(file, title, text, uploadUrl){
var fd = new FormData();
fd.append('file', file);
var obj = {
title: title,
text: text,
file: fd
};
var newObj = JSON.stringify(obj);
$http.post(uploadUrl, newObj, {
transformRequest: angular.identity,
headers: {'Content-Type': 'multipart/form-data'}
})
.success(function(){
blockUI.stop();
})
.error(function(error){
toaster.pop('error', 'Errore', error);
});
}
If I try to send, I get Error 400, and the response is: Multipart form parse error - Invalid boundary in multipart: None.
The Payload of Request is: {"title":"sadf","text":"sdfsadf","file":{}}
Don't serialize FormData with POSTing to server. Do this:
this.uploadFileToUrl = function(file, title, text, uploadUrl){
var payload = new FormData();
payload.append("title", title);
payload.append('text', text);
payload.append('file', file);
return $http({
url: uploadUrl,
method: 'POST',
data: payload,
//assign content-type as undefined, the browser
//will assign the correct boundary for us
headers: { 'Content-Type': undefined},
//prevents serializing payload. don't do it.
transformRequest: angular.identity
});
}
Then use it:
MyService.uploadFileToUrl(file, title, text, uploadUrl).then(successCallback).catch(errorCallback);
Here is the complete solution
html code,
create the text anf file upload fields as shown below
<div class="form-group">
<div>
<label for="usr">User Name:</label>
<input type="text" id="usr" ng-model="model.username">
</div>
<div>
<label for="pwd">Password:</label>
<input type="password" id="pwd" ng-model="model.password">
</div><hr>
<div>
<div class="col-lg-6">
<input type="file" file-model="model.somefile"/>
</div>
</div>
<div>
<label for="dob">Dob:</label>
<input type="date" id="dob" ng-model="model.dob">
</div>
<div>
<label for="email">Email:</label>
<input type="email"id="email" ng-model="model.email">
</div>
<button type="submit" ng-click="saveData(model)" >Submit</button>
directive code
create a filemodel directive to parse file
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};}]);
Service code
append the file and fields to form data and do $http.post as shown below
remember to keep 'Content-Type': undefined
.service('fileUploadService', ['$http', function ($http) {
this.uploadFileToUrl = function(file, username, password, dob, email, uploadUrl){
var myFormData = new FormData();
myFormData.append('file', file);
myFormData.append('username', username);
myFormData.append('password', password);
myFormData.append('dob', dob);
myFormData.append('email', email);
$http.post(uploadUrl, myFormData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
In controller
Now in controller call the service by sending required data to be appended in parameters,
$scope.saveData = function(model){
var file = model.myFile;
var uploadUrl = "/api/createUsers";
fileUpload.uploadFileToUrl(file, model.username, model.password, model.dob, model.email, uploadUrl);
};
You're sending JSON-formatted data to a server which isn't expecting that format. You already provided the format that the server needs, so you'll need to format it yourself which is pretty simple.
var data = '"title='+title+'" "text='+text+'" "file='+file+'"';
$http.post(uploadUrl, data)
This never gonna work, you can't stringify your FormData object.
You should do this:
this.uploadFileToUrl = function(file, title, text, uploadUrl){
var fd = new FormData();
fd.append('title', title);
fd.append('text', text);
fd.append('file', file);
$http.post(uploadUrl, obj, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
blockUI.stop();
})
.error(function(error){
toaster.pop('error', 'Errore', error);
});
}
Using $resource in AngularJS you can do:
task.service.js
$ngTask.factory("$taskService", [
"$resource",
function ($resource) {
var taskModelUrl = 'api/task/';
return {
rest: {
taskUpload: $resource(taskModelUrl, {
id: '#id'
}, {
save: {
method: "POST",
isArray: false,
headers: {"Content-Type": undefined},
transformRequest: angular.identity
}
})
}
};
}
]);
And then use it in a module:
task.module.js
$ngModelTask.controller("taskController", [
"$scope",
"$taskService",
function (
$scope,
$taskService,
) {
$scope.saveTask = function (name, file) {
var newTask,
payload = new FormData();
payload.append("name", name);
payload.append("file", file);
newTask = $taskService.rest.taskUpload.save(payload);
// check if exists
}
}
Assume that we want to get a list of certain images from a PHP server using the POST method.
You have to provide two parameters in the form for the POST method. Here is how you are going to do.
app.controller('gallery-item', function ($scope, $http) {
var url = 'service.php';
var data = new FormData();
data.append("function", 'getImageList');
data.append('dir', 'all');
$http.post(url, data, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).then(function (response) {
// This function handles success
console.log('angular:', response);
}, function (response) {
// this function handles error
});
});
I have tested it on my system and it works.
Related
Angularjs
app.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
app.service('fileUpload', ['$http', function ($http) {
this.uploadFileAndFieldsToUrl = function(file, fields, uploadUrl){
var fd = new FormData();
fd.append('file', file);
console.log(file) //File { name: "franklindroosevelt1.jpg", lastModified: 1522139208000, lastModifiedDate: Date 2018-03-27T08:26:48.000Z, webkitRelativePath: "", size: 63159, type: "image/jpeg" }
for(var i = 0; i < fields.length; i++){
fd.append(fields[i].name, fields[i].data)
}
console.log(file)//File { name: "franklindroosevelt1.jpg", lastModified: 1522139208000, lastModifiedDate: Date 2018-03-27T08:26:48.000Z, webkitRelativePath: "", size: 63159, type: "image/jpeg" }
$http.post(Appname+"/upload_image/", fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
app.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.$watch('myFile', function(newFileObj){
if(newFileObj)
$scope.filename = newFileObj.name;
});
$scope.uploadForm = function(){
var file = $scope.myFile;
var uploadUrl = "/formUpload";
var fields = [{"name": "filename", "data": $scope.filename}];
fileUpload.uploadFileAndFieldsToUrl(file, fields, uploadUrl);
};
}]);
HTML
<div class="maincontent">
<div ng-app="Appschedule" ng-controller="myCtrl" class="container container1">
<p>
<input type="file" file-model="myFile"/>
</p>
<p>
<label>File Name:</label>
<input type="text" ng-model="filename"></input>
</p>
<button ng-click="uploadForm()">upload me</button>
</div>
</div>
I had written a code to upload a image into directory , here i want to change the image name based on input text or any random name.I cant change the name , the name remains same while uploading. Is there any other way to send the name. please help me
Is there any other way to send the name?
Here is code showing how to send name as string and file in the same request:
myApp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
var info = {
"text":"file_name"
};
fd.append('data', angular.toJson(info));
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
On server side it's in req.body.data, so it can be received i.e. like this:
upload(req, res, function (err) {
if (err) {
res.json({error_code: 1, err_desc: err});
return;
}
console.log(req.body.data);
res.json({error_code: 0, err_desc: null});
})
Here is my code to upload file to server on input change
$scope.uploadImage = function (f) {
$http.post('/art',{'image':f},{headers: {'Content-Type': undefined}}).then(function (response) {
console.log(response);
});
}
but i will get empty files in server however i check my serverside code with normal fileupload it works fine without any problem
Serverside
//get empty in angular upload
console.log(req.file('image'));
req.file('image').upload({
// don't allow the total upload size to exceed ~10MB
maxBytes: 10000000
},function whenDone(err, uploadedFiles) {
return res.json({
'status':uploadedFiles
})
});
HTML
<input type="file" ng-model="art.artImage" onchange="angular.element(this).scope().uploadImage(this.files)" name="artImage" id="artImage">
I believe its problem with content-type in angular http post request
when the input type is file file will not attach the model. You need a workaround like this.
.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread = loadEvent.target.result;
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}]);
change the input like
<input type="file" fileread="art.artImage" onchange="angular.element(this).scope().uploadImage(this.files)"
name="artImage" id="artImage">
use the multipart header in your request
$http.post('/art', {
'image': art.artImage
}, {
transformRequest: angular.identity,
headers: {
'Content-Type': "multipart/form-data"
}
})
Use ng-fileUpload lib for angularjs
My HTML
<form method="post" enctype="multipart/form-data" ng-controller="commentCtrl" name="form">
<img src="source/assets/images/icons/icofileattached.png" class="attachmentpng-height" ngf-select="uploadFiles($file)" ng-model="files"/>
<md-button type="submit" class="md-raised custom-submit-button" ng-click="MakeComments()"> SUBMIT </md-button>
</form>
My Controller code
$scope.uploadFiles = function(file) {
console.log(file);
$scope.fileData = file;
var fd = new FormData();
fd.append('file', file);
Restangular.one('/api/files/end points').withHttpConfig({transformRequest: angular.identity})
.customPOST(fd, '', undefined, {'Content-Type': undefined})
};
Please try this , avoid using onload in HTML tag for file :
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
</head>
<body ng-app = "myApp">
<div ng-controller = "myCtrl">
<input type = "file" file-model = "myFile"/>
<button ng-click = "uploadFile()">upload me</button>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
alert("Done");
})
.error(function(){
alert("Sorry");
});
}
}]);
myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "/art";
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
</script>
</body>
</html>
I am working on a project that uses Angularjs for the FrontEnd and Java Webservices in the backend. I am trying to upload and send an Image through JSON.
The Images when uploaded, generates a blob url ( blob:http://localhost/a34ac19f-3320-4cdf-b30f-e1b0a0e7a745 ) in src. How can I read it and convert it to Base64 or other types that can be sent through JSON?
First of all add this custom directory right below your controller :
app.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Then in you view use it like this :
<input type = "file" name="files" file-model = "myFile"/>
In your controller function when youf form will submitted :
Do it like this :
$scope.formSubmit = function(){
var file = $scope.myFile;
var fd = new FormData();
fd.append('profilepic', file);
fd.append('action', 'add');
$http.post('yourjavafile', fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
}).success(function (response) {
if (response) {
} else {
}
});;
}
I have the following HTML.
<form >
<input type="file" file-model="myFile"/>
<button ng-click="uploadFile()">upload me</button>
</form>
And inside controller I have following function
$scope.uploadFile = function() {
var file = $scope.myFile; //when I try console.log(file...it says undefined)
var fd = new FormData();
fd.append('file', file);
$http.post("url", fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
transformResponse: [function (data) {
return data;
}]
}).then(function (result) {
console.log(result.data);
})
}
the Directives I have is
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
For some reason, I am not getting the file value. On console.log() I am receiving undefined. FYI, I am just trying to grab a file. Is there something wrong in my code?
I came to that conclusion because it seems to have passing undefined to server from browser's developer tool. The screen-grab is as follows.
The problem was non binding issue with files. Angular has no support for that yet. It was solved with the solution provided here.
AngularJs: How to check for changes in file input fields?
This worked for me:
<div>
<input id="imageList" name="imageList" type="file" file-model="myFile">
</div>
I also had a json object to send with the form:
$scope.saveForm = function () {
var formData = new FormData();
var file = $scope.myFile;
formData.append("file", file);
var req = {
url: '/upload',
method: 'POST',
headers: {'Content-Type': undefined},
data: formData,
transformRequest: function (data, headersGetterFunction) {
return data;
}
};
Angular suggests setting 'Content-Type' header to undefined (https://docs.angularjs.org/api/ng/service/$http) so that the browser can pick up the file data and supply the correct Content-Type header.
But even when I upload a PDF, the content-type is set to 'text/plain;charset=UTF-8'. I want the content-type to be set to multipart, because this is what the backend expects, but how can I make this happen, if the browser is responsible for setting the content-type?
I have also tried this post's tactic but to no avail. I have also tried using Dropzone.js with the same result.
Here's the code for the request itself:
uploadFile: function(token, baseurl, projectname, filename, file) {
var dataUpload= {
method: 'PUT',
url: baseurl + '/projects/' + projectname + '/files/' + filename,
transformRequest: angular.identity,
headers: {
'Authorization': 'bearer ' + token,
'Accept': "application/json",
'Content-Type': undefined
},
data: {
'files': file
}
};
return dataUpload;
}
Below I am including the code from the post previously linked which is supposed to work but when I used it with my own url the same thing happens: the browser sets Content-Type to 'text/plain;charset=UTF-8' and I get a 415 error from the backend. How? Why? Any help (including workarounds for the backend) would be extremely appreciated. I've been working on this for days.
The JavaScript:
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('fileUpload', ['$http', function ($http) {
this.uploadFileToUrl = function(file, uploadUrl){
var fd = new FormData();
fd.append('file', file);
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function(){
})
.error(function(){
});
}
}]);
myApp.controller('myCtrl', ['$scope', 'fileUpload', function($scope, fileUpload){
$scope.uploadFile = function(){
var file = $scope.myFile;
console.log('file is ' );
console.dir(file);
var uploadUrl = "/fileUpload";
fileUpload.uploadFileToUrl(file, uploadUrl);
};
}]);
The HTML:
<div ng-controller = "myCtrl">
<input type="file" file-model="myFile"/>
<button ng-click="uploadFile()">upload me</button>
</div>
I guess it's too late to answer this but in case someone came across with the same problem.
The error in your code is here:
data: {
'files': file
}
Your form data object already has the information of the field your backend is expecting so, you need to change that line for:
data: file
If you've created the FormData object manually you'll probably have something like this:
var fd = new FormData();
fd.append("files", $scope.file);