How to clear a file input from Angular JS
Asked Answered
P

6

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.

Pussyfoot answered 26/2, 2013 at 1:30 Comment(0)
T
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.

Tremulous answered 26/2, 2013 at 1:56 Comment(3)
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)Pussyfoot
Workaround is to change "selector.val(file);" to "if (file==null) selector.val(file);"Pussyfoot
This kind of answer is quite frustrating without any explanation.Collarbone
F
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.

Farmhouse answered 18/6, 2013 at 20:17 Comment(4)
You really shouldn't be doing DOM manipulation in the controller. This is what directives are for.Gush
This doesn't work for me. If I try and select the same file again, the onchange isn't fired. Any ideas?Maritsa
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).Carmelinacarmelita
If you don't want to use jQuery, you can use document.getElementById('inputId').value = null;Overmantel
T
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.

Tremulous answered 26/2, 2013 at 1:56 Comment(3)
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)Pussyfoot
Workaround is to change "selector.val(file);" to "if (file==null) selector.val(file);"Pussyfoot
This kind of answer is quite frustrating without any explanation.Collarbone
T
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
    };
}]);
Tazza answered 25/11, 2014 at 22:20 Comment(2)
this should be the best answer. short and elegant. Wonder why use a selector in directive when we have linker.Natator
how it could be rewritten for a component instead of directive?Kemppe
P
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('');
        }
    });
};
Perforated answered 28/1, 2015 at 6:2 Comment(0)
K
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.

Kieger answered 20/11, 2017 at 5:37 Comment(0)
H
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/>
Hysterogenic answered 11/4, 2018 at 19:35 Comment(1)
this is perfect.Shelli

© 2022 - 2024 — McMap. All rights reserved.