2

I'm trying to use AngularJS do upload an images with a PUT or Post request, is this possible, if so how as below does not change the header (still json) and there is no payload.

This is what I have tried:

in my controller:

       $scope.uploadFile = function (elm) {

            $scope.files = elm.files
            $scope.$apply();

            var fd = new FormData()
            fd.append('file', $scope.files[0])


            $scope.profile

                .customPOST(fd, "", ["Content-Type", undefined])
             .withHttpConfig({
                    transformRequest: angular.identity
                });

            event.preventDefault();


        };

html:

<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>

This code actually gets the file name and add its to the database, but no file actually gets uploaded during the put request.

Prometheus
  • 32,405
  • 54
  • 166
  • 302
  • 1
    you pass this.files to uploadFile(), but uploadFile() wants an element for _elm_, not a files collection. that might be your only issue from what i see posted in your question... – dandavis Jul 25 '14 at 17:43

5 Answers5

1

This is the directive I like to use for my file uploads:
https://github.com/danialfarid/angular-file-upload

You can install it with bower: bower install ng-file-upload --save
It comes with many features like progress bar handling and easy drag and drop.

You can find examples on how to use it on the github link, but here's how I use it in Coffeescript with AWS S3 direct upload. Just note that doing uploads to s3 takes a whole lot more of code. That also includes generating a token from the server. Thats the /api/media/upload_token you see there.

$scope.processUpload = (metadata) ->
  $scope.fileUploads.push metadata
  $http.put('/api/media/' + metadata._id, metadata)
  .success (res) ->
    // do your stuff here when the upload is finished
    // $scope.reloadMedia();
  console.log metadata


$scope.onFileSelect = ($files) ->
  # merge new uploads, ignore old uploads
  $scope.files = $files;
  $scope.upload = [];
  # create a new closure for each file upload
  for file, i in $files
    file.progress = parseInt 0
    do (file, i) ->
      anticache = Math.random().toString(36).substring(3,9)
      $http.get('/api/media/upload_token?mimeType=' + file.type + '&rnd=' + anticache,
      {filename: file.name})
      .success (response) ->
        s3Params = response
        uploadData =
          url: 'https://<mybucketname>.s3.amazonaws.com/'
          method: 'POST'
          data:
            key: s3Params.filename + '$$' + file.name
            acl: 'public-read'
            'Content-Type': file.type
            AWSAccessKeyId: s3Params.AWSAccessKeyId
            success_action_status: 201
            Policy: s3Params.s3Policy
            Signature: s3Params.s3Signature
          file: file

        # start the upload
        $scope.upload[i] = $upload.upload(uploadData)
        .progress (evt) ->
          file.progress = parseInt(100.0 * evt.loaded / evt.total)
        .success (res, status, headers, config) ->
          file.progress = parseInt 100
          if status is 201
            xmlDoc = (new DOMParser).parseFromString(res, 'application/xml')
            getXmlValue = (k) -> xmlDoc.getElementsByTagName(k)[0].firstChild.nodeValue
            metadata =
              _id: response.filename
              location: getXmlValue 'Location'
              bucket: getXmlValue 'Bucket'
              key: getXmlValue 'Key'
              etag: getXmlValue 'ETag'
              filename: file.name
            $scope.processUpload(metadata)
          else
            throw new Error("File Upload Failed! Server status is not 201");
            alert 'Upload Failed, please try again.'

This is my Jade view, just note that the classes I have are from Bootstrap

.form-group.well(ng-file-drop='onFileSelect($files)')
  span.btn.btn-primary.btn-file.btn-block
    | Upload Media
    input(type='file', ng-file-select='onFileSelect($files)', multiple)
  p.help-block You can also drag and drop files here.
  .row(ng-repeat='file in files')
    .col-md-8
      .progress
        .progress-bar(role='progressbar', style='width:{{file.progress}}%;')
            | {{file.name}} : {{file.progress}}
    .col-md-4
      button.btn.btn-warning(type='button', ng-click='abort($index)', ng-show='file.progress != 100') Abort
  div(ng-file-drop-available='dropSupported=true', ng-show='!dropSupported') HTML5 Drop File is not supported!
Josue Alexander Ibarra
  • 8,269
  • 3
  • 30
  • 37
1

In order to upload the image using AngularJS you can put the input tag in a form and submit the form.

So in the HTML your code should look like this:

<form id='uploadForm' enctype='multipart/form-data' method = 'post' name ='settingForm'>
    <input id='inputFile' type='file' name = 'uploadFile' />
    <button id='saveSetting' ng-click='onSubmit()' name='save'>Save</button>
</form>

Here you can notice the enctype set to multipart and method as post.

In the controller:

$scope.onSubmit = function() {
    var options = {
        target: '',
        url: '<your server url>',
        success: function() {
            //what ever you require on success
        }
    };
    $('#uploadForm').ajaxSubmit(options);
}

In the server you can get the file in the request parameter (in NodeJS it will look like this):

req.files.uploadFile;

where 'uploadFile' is the name that you specify in the HTML markup

Hope that helps!!

V31
  • 7,626
  • 3
  • 26
  • 44
1

You can use angular method like this, HTML Part,

<input type="file" ng-file-select="onFileSelect($files)" />

In your controller write this,

    $scope.onFileSelect = function ($files) {
        var file = $files[0];
        // upload file to server
        $scope.upload = $upload.upload({
            url: 'http://www.yourdomain.com/yourpath',
            file: file
        }).success(function(data, status, headers, config) {
            // file is uploaded successfully
        }).error(function (data) {
            // file upload failed
        });
    };
JSunny
  • 477
  • 2
  • 7
0

You can try this way:

HTML Part:

<input type="file" name="file" onchange="angular.element(this).scope().uploadFile(this.files)"/>

Angular part:

$scope.uploadFile = function(files) {
    var fd = new FormData();

    fd.append("file", files[0]);

    $http.post(uploadUrl, fd, {
        withCredentials: true,
        headers: {'Content-Type': undefined },
        transformRequest: angular.identity
    }).success( /*COOOOOOLLL*/ ).error( /*Use the force Luke!*/ );

};

OR if you want to add some progress bar you can try this with multiple file upload:

<div ng-controller="FileUploadCtrl">
  <input type="file" ng-file-select="onFileSelect($files)" multiple>
</div>

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

var FileUploadCtrl = [ '$scope', '$upload', function($scope, $upload) {
  $scope.onFileSelect = function($files) {
    for (var i = 0; i < $files.length; i++) {
      var file = $files[i];
      $scope.upload = $upload.upload({
        url: 'server/upload/url', 
        data: {uploadObject: $scope.myModelObj},
        file: file,
      }).progress(function(evt) {
        console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
      }).success(function(data, status, headers, config) {
        console.log(data);
      });
    }
  };
}];
Chrissx
  • 357
  • 1
  • 7
0

Following worked for me as I was looking for a solution to post file to Amazon S3. Worked with both PUT AND POST as method

$http({
    method: 'PUT',
    url: http://www.yourdomain.com/yourpath',
    data: file,
    headers: {
        'Content-Type': undefined
    },
    transformRequest : function (data, headersGetter) {
        return data;
    }
});