0

I can't figure out how to post through angular $http. Why? I'd like multer to parse and store my file and angular to get a copy when it is done. Better yet, I'd love to just let angular get a copy, then pass it down to the server.

I am able to upload a file using the snippets below:

// view (jade)
.container
  form(action="/upload", method="POST", enctype="multipart/form-data")
    input(type="file", name="f")
    input(type="submit", value="Upload")

// post route (express)
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('f'), function(req, res) {
  console.log(req.file);
});

Running this with any sample file, returns the json I want to the console and the image is stored successfully in the proper directory. However:

// view (jade)
form(enctype="multipart/form-data" ng-submit="uploadFile(file)")
input(type="file", name="f", ng-model="file")
input(type="submit", value="Upload")

// ctrl (angular)
$scope.uploadFile = function(file) {
  console.log(file);
  $http.post('/upload', file);
};

// post route (express)
var multer = require('multer');
var upload = multer({ dest: 'uploads/' });
app.post('/upload', upload.single('f'), function(req, res) {
  console.log(req.file);
});

This returns undefined on both console inputs, even though I didn't change the file, I only changed how it was sent.

This leads me two believe one of two things:

The data submitted is not what I think it is. If this is the case, what is it? Nothing prints on the log.

OR

The data submitted is altered in some way by angular. If this is the case, how? Again nothing prints on the log.

1 Answer 1

2

In the first case, by sending the data directly through the form to the server, you let html do the transformation magic under the hood.

In the second case, by posting through AngularJs via $http, you need to tell the middleware that is $http, the required transformation it needs to do to the request to match the attributes you passed to the form.

For having struggled with this myself for a while, here is an adaptation of the code I used (for $resource). But I think it should work for its underlying $http.

So in your controller:

$scope.uploadFile = function(file) {
   console.log(file);
   var fd = new FormData();
    fd.append('file', file);
    $http.post(uploadUrl, fd, {
        transformRequest: angular.identity,
        headers: {
            'Content-Type': undefined},
            enctype: 'multipart/form-data'
        }
     })
    .success(function(){
    })
    .error(function(){
    });   
 };

For that to work, you need to bind the file input field to the model. Of course, Angularjs chooses not to do that natively for some reasons.

In the jade view:

form(enctype="multipart/form-data" ng-submit....)
  input(type="file", name="f", ng-model="file" on change='angular.element(this).scope().readFile(this)')
  input(type="submit", value="Upload")

onchange is JavaScript and not AngularJs and it triggers the scope.readfile() function that we need to define:

In the controller:

$scope.readfile = function(elem) {
    var file= elem.files[0];
    var reader = new FileReader();
   reader.onload = function() {
       $scope.$apply(function(){
           $scope.file = file;
           $scope.imageUrl = reader.result // to display         image via ng-Src
       })
   }
   reader.readAsDataURL(file);
}

I think that should bring back some html magic back into angular when working with forms.

I suggest you look into JavaScript's onchange, FormData, and FileReader for code snippets like these and better documentation.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.