Angular JS + Spring 4 : Upload File and Form Data - angularjs

We are using Spring 4 (Annotation based configuration) and AngularJS for building our application. In one of the usecase, we need to upload a document. On submitting the form, we need to send the form data (apart from file uploaded file, there are fields which are part of the form) and the file content as part of the POST request.
#Bean(name="multipartResolver")
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
return multipartResolver;
}
The HTML form contents:
<form method="post" id="fromFileUpload"
enctype="multipart/form-data" ng-submit="create()">
<div class="form-group">
<label for="inputValue" class="col-md-offset-2 col-md-4 form-element">Input Value</label>
<div class="col-md-6 form-element">
<input class="form-control" ng-model="model.value"
name="val" required autofocus>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-4 col-xs-12" for="file">Please
upload the file : <span class="required">*</span>
</label>
<div class="col-xs-4 input-max controls ">
<input class="inline-block" type="file" name="file"
ng-model="file" data-rule-required="true" id="file"
accept=".xls">
</div>
<span id="vaildFile" class="text-success icon-ok hide">Valid
File</span> <span id="invaildFile" class="text-error icon-remove hide">
Invalid File</span>
</div>
<div class="box-header">
<div class="actions">
<button type="submit" class="btn btn-primary">
<i class="icon-arrow-right"></i> Create
</button>
</div>
</div>
</form>
Below is the angularJS code :
$scope.create = function() {
var formData=new FormData();
formData.append("file",$scope.file);
formData.append("docData", angular.toJson($scope.model));
console.log(formData);
$http({
method: 'POST',
url: "http://localhost:8080/saprof/value",
headers: {'Content-Type': false},
data: formData,
transformRequest: function(data, headers) {
return data;
}
})
.success(function(data, status) {
alert("Success");
})
.error(function(data, status) {
alert("Error");
});
};
Below is the controller Code (Annotated with #RestController)
#RequestMapping(value="/saprof/value", method=RequestMethod.POST)
public void createValue(HttpServletRequest request, HttpServletResponse response, HttpSession session){
LOGGER.info("Request is of type MultiPartRequest "+(request instanceof MultipartHttpServletRequest)); // false
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
LOGGER.info("isMultiPart Request : "+isMultipart); // false
}
Problem:
I am getting RequestFacade object as the request object and not MultiPartServletRequest. Hence i am not able to retrieve the form data + file contents from this request.
When see the request which is been sent using browser, below is the content:
Request Payload
------WebKitFormBoundaryzfZtWVlK6xH8aSyf
Content-Disposition: form-data; name="file"
[object Object]
------WebKitFormBoundaryzfZtWVlK6xH8aSyf
Content-Disposition: form-data; name="docData"
{"value":"test"}
------WebKitFormBoundaryzfZtWVlK6xH8aSyf--
Need your help in correcting my mistakes. Let me know if you need any further details. Really appreciate your help.
Regards,
Manjunath

I used this module on my own project and it worked like a charm:
danialfarid/ng-file-upload

Related

angular: form submit with dynamic dropdown list

I have a small form and in that form i have a drop down list. List items are generated dynamically.
$http({
url: 'alljobs.php',
method: "GET",
params: {
uid: viewer_id
}
}).success(function(data) {
$scope.jobss = data.content;
});
Below is the code for form submit.
$scope.formprofile33 = function() {
var allData33 = {
'msg': $scope.msg,
'emp_id': viewer_id,
'job_id': job.job_id,
'job_title': $scope.jobss.SelectedOption.job_title,
// 'job':job,
'user_id': user_id
}
$http({
method: 'POST',
url: 'send_msg.php',
data: allData33,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).success(function(data) {
if (!data.success) {
$scope.message = data.errors.message;
} else {
$scope.message = '';
alert('Your message has been sent.');
$scope.message = '';
}
});
};
Here is the form.
<form name="formProfile33" method="post" id="formProfile33" role="form" ng-submit="formprofile33()">
<div class="container">
<div class="row">
<div class="col-xs-12">
<div class="row">
<div class="col-xs-10">
<div class="col-xs-12 s_ma">
<select id="job" name="job" class="search_color selectors form-control" ng-model="job" required="required" ng-options="item.job_title for item in jobss track by item.job_id">
<option value=""> Select Job *</option>
</select>
</div>
<textarea name="msg" ng-model="msg" class="form-control textbox1" id="msg" placeholder="Write your message" required="required" rows="3"></textarea>
</div>
</div>
</div>
</div>
<center>
<button type="submit" class="btn btn-home" name="btn-save1" id="btn-save1" required="required"><i class="icon ion-email"></i> Send Message </button>
</center>
</div>
</form>
Problem is i am not able to pass dropdown value and id during form submit.
I am getting below error.
TypeError: Cannot read property 'job_title' of undefined
Please advise how can i submit the form with dropdown id and value.
Your example set a job item to the scope field "job" => ng-model="job",
the full selected item is accessible with $scope.job.
Try $scope.job.job_title or $scope.job.job_id
A print out in your html is anytime a good helper: Full job item: {{job | json}}
https://plnkr.co/edit/VenFVchI0brGZNC2Q7Fn?p=preview

AngularJS http POST using form not working

// http.post gives 404 error no matter what so I am trying with GET
// $scope.user.name etc does bring correct values from form
// I think we can't view FormData on console but passing the 'data
// after appending $scope values, runs the get request without any //data
// so I tried to make a plain dummy object 'obj' with static
// values to check get request
// this too runs URL with no data
// response that i recieve is //{"success":"no","data":"","error_code":"DSWS3","error_descriptio//n":"Server Error"}
//and yes, testing the API with same parameters on Postman does //give correct result
var data = new FormData();
data.append('name', $scope.user.name);
data.append('city', $scope.user.city);
data.append('address', $scope.user.address);
var obj = {
name: "fefe",
city: "1",
address: "fofo"
};
var data = JSON.stringify(obj);
console.log(data);
//alert(JSON.stringify(data));
$http.get('http://lowc----.com/storeManager/createParentStore?token=6fc72be8-4153-432e23a9e', data, {
withCredentials: false,
transformRequest: angular.identity,
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
console.log(response)
});
I am stuck at making this HTTP POST work.. I am getting the data from form and I want to append it at the end of the URL like this baseURL+token+&name=store%20name&city=this&address=that
It gives two errors also how can I make an object of the data I received from form to pass to the http data.
1. POST (url i provided) 404 not found
2. Possibly unhandled rejection: {"data":"<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>Error</title>\n</head>\n<body>\n<pre>Cannot POST /storeManager/createParentStore</pre>\n</body>\n</html>\n","status":404,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://lowcost-env.2u3kmcbg4k.us-west-2.elasticbeanstalk.com/storeManager/createParentStore?token=6fc72be8-4153-432e-9191-64a9e3b23a9e","data":{"name":"$scope.user.name","city":"$scope.user.city","address":"$scope.user.address"},"headers":{"Content-Type":"application/x-www-form-urlencoded","Accept":"application/json, text/plain, */*"}},"statusText":"Not Found"}
Here is my HTML
<form class="form-horizontal" name="userForm" ng-submit="submitForm()">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title"><strong>Add new </strong></h3>
</div>
<div class="panel-body form-group-separated">
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Name</label>
<div class="col-md-6 col-xs-12">
<div class="input-group">
<span class="input-group-addon"><span class="fa fa-pencil"></span></span>
<input type="text" class="form-control" name="name" ng-model="user.name" />
</div>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">City</label>
<div class="col-md-6 col-xs-12">
<select class="form-control select" name="city" ng-model="user.city">
<option>Islamabad</option>
<option>Rawalpindi</option>
<option>Karachi</option>
</select>
</div>
</div>
<div class="form-group">
<label class="col-md-3 col-xs-12 control-label">Address</label>
<div class="col-md-6 col-xs-12">
<textarea class="form-control" rows="5" name="address" ng-model="user.address"></textarea>
</div>
</div>
</form>
You should not pass the $scope variables in quotes, remove the quotes and pass it as below,
var data = new FormData();
data.append('name', $scope.user.name);
data.append('city', $scope.user.city);
data.append('address', $scope.user.address);
$http.post('http://low----.com/storeManager/createParentStore?token=6fc72be3-432e-9191-64a9e3b23a9e', data, {
withCredentials : false,
transformRequest : angular.identity,
headers : {
'Content-Type' : undefined
}
}).success(function(response) {
console.log(response)
});
Try this:
$http({ url:'http://low----.com/storeManager/createParentStore?token=6fc72be3-432e-9191-64a9e3b23a9e',
method: "POST",
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
data: JSON.stringify($scope.user),
responseType: 'arraybuffer'
}).success(function(data, status, headers, config) {
console.log("success");
}).error(function(data, status, headers, config) {
console.log("error");
return null;
});

Symfony 2 Angular JS HTTP POST

I have a form that i submit using angularJS http method.
code :
<script>
// define angular module/app
var formApp = angular.module('formApp', []);
// create angular controller and pass in $scope and $http
function formController($scope, $http) {
// create a blank object to hold our form information
// $scope will allow this to pass between controller and view
$scope.formData = {};
// process the form
$scope.processForm = function () {
$http({
method: 'POST',
url: 'http://localhost/angular/web/app_dev.php/testcall',
data: $.param($scope.formData), // pass in data as strings
headers: {'Content-Type': 'application/x-www-form-urlencoded'} // set the headers so angular passing info as form data (not request payload)
})
.success(function (data) {
console.log(data);
if (!data.success) {
// if not successful, bind errors to error variables
$scope.errorName = data.errors.name;
$scope.errorSuperhero = data.errors.superheroAlias;
} else {
// if successful, bind success message to message
$scope.message = data.message;
$scope.errorName = '';
$scope.errorSuperhero = '';
}
});
};
}
</script>
my form :
<div class="container">
<div class="col-md-6 col-md-offset-3">
<!-- PAGE TITLE -->
<div class="page-header">
<h1><span class="glyphicon glyphicon-tower"></span> Submitting Forms with Angular</h1>
</div>
<!-- SHOW ERROR/SUCCESS MESSAGES -->
<div id="messages" class="well" ng-show="message">{% verbatim %}{{ message}}{% endverbatim %}</div>
<!-- FORM -->
<form ng-submit="processForm()">
<!-- NAME -->
<div id="name-group" class="form-group" ng-class="{ 'has-error' : errorName }">
<label>Name</label>
<input type="text" name="name" class="form-control" placeholder="Bruce Wayne" ng-model="formData.name">
<span class="help-block" ng-show="errorName">{% verbatim %}{{ errorName}}{% endverbatim %}</span>
</div>
<!-- SUPERHERO NAME -->
<div id="superhero-group" class="form-group" ng-class="{ 'has-error' : errorSuperhero }">
<label>Superhero Alias</label>
<input type="text" name="superheroAlias" class="form-control" placeholder="Caped Crusader" ng-model="formData.superheroAlias">
<span class="help-block" ng-show="errorSuperhero">{% verbatim %}{{ errorSuperhero}}{% endverbatim %}</span>
</div>
<!-- SUBMIT BUTTON -->
<button type="submit" class="btn btn-success btn-lg btn-block">
<span class="glyphicon glyphicon-flash"></span> Submit!
</button>
</form>
<!-- SHOW DATA FROM INPUTS AS THEY ARE BEING TYPED -->
<pre>
{% verbatim %}{{ formData}}{% endverbatim %}
</pre>
</div>
</div>
my function where i want my form data from the http request :
/**
* #Route("/testcall")
* #Template()
*/
public function testAction() {
var_dump($_POST);
exit;
}
The only thing i get is this url :
http://localhost/angular/web/app_dev.php/test?name=Tommie&superheroAlias=Crawford
So the values from the form are saved in the URL.
But its not in the $_POST variable..
Its looks like that the function testAction never get accessed
How can i fix this?
You have to access data from the request. If you post JSON object like
{
"foo": "bar"
}
Your controller's action should look something like that:
public function postAction(Request $request)
{
$data = json_decode($request->getContent(), true);
$request->request->replace($data);
//echo below should output 'bar'
echo $request->request->get('foo');
//return response
//....
}
more detailed information about that could be found here

MEAN stack ng-upload-file

I am currently using MEAN.js to create an app and I scaffolded a simple entity called Campaign. I would like each Campaign to have a picture associated. Therefore, I would like to change the CRUD interface to be able to upload a file to the back end.
I injected the ng-file-upload plugin to create the FE with Angular. On the Node.js side, I installed the multer plugin to help me save the file into a folder (e.g. ./uploads). The thing is that I do not quite get the flow and I was hoping for a suggestion.
Please, find below the view:
<section data-ng-controller="CampaignsController">
<div class="page-header">
<h1>New Campaign</h1>
</div>
<div class="col-md-12">
<form class="form-horizontal" data-ng-submit="create()" novalidate>
<fieldset>
<div class="form-group">
<label class="control-label" for="name">Name</label>
<div class="controls">
<input type="text" data-ng-model="name" id="name" class="form-control" placeholder="Name" required>
</div>
</div>
<div class="form-group">
<button ng-file-select ng-model="token">Upload the token</button>
<div ng-file-drop ng-model="token" class="drop-box"
drag-over-class="{accept:'dragover', reject:'dragover-err', delay:100}"
accept="image/*">
Drop image file here
</div>
<div ng-no-file-drop>Image drop is not supported for this browser.</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-default">
</div>
<div data-ng-show="error" class="text-danger">
<strong data-ng-bind="error"></strong>
</div>
</fieldset>
</form>
</div>
</section>
Then, the Angular controller action:
// Create new Campaign
$scope.create = function() {
// Create new Campaign object
var campaign = new Campaigns ({
name: this.name
});
$scope.$watch('token', function() {
$scope.upload = $upload.upload({
url: '/campaigns', //upload.php script, node.js route, or servlet url
method: 'POST', //Post or Put
headers: {'Content-Type': 'multipart/form-data'},
//withCredentials: true,
data: campaign, //from data to send along with the file
file: $scope.token, // or list of files ($files) for html5 only
//fileName: 'photo' // to modify the name of the file(s)
}).success(function (response, status) {
// Redirect after save
campaign.$save(function(response) {
$location.path('campaigns/' + response._id);
// Clear form fields
$scope.name = '';
}, function(errorResponse) {
$scope.error = errorResponse.data.message;
});
}
).error(function (errorResponse) {
$scope.error = errorResponse.data;
//$scope.error = errorResponse.data.message;
});
});
};
Finally, the Node.js controller portion:
var mongoose = require('mongoose'),
errorHandler = require('./errors'),
multer = require('multer'),
Campaign = mongoose.model('Campaign'),
_ = require('lodash');
/**
* Create a Campaign
*/
exports.create = function(req, res) {
var campaign = new Campaign(req.body);
campaign.user = req.user;
multer({
dest: './uploads/'
});
campaign.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(campaign);
}
});
};
Right now, what happens is that - when I try to upload a file - the uploader does not wait for the file to be selected, but it sends the POST request immediately (why?). Moreover, I get a 400 response.
Any suggestion would be really appreciated!
Thanks
Cheers
I partially solved the problem.
This is the new view:
<section data-ng-controller="CampaignsController">
<div class="container">
<div class="page-header">
<h1>New Campaign</h1>
</div>
<div class="col-sm-12 col-md-4 col-md-offset-4">
<form class="form-horizontal" data-ng-submit="create(token)" novalidate>
<fieldset>
<div class="form-group">
<label class="control-label" for="name">Name</label>
<div class="controls">
<input type="text" data-ng-model="name" id="name" class="form-control" placeholder="Name" required>
</div>
</div>
<div class="form-group">
<label class="control-label" for="token">Token</label>
<div class="controls">
<input type="file" id="token" ng-file-select ng-model="token"/>
<p class="help-block">The token file must be a squared .png or .jpg image.</p>
</div>
</div>
<div class="form-group">
<div class="controls">
<input type="submit" class="btn btn-default col-xs-12">
</div>
</div>
<div class="form-group">
<div data-ng-show="error" class="control alert alert-danger alert-dismissible" role="alert">
<span data-ng-bind="error"></span>
</div>
</div>
</fieldset>
</form>
</div>
</div>
</section>
Then, the Angular controller action:
$scope.create = function(token) {
// Create new Campaign object
var campaign = new Campaigns ({
name: this.name
});
$scope.upload = $upload.upload({
url: '/campaigns',
method: 'POST',
headers: {'Content-Type': 'multipart/form-data'},
//withCredentials: true,
data: {
campaign: JSON.stringify(campaign)
},
file: token,
//fileName: 'token' // to modify the name of the file
}).success(function (response, status) {
// Redirect after save
$location.path('campaigns/' + response._id);
// Clear form fields
$scope.name = '';
$scope.token = '';
}
).error(function (errorResponse) {
$scope.error = errorResponse.data;
}
);
};
I am now using node multiparty for the Node.js controller:
exports.create = function(req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
//res.writeHead(200, {'content-type': 'text/plain'});
//res.end(util.inspect({fields: fields, files: files}));
var file = files.file[0];
var contentType = file.headers['content-type'];
var tmpPath = file.path;
var extIndex = tmpPath.lastIndexOf('.');
var extension = (extIndex < 0) ? '' : tmpPath.substr(extIndex);
// uuid is for generating unique filenames.
//var fileName = uuid.v4() + extension;
var fileName = tmpPath;
var destPath = 'uploads/' + fileName;
// Server side file type checker.
if (contentType !== 'image/png' && contentType !== 'image/jpeg') {
fs.unlink(tmpPath);
return res.status(400).send({
message: 'Unsupported file type'
});
}
fs.rename(tmpPath, destPath, function(err) {
if (err) {
return res.status(400).send({
message: 'Image is not saved'
});
}
fs.unlink(tmpPath, function() {
if (err) {
return res.status(400).send({
message: 'Impossible to delete temp file'
});
}
});
console.log(destPath);
//return res.jsonp(destPath);
});
var campaign = new Campaign(JSON.parse(fields.campaign[0]));
campaign.user = req.user;
campaign.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(campaign);
}
});
});
};
I still get an error, but I do not think is related with the file upload. What do you think?
/home/maurizio/Workspace/bdf-v1/node_modules/mongoose/lib/utils.js:413
throw err;
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (http.js:691:11)
at ServerResponse.header (/home/maurizio/Workspace/bdf-v1/node_modules/express/lib/response.js:592:10)
at ServerResponse.send (/home/maurizio/Workspace/bdf-v1/node_modules/express/lib/response.js:144:12)
at ServerResponse.jsonp (/home/maurizio/Workspace/bdf-v1/node_modules/express/lib/response.js:301:15)
at Promise. (/home/maurizio/Workspace/bdf-v1/app/controllers/campaigns.server.controller.js:67:9)
at Promise. (/home/maurizio/Workspace/bdf-v1/node_modules/mongoose/node_modules/mpromise/lib/promise.js:177:8)
Using res.status(400).send... or res.jsonp() will send data back to the client starting with the headers. Your script has these statements falling through, but the subsequent ones cannot be executed since data has already been sent to the client.
The returns you have will end the execution of the method they're invoked in, but the script will just continue to the next method where it will encounter another express send(). In your case, fs.rename will send() the 400, but will encounter another send() when it reaches the campaign.save method where it will throw the error.
Take your calls of return res.status(400).send(), and instead set the message as a string variable, and make the res.status(400).send() call in your final conditional statement if an error is present.
Essentially, make sure a send() or jsonp() invocation can only be made once in your script.

AngularJS $http post request being cancelled

I'm trying to send a post form to a PHP script, and every time, the POST request shows as canceled.
My controller looks like this:
var authenticationControllers = angular.module('authenticationControllers', []);
authenticationControllers.controller('Authentication', ['$scope', '$http', function($scope, $http) {
$scope.WPlogin = function () {
var mydata ={
'action': 'ajaxlogin',
'username': $scope.user.username,
'password': $scope.user.password,
'security-login': pluginParams.nonce,
'_wp_http_referer': '/s/play/'
};
$http({
method: 'POST',
url: $scope.ajaxURL, //This is defined earlier, I'm sure this is valid
data: jQuery.param(mydata),
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function(data, status, headers, config) {
console.log(data.message);
}).error(function(e){alert('error')});
};
}]);
And the form looks like this:
<div class="white-popup mfp-hide" id="login-modal" ng-controller="Authentication">
<form name="loginform" id="loginform" novalidate>
<h1>Login</h1>
<p class="status"></p>
<label for="username">Username</label>
<input id="username" type="text" name="username" ng-model="user.username" ng-required="true">
<label for="password">Password</label>
<input id="password" type="password" name="password" ng-model="user.password" ng-required="true">
<a class="lost" href="<?php echo wp_lostpassword_url(); ?>">Lost your password?</a>
<button class="submit_button" ng-disabled="loginform.$invalid" ng-click="WPlogin()" type="submit" name="submit"> Login</button>
</form>
</div>
Whenever I try to submit the form, the error alert pops up, but no console errors. Then, the page reloads, and I can see the form parameters in the URL (like a get request), and if I then submit my form (without deleting the get parameters), then the request is a success.
Can anyone tell me what I'm doing wrong?
Update
I added $event.preventDefault(); to the form (passing $event from the form), and now it all works as expected, but I don't understand, why do I need that? I thought AngularJS would automatically prevent the form submission.

Resources