Cannot access req.files from req object using multer

Viewed 1486

I am trying to upload a file to the server using NodeJs script. I am trying the following things.

HTML

<md-tab label="Upload log">
    <md-content class="md-padding" id="popupContainer" ng-cloak>
        <h4>Upload a zip file</h4>
            <form ng-submit="$event.preventDefault()">
                <md-input-container class="md-block" flex>
                    <label>Source</label>
                    <md-select name="source" ng-model="log.source" ng-click="getSources()">
                        <md-option ng-repeat="source in sourceInfo" value="{{source.sourceCode}}">{{source.sourceName}}</md-option>
                    </md-select>
                </md-input-container>
                <br>
                <md-input-container class="md-block">
                    <label>Select Batch</label>
                    <input required type="number" step="any" name="rate" ng-model="log.batch" min="1" max="100"/>
                </md-input-container>
                <md-input-container class="md-block">
                    <label>Enter your comments about the log files</label>
                    <textarea ng-readonly="false" ng-model="log.comment" md-maxlength="100" rows="3" md-select-on-focus></textarea>
                </md-input-container>
                <div ng-if="status" id="status">
                    <b layout="row" layout-align="center center" class="md-padding">{{status}}</b>
                </div>
                <input type="file" file-model="log.file" name="inputFile"/>
                <button ng-click="uploadFiles()">Upload</button>
                {{log}}
                <p> </p>
            </form>
    </md-content>
</md-tab>

Directive

var logApp = angular.module('logAnalysisApp', ['ngMaterial', 'lfNgMdFileInput', 'ngRoute', 'ngMessages']);
logApp.config(['$routeProvider', '$compileProvider', '$mdThemingProvider', function ($routeProvider, $compileProvider, $mdThemingProvider) {
            $compileProvider.debugInfoEnabled(false);
            $routeProvider
            .when('/login', {
                templateUrl: 'views/login.html',
                controller: 'loginControl'
            })
            .when('/register', {
                templateUrl: 'views/register.html',
                controller: 'registerControl'
            })
            .when('/home', {
                templateUrl: 'views/filemenu.html',
                controller: 'fileUploadCtrl'
            })
            .when('/admin', {
                templateUrl: 'views/adminpanel.html',
                controller: 'adminCtrl'
            })
            .when('/totalreport', {
                templateUrl: 'views/total.html',
                controller: 'totalCtrl'
            })
            .otherwise({
                redirectTo: '/login'
            });
        }
    ])

logApp.constant('config', {
    apiUrl: 'http://localhost:8080',
    serverUrl: 'http://localhost:3000'
})

logApp.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]);
                        });
                    });
                }
            };
        }
    ]);

Controller

logApp.controller('fileUploadCtrl', function ($rootScope, $scope, $timeout, $location, $http, config) {
    $scope.log = {};
    $scope.uploadFiles = function () {

        console.log($scope.log);

        var uploadUrl = "http://localhost:3000/testRef";

        var fd = new FormData();
        for (var key in $scope.log)
            fd.append(key, $scope.log[key]);
        for (var pair of fd.entries()) {
            console.log(pair[0] + ', ' + pair[1]);
        }
        $http.post(uploadUrl, fd, {
            transformRequest: angular.indentity,
            headers: {
                'Content-Type': undefined
            }
        })
        .success(function () {
            console.log("success!!");
        })
        .error(function () {
            console.log("error!!");
        });
    };
});

ServerSide Coding

var express = require('express')
var app = express()
var multer  = require('multer');
var upload = multer({ dest: './uploads' });
app.post('/testRef', upload.any("inputFile"), function(request, response) {

    console.log(request.files)
    console.log(request.body)
    response.send("Done")
});

When I trying to see the request.files in the console, it is showing blank array, and request.body as a blank object. But in the client log when I am printing $scope.log it is showing the appropriate content and when iterating through the FormData variable I am seeing the desired data which I am sending. Also, in the html when I am printing the {{log}} the file data is not getting populated.

Any type of help is welcome.

Thank you.

3 Answers

You have to add header 'Content-type': 'multipart/form-data'.

Use req.files[0] since you have upload.any('inputFile') in your server code.

I too have faced the same problem but Thats how our browser works, it's impossible to fix in multer.

A fix for this is to use javascript on the client side to catch the submit event and instead submit using FormData and ordering the fields so that the input data is before any files.

This trick worked for me

Related