Uploading file in API makes error 400 - angularjs

I'm working on an API project which communicate with another API, my front is AngularJS
I try to upload a file (a picture) an post it through an API which already works for other posts (other posts are not uploads, just data)
I can upload the picture and treat it in a formdata, but when I try to post it, I have a 400 error with no 'Access-Control-Allow-Origin'. But my others post methods work well but this one makes trouble.
My Ajax post method:
apiDataService.postPicture = function(formData, callback) {
$http({
method: 'POST',
url: apiUrl + '/pictures',
data: formData,
contentType: false,
processData: false,
headers: {
'Authorization': localStorageService.get('auth')
}
}).then(function successCallback(response) {
// retrieve response data
callback(response.data);
}, function errorCallback(response) {
// an error occured
});
};
I took the pattern of my others post methods so, it would works...
My uploading function:
self.addPicture = (image) => {
var fileInput = document.getElementById('the-file');
var file = fileInput.files[0];
var formData = new FormData();
formData.append('file', file);
apiDataService.postPicture(formData);
}
And my view:
<form id="form-id">
<div class="col-xs-12">
<span>Image :</span>
<br/>
<input id="the-file" type="file" placeholder="Image du Procédé" ng-model="picture.file" class="form-control" />
</div>
<div class="col-xs-12">
<button ng-click="addPicture(image)">Enregistrer image</button>
</div>
</form>
If you have any ideas, I don't understand my error...

It is certainly due to your CORS options your server are using. Maybe you don't allow data header or something like that.

#Nounnoune can you try to add below header I had Same Problem so I added below header and work like charm .
'Content-type': 'application/x-www-form-urlencoded; charset=utf-8'

There are already many Angular.js modules to perform file uploading.
These two have explicit support for older browsers:
Uses iframes as a fallback
Uses FileAPI/Flash as a fallback

I finally got a good form, a basic one only in HTML, it's not as pretty as I would like it to be, but it works! Just have to optimize it.

Related

Upload File and Data with Angularjs in MVC .net core

<input type="file" ng-model="ch.FileName" id="file" name="myFile" nchange="angular.element(this).scope().saveChapter(this.files)"/>
Action Method,Js and other Code
Upload File and Data with Angularjs in MVC .net core
If you'd like to post binary data with other additional information/data from your angularjs frontend to WebAPI backend, you can try to pass the data through FormData object, like below.
var formdata = new FormData();
formdata.append('chapterID', $scope.ch.ChapterID);
formdata.append('bookID', $scope.ch.BookID);
formdata.append('chapterName', $scope.ch.FileName);
//...
formdata.append('cHFile', $scope.chfile);
$http({
method: 'POST',
url: 'your_request_url_here',
headers: { 'Content-Type': undefined },
data: formdata
}).then(function mySuccess(response) {
//...
In browser developer tool Network tab, can find the data passed as expected
Test Result

Upload file without using Formdata in AngularJs

Is there any way to upload files without using formdata in Angular Js. I have checked the below links, which have not helped:
https://stackoverflow.com/questions/32432299/upload-file-using-jquery-without-using-html5
How to send/ Upload file without using FORMDATA in jquery ajax
How can I upload file in JavaScript and PHP without using FormData
I do not want to use any plug-in, and cannot use iframes. I want to upload single file. I have the service created as below, to which I have to pass the image data.
myAPIService.postUploadImage = function (formdata) {
var request = {
url: urlBase + 'UploadImage',
method: 'POST',
data: formdata,
headers: {
'Content-Type': undefined
}
}
return $http(request);
};
The UI is defined as below:
<input type="file" class="form-control" id="imageUploadfile" name="Imagefile" accept="image/*" />
<input type="button" name="imageUploadButton" ng-click="uploadFiles()" value="Upload" />
Requesting Admin/moderators to not mark it as duplicate, as I have tried most of the links, but that has not worked.
How to upload single file in AngularJS without using plugins,iframe and which works in IE 11, Chrome.
Thanks

How send POST request in angularjs with _csrf?

I want sending POST requests to service under spring security.
if i using form submission (with hidden input) - it's working fine.
But i don't know, how send request with $http.post.
my form:
<form method="POST" type="submit" action="http://localhost:8888/rest/post1" />
<button>345</button>
<input name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
it work.
I save params:
<script>
var a = "${_csrf.parameterName}";
var b = "${_csrf.token}";
</script>
My ng-click function:
$http.post('http://localhost:8888/rest/post1', {"_csrf": b}, {
"headers" :
{ "_csrf" : b }
}).success(function(data) {
console.log("ok");
}).error(function(){
console.log("no");
});
It always writing "no".
I think, that need to send variable as webForm, but how do it in $http.post?
Fiddler write: Content-Type is 'application/json'; this inspector supports 'x-www-form-urlencoded' only
Server console:
org.springframework.web.servlet.PageNotFound handleHttpRequestMethodNotSupported
WARNING: Request method 'POST' not supported
Help me, please!
You might need to set "_csrf" in the request header. You are passing it as an argument for a method. This won't work. I am not much aware of angular.js but you must need to pass it as request header or request payload. I found some reference. Here it goes:
$httpProvider.defaults.xsrfCookieName = 'csrftoken';
$httpProvider.defaults.xsrfHeaderName = 'X-CSRFToken';
Hope this helps you to solve your problem. Cheers !!!
I solved this)
var request = $http({
method: "post",
url: "http://localhost:8888/rest/post1",
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(){return a+"="+b;},
data: {}
});

change Content-type to "application/json" POST method, RESTful API

I am new at AngularJS and I needed your help.
All I need just need is to POST my json to the API and recieve the proper response.
Here's my JSON where i don't know where to code this.
JSON
{
"userId" :"testAgent2",
"token" :"testAgent2",
"terminalInfo":"test2",
"forceLogin" :"false"
}
NOT SURE IF I'm doing this right.
CONTROLLER.JS
function UserLoginCtrl($scope, UserLoginResource) {
//Save a new userLogin
$scope.loginUser = function() {
var loggedin = false;
var uUsername = $scope.userUsername;
var uPassword = $scope.userPassword;
var uforcelogin = 'true';
UserLoginResource.save();
}
}
SERVICES.JS
angular.module('UserLoginModule', ['ngResource'])
.factory('UserLoginResource', function($resource, $http) {
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common['X-Requested-With'];
$http.defaults.headers.post["Content-Type"] = "application/json"; //NOT WORKING
return $resource('http://123.123.123.123\\:1234/SOME/LOCATION/THERE', {}, {
save: {
method:'POST',
headers: [{'Content-Type': 'application/json'}]
} //NOT WORKING EITHER
});
});
INDEX.HTML
<html ng-app>
<head>
<script src="js/lib/angular/angular.js"></script>
<script src="js/lib/angular/angular-resource.js"></script>
</head>
<body ng-controller="UserLoginCtrl">
<form class="form-horizontal" name="form-horizontal" ng-submit="loginUser();">
<div class="button-login">
<!-- start: button-login -->
<button class="btn btn-primary" type="submit">Login</button>
</div>
</form>
</body>
</html>
I kept on getting a response like Unsupported Media Type. I don't know, what else to do.
Assuming you are able to use one of the more recent "unstable" releases, the correct syntax to change the header is.
app.factory('BarService', function ($resource) {
var BarService = $resource('/foo/api/bars/:id', {}, {
'delete': {
method: 'DELETE',
headers: {
'Content-Type': 'application/json'
}
}
});
return BarService;
});
I find the $resource service is a tremendously powerful tool for building applications and has matured to a point that you do not need to fall back to $http as much. Plus its active record like patterns are damn convenient.
Posting a JSON object is quite easy in Angular. All you need to do is the following:
Create a Javascript Object
I'll use your exact properties from your code.
var postObject = new Object();
postObject.userId = "testAgent2";
postObject.token = "testAgent2";
postObject.terminalInfo = "test2";
postObject.forceLogin = "false";
Post the object to the API
To post an object to an API you merely need a simple $http.post function. See below:
$http.post("/path/to/api/", postObject).success(function(data){
//Callback function here.
//"data" is the response from the server.
});
Since JSON is the default method of posting to an API, there's no need to reset that. See this link on $http shortcuts for more information.
With regards to your code specifically, try changing your save method to include this simple post method.
The right way to set 'Content-Type': 'application/json' is setting a transformRequest function for the save action.
angular.module('NoteWrangler')
.factory('NoteNgResource', function NoteNgResourceFactory($resource) {
// https://docs.angularjs.org/api/ngResource/service/$resource
return $resource("./php/notes/:id", {}, {
save : { // redefine save action defaults
method : 'POST',
url : "./php/notes", // I dont want the id in the url
transformRequest: function(data, headers){
console.log(headers);
headers = angular.extend({}, headers, {'Content-Type': 'application/json'});
console.log(headers);
console.log(data);
console.log(angular.toJson(data));
return angular.toJson(data); // this will go in the body request
}
}
});
});
It seems there isn't a method to clear query parameters, the request will have both...

AngularJS: how to implement a simple file upload with multipart form?

I want to do a simple multipart form post from AngularJS to a node.js server,
the form should contain a JSON object in one part and an image in the other part,
(I'm currently posting only the JSON object with $resource)
I figured I should start with input type="file", but then found out that AngularJS can't bind to that..
all the examples I can find are for wraping jQuery plugins for drag & drop. I want a simple upload of one file.
I'm new to AngularJS and don't feel comfortable at all with writing my own directives.
A real working solution with no other dependencies than angularjs (tested with v.1.0.6)
html
<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>
Angularjs (1.0.6) not support ng-model on "input-file" tags so you have to do it in a "native-way" that pass the all (eventually) selected files from the user.
controller
$scope.uploadFile = function(files) {
var fd = new FormData();
//Take the first selected file
fd.append("file", files[0]);
$http.post(uploadUrl, fd, {
withCredentials: true,
headers: {'Content-Type': undefined },
transformRequest: angular.identity
}).success( ...all right!... ).error( ..damn!... );
};
The cool part is the undefined content-type and the transformRequest: angular.identity that give at the $http the ability to choose the right "content-type" and manage the boundary needed when handling multipart data.
You can use the simple/lightweight ng-file-upload directive.
It supports drag&drop, file progress and file upload for non-HTML5 browsers with FileAPI flash shim
<div ng-controller="MyCtrl">
<input type="file" ngf-select="onFileSelect($files)" multiple>
</div>
JS:
//inject angular file upload directive.
angular.module('myApp', ['ngFileUpload']);
var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
$scope.onFileSelect = function($files) {
Upload.upload({
url: 'my/upload/url',
file: $files,
}).progress(function(e) {
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}];
It is more efficient to send a file 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:
$scope.upload = function(url, file) {
var config = { headers: { 'Content-Type': undefined },
transformResponse: angular.identity
};
return $http.post(url, file, config);
};
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.
To send multiple files, see Doing Multiple $http.post Requests Directly from a FileList
I figured I should start with input type="file", but then found out that AngularJS can't bind to that..
The <input type=file> element does not by default work with the ng-model directive. It needs a custom directive:
Working Demo of "select-ng-files" Directive that Works with ng-model1
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="fileArray" multiple>
<h2>Files</h2>
<div ng-repeat="file in fileArray">
{{file.name}}
</div>
</body>
$http.post with content type multipart/form-data
If one must send multipart/form-data:
<form role="form" enctype="multipart/form-data" name="myForm">
<input type="text" ng-model="fdata.UserName">
<input type="text" ng-model="fdata.FirstName">
<input type="file" select-ng-files ng-model="filesArray" multiple>
<button type="submit" ng-click="upload()">save</button>
</form>
$scope.upload = function() {
var fd = new FormData();
fd.append("data", angular.toJson($scope.fdata));
for (i=0; i<$scope.filesArray.length; i++) {
fd.append("file"+i, $scope.filesArray[i]);
};
var config = { headers: {'Content-Type': undefined},
transformRequest: angular.identity
}
return $http.post(url, fd, config);
};
When sending a POST with the FormData API, it is important to set 'Content-Type': undefined. The XHR send method will then detect the FormData object and automatically set the content type header to multipart/form-data with the proper boundary.
I just had this issue. So there are a few approaches. The first is that new browsers support the
var formData = new FormData();
Follow this link to a blog with info about how support is limited to modern browsers but otherwise it totally solves this issue.
Otherwise you can post the form to an iframe using the target attribute.
When you post the form be sure to set the target to an iframe with its display property set to none.
The target is the name of the iframe. (Just so you know.)
I hope this helps
You could upload via $resource by assigning data to params attribute of resource actions like so:
$scope.uploadFile = function(files) {
var fdata = new FormData();
fdata.append("file", files[0]);
$resource('api/post/:id', { id: "#id" }, {
postWithFile: {
method: "POST",
data: fdata,
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
}
}).postWithFile(fdata).$promise.then(function(response){
//successful
},function(error){
//error
});
};
I know this is a late entry but I have created a simple upload directive. Which you can get working in no time!
<input type="file" multiple ng-simple-upload web-api-url="/api/post"
callback-fn="myCallback" />
ng-simple-upload more on Github with an example using Web API.
I just wrote a simple directive (from existing one ofcourse) for a simple uploader in AngularJs.
(The exact jQuery uploader plugin is https://github.com/blueimp/jQuery-File-Upload)
A Simple Uploader using AngularJs (with CORS Implementation)
(Though the server side is for PHP, you can simple change it node also)

Resources