Uploading file with AngularJS fails
Question: Below are the snippets of my code regarding file upload.

Here is my HTML code where I will choose and upload the file:

    
    
    <form ng-click="addImportFile()" enctype="multipart/form-data">
        <label for="importfile">Import Time Events File:</label><br><br>
        <label for="select_import_file">SELECT FILE:</label><br>
        <input id="import_file" type="file" class="file btn btn-default" ng-disabled="CutOffListTemp.id== Null" data-show-preview="false">
        <input class="btn btn-primary" type="submit" name="submit" value="Upload" ng-disabled="CutOffListTemp.id== Null"/><br/><br/>
    </form>
    

This is my controller that will link both html and my python file:

    
    
    angular.module('hrisWebappApp').controller('ImportPayrollCtrl', function ($scope, $state, $stateParams, $http, ngTableParams, $modal, $filter) {
      $scope.addImportFile = function() {
        $http.post('http://127.0.0.1:5000/api/v1.0/upload_file/' + $scope.CutOffListTemp.id, {})
        .success(function(data, status, headers, config) {
          console.log(data);
    
          if (data.success) {
            console.log('import success!');
          } else {
            console.log('importing of file failed' );
          }
        })
        .error(function(data, status, headers, config) {});
    };
    

This is my python file:

    
    
    @api.route('/upload_file/<int:id>', methods=['GET','POST'])
    @cross_origin(headers=['Content-Type'])
    def upload_file(id):
        print "hello"
        try:
            os.stat('UPLOAD_FOLDER')
        except:
            os.mkdir('UPLOAD_FOLDER')
        file = request.files['file']
        print 'filename: ' + file.filename
    
        if file and allowed_file(file.filename):
            print 'allowing file'
            filename = secure_filename(file.filename)
            path=(os.path.join(current_app.config['UPLOAD_FOLDER'], filename))
            file.save(path) #The end of the line which save the file you uploaded.
            return redirect(url_for('uploaded_file',
                                                filename=filename))
        return '''
            <!doctype html>
            <title>Upload new File</title>
            <h1>Upload new File</h1>
            <p>opsss it seems you uploaded an invalid filename please use .csv only</p>
    
            <form action="" method=post enctype=multipart/form-data>
              <p><input type=file name=file>
                 <input type=submit value=Upload>
            </form>
            '''
    

And the result in the console gave me this even if I select the correct format
of file:

    
    
    <!doctype html>
    <title>Upload new File</title>
    <h1>Upload new File</h1>
    <p>opsss it seems you uploaded an invalid filename please use .csv only</p>
    <form action="" method=post enctype=multipart/form-data>
    <p><input type=file name=file>
    <input type=submit value=Upload>
    </form>
    

This is not returning to my HTML and I cannot upload the file.


Answer: The first thing is about the post request. Without ng-click="addImportFile()",
the browser will usually take care of serializing form data and sending it to
the server. So if you try:

    
    
    <form method="put" enctype="multipart/form-data" action="http://127.0.0.1:5000/api/v1.0/upload_file">
        <label for="importfile">Import Time Events File:</label><br><br>
        <label for="select_import_file">SELECT FILE:</label><br>
        <input id="import_file" type="file" name="file" class="file btn btn-default" ng-disabled="CutOffListTemp.id== Null" data-show-preview="false">
        <input class="btn btn-primary" type="submit" name="submit" value="Upload" ng-disabled="CutOffListTemp.id== Null"/><br/><br/>
    </form>
    

and then in python, make your request url independent of
scope.CutOffListTemp.id: @api.route('/upload_file', methods=['GET','POST'])

It probably will work.

Alternatively, if you want to use your custom function to send post request,
the browser will not take care of the serialization stuff any more, you will
need to do it yourself.

In angular, the API for $http.post is: $http.post('/someUrl',
data).success(successCallback); If we use "{}" for the data parameter, which
means empty, the server will not find the data named "file" (file =
request.files['file']). Thus you will see Bad Request

To fix it, we need to use formData to make file upload which requires your
browser supports HTML5:

    
    
    $scope.addImportFile = function() {
        var f = document.getElementById('file').files[0]
        var fd = new FormData();
        fd.append("file", f);
    
        $http.post('http://127.0.0.1:5000/api/v1.0/upload_file/'+$scope.CutOffListTemp.id,
                   fd,
                   headers: {'Content-Type': undefined})
        .success......
    

Other than using the native javascript code above, there are plenty great
angular file upload libraries which can make file upload much easier for
angular, you may probably want to have a look at one of them (reference: [File
Upload using angularjs](http://stackoverflow.com/questions/18571001/file-
upload-using-angularjs)):

  * <https://github.com/nervgh/angular-file-upload>
  * <https://github.com/leon/angular-upload>
  * ......

