Gandalf the White Gandalf the White - 6 months ago 69
AngularJS Question

Angular JS Express JS Node JS file upload issue

Please help me
I'm new to this and for file upload I referred to this - http://goodheads.io/2015/06/22/handling-file-uploads-using-angularjs-node-and-express/

my implementation is given below. At place I have deleted things to make sure the post size is readable enough. The main problem is only file upload section other than that everything is working like a charm. Please help.

Here is the index.html section.

<!doctype html>
<html ng-app ="myApp">
<head>
<meta charset="utf-8">
<title>Untitled Document</title>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css">
</head>
<body>
<div class="container" ng-controller="AppCtrl">
<table width="500" border="2" cellspacing="2" cellpadding="2">
<form>
<tbody>
<tr>
<td><input type="file" ng-file-select="fileSelected($files)" accept="'image/*'"></td>
<td><input type="submit" ng-click="uploadFile()" ></td>
</tr>

</tbody>
</form>
</table>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.12/angular.min.js"></script>
<script src="controller.js"></script>
<script type="text/javascript" src="../bower_components/ng-file-upload-shim/ng-file-upload-shim.js"></script>
<script type="text/javascript" src="../bower_components/ng-file-upload-shim/ng-file-upload.js"></script>
</body>
</html>
<form></form>


Here is the controller that is guiding the file.

var myApp = angular.module('myApp', ['angularFileUpload']);

myApp.controller('AppCtrl', ['$scope', '$http', 'upload', function($scope, $http, $upload) {
console.log("Hello World from controller");

$scope.addData = function()
{
console.log($scope.user);
console.log("whore");
$http.post('../addData', $scope.user).success(function(response) {
console.log(response);
});

$scope.fileSelected = function(files)

{
if (files && files.length) {
$scope.file = files[0];
}

$upload.upload({
url: '../upload',
file: $scope.file
})
.success(function(data) {
console.log(data, 'uploaded');
});


};
};

}]);


Please ignore the first function it is for something else but my problem is something else.

Now here is the server code where I have used multer to do the trick.

var express = require('express');
var app = express();
var mongoose = require('mongoose');
var multer = require('multer');
var validator = require('node-mongoose-validator');
var bodyParser = require('body-parser')
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }))
app.use(multer({
dest: './uploads/'
}));

app.use(express.static(__dirname + '/public'));
app.use(bodyParser.json());


The server file is very big therefore I'm not adding all the routes and all section here. When I'm deleting the section which has the upload command it runs without error but when I am adding it, error is shown.

C:\nodefiles\new\node_modules\express\lib\application.js:209
throw new TypeError('app.use() requires middleware functions');
^
TypeError: app.use() requires middleware functions
at EventEmitter.use (C:\nodefiles\new\node_modules\express\lib\application.js:209:11)
at Object.<anonymous> (C:\nodefiles\new\server.js:9:5)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Function.Module.runMain (module.js:501:10)
at startup (node.js:129:16)
at node.js:814:3

Answer

multer({dest: './uploads/'}) does not itself return a middleware function. You have to use one of the functions of multer class to get a middleware function.

So you would end up using it like multer({...}).single(). The different functions are described here - https://github.com/expressjs/multer#singlefieldname.

Multer doc has good examples of the right usage: https://github.com/expressjs/multer#usage

To save a click, here is a full working example:

var multer = require('multer');
var upload = multer({
    dest: __dirname + '/../../public/uploads/',
});

app.post('/api/data', upload.single('filenameInTheForm'), function (req, res, next) {
    return res.ok();
});

Important to note that filenameInTheForm must match the field name in the multipart/form-data request.

Also, there is a slight difference in using app.use(..) and the way described above. app.use() will cause the middleware executed for every endpoint, lucky enough, if the content type is not multipart/form-data the middleware does nothing. To avoid slight overhead from the fact that it still performs the content type check, it is nicer to use it as in the example above.

Comments