29

In AngularJS, I'm using the approach described here to handle input type=file.

Markup:

<div ng-controller="MyCtrl">
    <input type="file" onchange="angular.element(this).scope().setFile(this)">
    {{theFile.name}}
</div>

Controller:

var myApp = angular.module('myApp', []);

myApp.controller('MyCtrl', function($scope) {
    $scope.setFile = function(element) {
        $scope.$apply(function($scope) {
            $scope.theFile = element.files[0];
        });
    };
});

As mentioned it's a bit of a hack, but it mostly works for my purposes. What I need however is a way to clear the file input after the upload has finished - ie: from the controller.

I could completely hack it and use jQuery or something to find the input element and clear it, but was hoping for something a little more elegant.

6 Answers 6

37

Upon a successful upload, I clear up the input type file elements explicitly from my controller, like so:

  angular.forEach(
    angular.element("input[type='file']"),
    function(inputElem) {
      angular.element(inputElem).val(null);
    });

The input[type='file'] selector requires jQuery, but everything else is plain Angular.

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

4 Comments

You really shouldn't be doing DOM manipulation in the controller. This is what directives are for.
This doesn't work for me. If I try and select the same file again, the onchange isn't fired. Any ideas?
This works fine for me. For some reasons, I couldn't make the accepted directive work (maybe my fault since I have more stuff in input tag).
If you don't want to use jQuery, you can use document.getElementById('inputId').value = null;
11

I would definitely use directive for this kind of task.

http://plnkr.co/edit/xLM9VX

app.directive('fileSelect', function() {
  var template = '<input type="file" name="files"/>';
  return function( scope, elem, attrs ) {
    var selector = $( template );
    elem.append(selector);
    selector.bind('change', function( event ) {
      scope.$apply(function() {
        scope[ attrs.fileSelect ] = event.originalEvent.target.files;
      });
    });
    scope.$watch(attrs.fileSelect, function(file) {
      selector.val(file);
    });
  };
});

note: it is using jquery for element creation.

3 Comments

Nice. The only issue I've noticed is that after selecting a file, there's an error in the console log about an invalid HTML element in the scope.$watch function. (Running in Chrome)
Workaround is to change "selector.val(file);" to "if (file==null) selector.val(file);"
This kind of answer is quite frustrating without any explanation.
10

my solution without using $scope.

app.directive('fileChange',['UploadService',function (UploadService) {
    var linker = function (element, attrs) {
        element.bind('change', function (event) {
            var files = event.target.files;
            UploadService.upload({'name':attrs['name'],'file':files[0]});
            element.val(null);  // clear input
        });
    };
    return {
        restrict: 'A',
        link: linker
    };
}]);

2 Comments

this should be the best answer. short and elegant. Wonder why use a selector in directive when we have linker.
how it could be rewritten for a component instead of directive?
6

It might help you!!

HTML code sample

 <input type="file" id="fileMobile" file-model="myFile">
 <button type="button" class="btn btn-danger" id="i-agree" ng-click="uploadFile()"> Upload </button>

AngularJs code sample

$scope.uploadFile = function () {
    var file = $scope.myFile;
    mobileService.uploadBulkFile(file).then(function (resp) {
        if (resp !== undefined) {
            $('#fileMobile').val('');
        }
    });
};

Comments

3

You can use ID to reset file field.

<div class="col-md-8">  
    <label for="files">Select File</label>
    <input type="file" id="file_upload" class="form-control">
</div>

After uploading clear it.

var fileElement = angular.element('#file_upload');
angular.element(fileElement).val(null);

Above example working good for me. Will work for you too.

Comments

2

In my case, I broadcast events when a file upload succeeds. So my directive watches for the broadcast, and clears the selection.

app.directive("fileInput", function( APP_EVENTS ){
    return{
        require: "ngModel",
        link: function postLink( scope, elem, attrs, ngModel ){

            elem.on("change", function( e ){
                var files=elem[0].files;
                ngModel.$setViewValue( files );
            });

            scope.$on( APP_EVENTS.FILE_UPLOAD_SUCCESS, function( event ){
                elem.val( null );
            });
        }
    }
});

It's used like so:

<input type="file" name="myFieldName" ng-model="myModel" file-input/>

1 Comment

this is perfect.

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.