Using $resource to upload file - angularjs

I have gone through all the questions on this website on this topic and pretty much tried all codes. Following is the latest snippet that I have borrowed from the answers listed on this website. I am trying to upload a file asynchronously to AWS s3 endpoint. I get my signed url correctly but am unable to actually upload the file.
HTML:
<form name="Details" ng-controller="DetailsController">
<input type="file" file-input="files" />
<button ng-click="initUpload()">Upload</button>
</form>
fileInput Directive and DetailsController:
module.directive('fileInput', ['$parse', function ($parse) {
return {
restrict: 'A',
link:function(scope, elm, attrs){
elm.bind('change', function(){
$parse(attrs.fileInput)
.assign(scope, elm[0].files);
scope.$apply();
});
}
}
}]).controller("DetailsController", ["$scope", "PostalService",
function ($scope, PostalService) {
getSignedURLForUpload = function(userId, filename, filetype){
return (PostalService.getSignedURLForUpload(userId, filename, filetype));
};
$scope.initUpload = function(){
var signedUrl = getSignedURLForUpload($scope.userId, $scope.files[0].name,$scope.files[0].type);
signedUrl.then(function (data) {
var uploadPromise = PostalService.uploadFile($scope.files, data.signedRequest);
uploadPromise.then(function(result) {
$scope.awsurl = data.url;
});
});
};
]);
PostalService:
module.factory("PostalService",
["$resource",
function($resource) {
var functions = {
getSignedURLForUpload: function(userId, filename, filetype) {
var SignUrl = $resource("host end point?userid="+userId+"&file-name="+filename+"&file-type="+filetype);
var promise = SignUrl.get().$promise;
return promise;
},
uploadFile: function(file, signedRequest) {
var Upload = $resource(signedRequest, null, {
'save':{
method: 'POST',
transformRequest: function(data){
var fd = new FormData();
angular.forEach(data, function(value, key) {
if(value instanceof FileList) {
if(value.length ===1){
fd.append(key, value[0]);
}else {
angular.forEach(value, function(file, index){
fd.append(key+'_'+index, file);
});
}
}else {
fd.append(key, value);
}
});
return fd;
},
headers: {'Content-Type' : undefined}
}
});
var promise = Upload.save(file).$promise;
return promise;
}
};
return functions;
}
]);

So the issue was in implementation of uploadFile function of PostalService.
The headers needed to be set properly:
1. 'Content-Type' : 'image/jpeg'
2. Authorization: 'undefined'
Authorization headers were being automatically set by my application and in this case, I had to nullify them as the particular url link used to upload the file to the server was pre-signed and signature was part of the query.
Content type needed to be 'image/jpeg' and not undefined as that was expected by my backend server.
Finally, the method 'POST' didn't work. Had to replace it with 'PUT' instead.

Related

sending files via POST with AngularJS

I have a problem sending data via POST in angular,
my data include 2 files and some text field,
the problem is that the service doesn't receives any data.
this is my code:
var inputs = document.querySelectorAll( 'input[type="file"]' );
Array.prototype.forEach.call( inputs, function( input ){
input.addEventListener( 'change', function( e ){
if(this.id == "zipToUpload")
$scope.zipToUpload = this.files[0];
else
$scope.imgToUpload = this.files[1];
});
});
$scope.submit = function(){
var getInput = {nome: $scope.app_name, zipToUpload: $scope.zipToUpload, imgToUpload: $scope.imgToUpload, url: $scope.app_url,
secure: $scope.checkbox_pass, hide: $scope.checkbox_hide, beta: $scope.checkbox_beta, password: $scope.app_pass, location: "1" };
var req = {
method: 'POST',
url: 'api/rest/app/insert_app.php',
headers: {
'Content-Type': undefined
},
data: getInput
}
$http(req)
.then(function(result) {
console.log(result);
});
}
You can not directly upload file using model in angular. First you need a directive to bind files to the model.
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]);
});
});
}
};
}]);
And the input will be like :
<input type = "file" file-model = "myFile"/>
And the you can send post request using form data
$scope.upload = funtion(){
var fd = new FormData();
fd.append('file', $scope.myFile);
var req = {
method: 'POST',
url: 'api/rest/app/insert_app.php',
headers: {
'Content-Type': undefined
},
data: fd
}
$http(req)
.then(function(result) {
console.log(result);
});
}

is it possible to send uploaded file from angularjs to spring controller but by formbean

I have form having text field and file type. I want to send this to controller using form bean. here is my code.following is my js file. from where I'm sending multipart file.
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, uploadform) {
var fd = new FormData();
fd.append('file', file);
fd.append("jsondata", JSON.stringify(uploadform));
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined}
})
.success(function () {
})
.error(function () {
});
}
}]);
myApp.controller('myFileUpload', ['$scope', 'fileUpload', function ($scope, fileUpload) {
$scope.uploadFile = function () {
var file = $scope.myFile;
$scope.uploadform = {};
var uploadUrl = "navigation/uploadexcel";
fileUpload.uploadFileToUrl(file, uploadUrl, $scope.uploadform);
};
}]);
and my controller is..I want to map multipart file and textbox value into firmbean first and from that I want to get my file for further process.
#RequestMapping(value = "/uploadexcel", method = RequestMethod.POST)
public #ResponseBody
String upload(#RequestBody EmployeeFormBean fb) {
String res = null;
try {
MultipartFile f = fb.getFile();
System.out.println("-->"+ f.getOriginalFilename());
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
my jsp code is as following
<div style="background-color: blanchedalmond">
<div ng-controller = "myFileUpload">
<input type="file" file-model="myFile"/>
<input type="text" name="template" ng-model="uploadform.templateName"/>
<button ng-click="uploadFile()">upload me</button>
</div>
</div>
but m getting error as follow...
415 Unsupported Media Type
59ms
angular...DF52B9C (line 103)
HeadersPostResponseHTMLCookies
"NetworkError: 415 Unsupported Media Type - http://localhost:8080/crmdemo1/navigation/uploadexcel"
how to resolve this issue. I dont want to do it by #resuestparam("file")
is it possible to do this using formbean.. and if yes please tell me how can I do it?
You have a problem in the content type of your request, try to add headers = "content-type=multipart/*" , consumes = "application/json" to #RequestMapping. Beside that (in your service fileUpload) change the headers: {'Content-Type': undefined} to headers: {'Content-Type': application/json}. Hope this will help you

Sending data & file from Angular to Web API

Trying to send some data & attachment(file) from AngularJS Client to MVC Web API and it does not work: I can see all the fields except of the attached file, which is shown as null
Here's the Model:
class Model{
... //the fields
public HttpPostedFileBase Photo { get; set; }//Attachment file, represented as an image
}
Here's the Web API:
public IHttpActionResult CreateModel([FromBody]Model model)
{
...
}
Here's the AngularJS code:
(function () {
angular.module("application")
.controller("homeCtrl", ["$scope", "entityService",
function ($scope, entityService) {
$scope.createModel = function (model)
{
entityService.createModel(model)
.then(function (data) {
console.log(data);
});
};
$scope.model = {
FirstName: "John",
LastName: "Doe"
};
}]);
})();
"use strict";
(function () {
angular.module("application")
.factory("entityService", ["akFileUploaderService", function (akFileUploaderService) {
var createModel = function (model) {
return akFileUploaderService.saveModel(model, "/api/CreateModel");
};
return {
createModel: createModel
};
}]);
})();
(function () {
"use strict"
angular.module("akFileUploader", [])
.factory("akFileUploaderService", ["$q", "$http",
function ($q, $http) {
var saveModel = function (data, url) {
var deferred = $q.defer();
$http({
url: url,
method: "POST",
data: JSON.stringify(data),
transformRequest: angular.identity,
headers: { 'Content-Type': "application/json" }
}).success(function (result) {
deferred.resolve(result);
}).error(function (result, status) {
deferred.reject(status);
});
return deferred.promise;
};
return {
saveModel: saveModel
}
}])
.directive("akFileModel", ["$parse",
function ($parse) {
return {
restrict: "A",
link: function (scope, element, attrs) {
var model = $parse(attrs.akFileModel);
var modelSetter = model.assign;
element.bind("change", function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
})(window, document);
And here's HTML View:
....
<div class="form-group">
<label for="attachment">Photo:</label>
<div class="col-md-10">
<input type="file" name="attachment" class="form-control" data-ak-file-model="model.Photo" />
</div>
</div>
<button type="button" ng-disabled="newForm.$invalid" ng-click="createModel(model)" class="btn btn-primary">
Create
</button>
WebApi doesn't (currently) use the same mechanism as MVC with HttpPostedFileBase. See this question answer as an example to handling file uploads - a sample is below (simplified from the answer):
public async Task<HttpResponseMessage> AddFile()
{
string root = HttpContext.Current.Server.MapPath("~/temp/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
foreach (var key in provider.FormData.AllKeys)
{
foreach (var val in provider.FormData.GetValues(key))
{
if (key == "aFormValue")
{
// do something with form data value
}
}
}
return this.Request.CreateResponse(HttpStatusCode.OK);
}
In a nutshell, you have to read the contents of the request picking out the file (and sometimes form) parts. You can use the built-in MultipartFormDataStreamProvider class and ReadAsMultipartAsync method on the HttpContent to do this.
The method above assumes you want to save to disk, when you want to put the file somewhere else it gets a little more tricky and you have to roll your own implementation of MultipartFormDataStreamProvider to handle this.

need help uploading images

I'm trying to upload an object file which contains 2 attributes, a name and a picture using AngularJS. I know that this topic has been treated multiple times but no matter what I read I can't seem to make it work.
I'm using Java Spring for my server and when I try to upload a "Character" (name + picture) through my client I get this error in my server : "Required request body content is missing"...
Here is my code :
.config(function($stateProvider, $httpProvider, $resourceProvider) {
$resourceProvider.defaults.stripTrailingSlashes = false;
$httpProvider.defaults.transformRequest = function(data) {
if (data === undefined)
return data;
var fd = new FormData();
angular.forEach(data, function(value, key) {
if (value instanceof FileList) {
if (value.length == 1) {
fd.append(key, value[0]);
} else {
angular.forEach(value, function(file, index) {
fd.append(key + '_' + index, file);
});
}
} else {
fd.append(key, value);
}
});
return fd;
}
$httpProvider.defaults.headers.post['Content-Type'] = undefined;
And here is my service :
angular.module('myApp.services', ['ngResource'])
.factory('Character', function($resource) {
return $resource('http://localhost:8080/myApp/character/:id',
{ id: '#id' },
{ update: { method: 'GET', transformRequest: angular.identity, headers: { 'Content-Type': undefined } } }
);
})
.service('popupService', function($window){
this.showPopup = function(message){
return $window.confirm(message);
}
});
And finally this is how I'm using it in my controller :
.controller('CharacterCreateController',function($scope,$state,$stateParams,Character){
$scope.character = new Character();
$scope.addCharacter = function(){
$scope.character.$save(function(){
$state.go('characters');
});
}
})
Could anyone please help me ??? I really don't know what to do and it's my first time trying to upload files using Angular.

net::ERR_INVALID_URL when setting <img> src from $http.get result

I have a angular directive that works on img tags and loads the image dynamically as a base64 string. I use $http.get to load the image and set it into the img.src like this:
var onSuccess = function(response) {
var data = response.data;
element.attr("src", "data:image/png;base64," + data);
};
var onError = function(response) {
console.log("failed to load image");
};
scope.$watch('authSrc', function(newValue) {
if (newValue) {
$http({
method: "GET",
url: scope.authSrc,
data: ""
}).then(onSuccess, onError)
}
});
after i set the src attribute, i get the net::ERR_INVALID_URL error.
The string that returns from the request looks like this:
IHDR����^tiDOT#(##AMȯz�#IDATx��uw\�ٷ�o����G�B["...
Any ideas?
thanks
Got it to work will the help of This link.
Trick was to use responseType: "blob", and use URL/webkitURL createObjectURL()
Here's the full directive:
'use strict';
app.directive('authSrc',function ($http) {
return {
restrict: 'A',
scope: {
authSrc: "="
},
link: function (scope, element) {
var onSuccess = function(response) {
var data = response.data;
var url = window.URL || window.webkitURL;
var src = url.createObjectURL(data);
element.attr("src", src);
};
var onError = function(response) {
console.log("failed to load image");
};
scope.$watch('authSrc', function(newValue) {
if (newValue) {
$http({
method: "GET",
url: scope.authSrc,
responseType: "blob"
}).then(onSuccess, onError)
}
});
}
}
});
Specify the responseType in your request, and you may have to disable default transforms that $http attempts on the data.
see here
My problem was specifying a zoom level after the base64 string '#zoom=90'

Resources