1
votes

I've researched for the past few days and I cannot figure this one out.

Goal: User uploads a text file using the angular-file-upload form, and multer saves the file to a temporary folder. The data then POSTs and the user can see the file metadata and contents either on the same page, or a redirected page.

Problem: In my POST route, I can console.log(req.file) and it shows file the metadata. The file saves to the temporary folder.

I've tried to res.send(req.file), res.json(req.file), data binding the metadata in the controller scope, res.locals, middleware functions, and many other things that I can't even remember. The json object never comes through to the view.

Here's a snippet of what I'm working with.

routes.js

var express = require('express');
var app = express();
var router = express.Router();

router.get('/test', function(req, res, next){
  res.render('test', {title: 'Test'});
});

router.post('/test', function(req, res, next){
  console.log(req.file);
  res.json(req.file);
});

module.exports = router;

app.js

var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var logger = require('morgan');
var sys = require('sys');
var multer = require('multer');
var app = express();
 // Local Files
var routes = require('./routes/index');
var users = require('./routes/users');
var favicon = require('serve-favicon');
// console.log(__dirname + '/public/scripts/test.py');

// Create multer object for file uploads
var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './tmp/')
  }
  // filename: function (req, file, cb) {
  //   cb(null, file.originalname + "%" + Date.now())
  // }
});

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// app.use(express.bodyParser( { keepExtensions: true, uploadDir: __dirname + '/photos' } ));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'bower_components')));
app.use(multer({ storage: storage }).single('file'));
app.use('/', routes);
app.use('/users', users);

controller.js

var t = angular.module('upload', ['ngFileUpload']);

t.controller('ctrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {
    $scope.f = '';
    $scope.uploadFiles = function(file) {
        $scope.f = file;
        console.log(file);
        if (file && !file.$error) {
            file.upload = Upload.upload({
                url: '/test',
                file: file
            });
            file.upload.then(function (response) {
                $timeout(function () {
                    file.result = response.data;
                });
            }, function (response) {
                if (response.status > 0)
                    $scope.errorMsg = response.status + ': ' + response.data;
            });
            file.upload.progress(function (evt) {
                file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
            });
        }
    }
}]);

req.file

{ fieldname: 'file',
  originalname: 'lorem.rtf',
  encoding: '7bit',
  mimetype: 'text/rtf',
  destination: './tmp/',
  filename: '0b9d25cc663a05628059bd56a0aef4bc',
  path: 'tmp/0b9d25cc663a05628059bd56a0aef4bc',
  size: 815 }
2

2 Answers

0
votes

You could always try JSON.stringify to serialize it. See if that renders req.file properly. You can still set the header to text/json manually.

0
votes

I don't know exactly why this is working versus what I was doing. (I feel like I tried many variations of the same thing) I stuck closely to the angular-file-upload docs and am able to set the response object to a scope variable.

The only noticeable difference is that I didn't set the Upload function to a variable and call actions on the variable. Instead, all the events are strung as one.

routes.js and app.js stayed the same.

new controller.js function

$scope.upload = function (file) {
  Upload.upload({
      url: '/test',
      data: {file: file}
  }).then(function (resp) {
      console.log('Success ' + resp.config.data.file.name + ' uploaded. Response: ' + resp.data);
      console.log(resp.data);
      $scope.obj = resp.data;
  }, function (resp) {
      console.log('Error status: ' + resp.status);
  }, function (evt) {
      var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
      console.log('progress: ' + progressPercentage + '% ' + evt.config.data.file.name);
  });
};