AngularJs:如何检查文件输入字段的变化?

man*_*ish 274 angularjs

我是棱角分明的新人.每当在此字段上发生"更改"时,我都会尝试从HTML"文件"字段中读取上传的文件路径.如果我使用'onChange'它可以工作,但是当我使用'ng-change'的角度方式时,它不起作用.

<script>
   var DemoModule = angular.module("Demo",[]);
   DemoModule .controller("form-cntlr",function($scope){
   $scope.selectFile = function()
   {
        $("#file").click();
   }
   $scope.fileNameChaged = function()
   {
        alert("select file");
   }
});
</script>

<div ng-controller="form-cntlr">
    <form>
         <button ng-click="selectFile()">Upload Your File</button>
         <input type="file" style="display:none" 
                          id="file" name='file' ng-Change="fileNameChaged()"/>
    </form>  
</div>
Run Code Online (Sandbox Code Playgroud)

fileNameChaged()永远不会调用.Firebug也没有显示任何错误.

sqr*_*ren 469

我做了一个小指令来监听文件输入的变化.

查看JSFiddle

view.html:

<input type="file" custom-on-change="uploadFile">
Run Code Online (Sandbox Code Playgroud)

controller.js:

app.controller('myCtrl', function($scope){
    $scope.uploadFile = function(event){
        var files = event.target.files;
    };
});     
Run Code Online (Sandbox Code Playgroud)

directive.js:

app.directive('customOnChange', function() {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var onChangeHandler = scope.$eval(attrs.customOnChange);
      element.on('change', onChangeHandler);
      element.on('$destroy', function() {
        element.off();
      });

    }
  };
});
Run Code Online (Sandbox Code Playgroud)

  • 这有一个非常不幸的"错误" - 控制器在customOnChange中没有被绑定为"this",而是文件输入!它把我扔了很长时间,我找不到真正的bug.我还不确定如何通过正确设置"this"来实际调用它. (12认同)
  • @JDawg您需要重置输入值http://jsfiddle.net/sqren/7t0h5aax/ (5认同)
  • 从今天开始,无论是在Chrome还是Firefox上,这个小提琴都不起作用. (4认同)
  • 如果每次选择一个不同的文件,这将很好地工作。选择同一文件时是否可以收听? (2认同)
  • 正如@KarelBílek所述,这个答案是有缺陷的.我无法解决它并决定使用angular-file-upload. (2认同)
  • IE 甚至 Chrome 都不喜欢您重新上传同名文件。以下是解决方法:http://stackoverflow.com/questions/12030686/html-input-file-selection-event-not-firing-upon-selecting-the-same-file#answer-12102992 (2认同)
  • 为了让它工作,我必须实现 @PatrickMichalina 建议的更改,并且因为该函数在指令的隔离范围内执行,所以还在函数末尾添加一个 `$scope.$apply()` 调用。它适用于同一文件的多个选择,以及 @sqren 在其 2015 年 9 月 12 日评论中链接的小提琴的更改。 (2认同)
  • 这绝对是怎么做的,就像一个魅力。此外,为什么还要在生产中使用调试功能? (2认同)

JQu*_*uru 236

没有对文件上载控件的绑定支持

https://github.com/angular/angular.js/issues/1375

<div ng-controller="form-cntlr">
        <form>
             <button ng-click="selectFile()">Upload Your File</button>
             <input type="file" style="display:none" 
                id="file" name='file' onchange="angular.element(this).scope().fileNameChanged(this)" />
        </form>  
    </div>
Run Code Online (Sandbox Code Playgroud)

代替

 <input type="file" style="display:none" 
    id="file" name='file' ng-Change="fileNameChanged()" />
Run Code Online (Sandbox Code Playgroud)

你能试一下吗

<input type="file" style="display:none" 
    id="file" name='file' onchange="angular.element(this).scope().fileNameChanged()" />
Run Code Online (Sandbox Code Playgroud)

注意:这要求角度应用程序始终处于调试模式.如果禁用调试模式,这将无法在生产代码中使用.

并在您的功能更改而不是

$scope.fileNameChanged = function() {
   alert("select file");
}
Run Code Online (Sandbox Code Playgroud)

你能试一下吗

$scope.fileNameChanged = function() {
  console.log("select file");
}
Run Code Online (Sandbox Code Playgroud)

下面是文件上传的一个工作示例,拖放文件上传可能会有所帮助 http://jsfiddle.net/danielzen/utp7j/

角度文件上载信息

ASP.Net中AngularJS文件上载的URL

http://cgeers.com/2013/05/03/angularjs-file-upload/

随着NodeJS的进展,AngularJs本机多文件上传

http://jasonturim.wordpress.com/2013/09/12/angularjs-native-multi-file-upload-with-progress/

ngUpload - 用于使用iframe上传文件的AngularJS服务

http://ngmodules.org/modules/ngUpload

  • 这是一个可怕的答案.调用angular.element(blah).scope()是一个调试功能,您只应该用于调试.Angular不使用.scope功能.它只是帮助开发人员调试.在构建应用程序并部署到生产环境时,您应该关闭调试信息.这加速了你的全部很多!因此,编写依赖于element.scope()调用的代码是个坏主意.不要这样做.有关创建自定义指令的答案是正确的方法.@JQueryGuru你应该更新你的答案.因为它的票数最多,人们会遵循这个糟糕的建议. (108认同)
  • 此方法绕过默认的AngularJS处理,因此不会调用$ scope.$ digest()(不更新绑定).之后调用'angular.element(this).scope().$ digest()'或调用使用$ apply的范围方法. (13认同)
  • 当禁用调试信息时,此解决方案将破坏应用程序.禁用该产品是官方建议https://docs.angularjs.org/guide/production.另请参阅http://blog.thoughtram.io/angularjs/2014/12/22/exploring-angular-1.3-disabling-debug-info.html (7认同)
  • BAD SOLUTION ...... ...阅读关于'关闭调试'的其他评论...... ......并查看`sqren`的解决方案...... ...... @ 0MV1 (4认同)
  • onchange ="angular.element(this).scope().fileNameChaged(this)"$ scope.fileNameChaged = function(element){console.log('files:',element.files); 你能改变两个地方并检查吗?取决于浏览器你将获得文件的完整路径我有更新下面的小提琴是url上传文件和检查控制台http://jsfiddle.net/utp7j/260/ (2认同)
  • for(var i = 0; i <element.files.length; i ++){console.log(element.files [i])}当你在mozilla attribut上循环文件对象时,如果你发现我的答案有用的话是"mozFullPath"你也可以upvote (2认同)

Stu*_*xon 40

这是对其他一些的改进,数据将最终出现在ng模型中,这通常是你想要的.

标记(只需创建一个属性数据文件,以便指令可以找到它)

<input
    data-file
    id="id_image" name="image"
    ng-model="my_image_model" type="file">
Run Code Online (Sandbox Code Playgroud)

JS

app.directive('file', function() {
    return {
        require:"ngModel",
        restrict: 'A',
        link: function($scope, el, attrs, ngModel){
            el.bind('change', function(event){
                var files = event.target.files;
                var file = files[0];

                ngModel.$setViewValue(file);
                $scope.$apply();
            });
        }
    };
});
Run Code Online (Sandbox Code Playgroud)


dan*_*ial 27

干净的方法是编写自己的指令来绑定到"更改"事件.只是为了让你知道IE9不支持FormData,所以你无法真正从change事件中获取文件对象.

您可以使用已经支持IE和FileAPI polyfill的ng-file-upload库,并简化将文件发布到服务器的过程.它使用指令来实现这一目标.

<script src="angular.min.js"></script>
<script src="ng-file-upload.js"></script>

<div ng-controller="MyCtrl">
  <input type="file" ngf-select="onFileSelect($files)" multiple>
</div>
Run Code Online (Sandbox Code Playgroud)

JS:

//inject angular file upload directive.
angular.module('myApp', ['ngFileUpload']);

var MyCtrl = [ '$scope', 'Upload', function($scope, Upload) {
  $scope.onFileSelect = function($files) {
    //$files: an array of files selected, each file has name, size, and type.
    for (var i = 0; i < $files.length; i++) {
      var $file = $files[i];
      Upload.upload({
        url: 'my/upload/url',
        data: {file: $file}
      }).then(function(data, status, headers, config) {
        // file is uploaded successfully
        console.log(data);
      }); 
    }
  }
}];
Run Code Online (Sandbox Code Playgroud)


JLR*_*she 26

我已经扩展了@Stuart Axon的想法,为文件输入添加双向绑定(即允许通过将模型值重置为null来重置输入):

app.directive('bindFile', [function () {
    return {
        require: "ngModel",
        restrict: 'A',
        link: function ($scope, el, attrs, ngModel) {
            el.bind('change', function (event) {
                ngModel.$setViewValue(event.target.files[0]);
                $scope.$apply();
            });

            $scope.$watch(function () {
                return ngModel.$viewValue;
            }, function (value) {
                if (!value) {
                    el.val("");
                }
            });
        }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

演示


Sim*_*obb 20

与此处的其他一些好的答案类似,我写了一个指令来解决这个问题,但是这个实现更接近地反映了附加事件的角度方式.

您可以像这样使用指令:

HTML

<input type="file" file-change="yourHandler($event, files)" />
Run Code Online (Sandbox Code Playgroud)

如您所见,您可以将选定的文件注入事件处理程序,就像将$ event对象注入任何ng事件处理程序一样.

使用Javascript

angular
  .module('yourModule')
  .directive('fileChange', ['$parse', function($parse) {

    return {
      require: 'ngModel',
      restrict: 'A',
      link: function ($scope, element, attrs, ngModel) {

        // Get the function provided in the file-change attribute.
        // Note the attribute has become an angular expression,
        // which is what we are parsing. The provided handler is 
        // wrapped up in an outer function (attrHandler) - we'll 
        // call the provided event handler inside the handler()
        // function below.
        var attrHandler = $parse(attrs['fileChange']);

        // This is a wrapper handler which will be attached to the
        // HTML change event.
        var handler = function (e) {

          $scope.$apply(function () {

            // Execute the provided handler in the directive's scope.
            // The files variable will be available for consumption
            // by the event handler.
            attrHandler($scope, { $event: e, files: e.target.files });
          });
        };

        // Attach the handler to the HTML change event 
        element[0].addEventListener('change', handler, false);
      }
    };
  }]);
Run Code Online (Sandbox Code Playgroud)


ing*_*ham 16

该指令也传递所选文件:

/**
 *File Input - custom call when the file has changed
 */
.directive('onFileChange', function() {
  return {
    restrict: 'A',
    link: function (scope, element, attrs) {
      var onChangeHandler = scope.$eval(attrs.onFileChange);

      element.bind('change', function() {
        scope.$apply(function() {
          var files = element[0].files;
          if (files) {
            onChangeHandler(files);
          }
        });
      });

    }
  };
});
Run Code Online (Sandbox Code Playgroud)

HTML,如何使用它:

<input type="file" ng-model="file" on-file-change="onFilesSelected">
Run Code Online (Sandbox Code Playgroud)

在我的控制器中:

$scope.onFilesSelected = function(files) {
     console.log("files - " + files);
};
Run Code Online (Sandbox Code Playgroud)

  • 我得到一个onChangeHandler不是函数错误吗? (2认同)

小智 7

我建议创建一个指令

<input type="file" custom-on-change handler="functionToBeCalled(params)">

app.directive('customOnChange', [function() {
        'use strict';

        return {
            restrict: "A",

            scope: {
                handler: '&'
            },
            link: function(scope, element){

                element.change(function(event){
                    scope.$apply(function(){
                        var params = {event: event, el: element};
                        scope.handler({params: params});
                    });
                });
            }

        };
    }]);
Run Code Online (Sandbox Code Playgroud)

该指令可以多次使用,它使用自己的作用域而不依赖于父作用域.你也可以给处理函数一些参数.将使用范围对象调用处理程序函数,该对象在您更改输入时处于活动状态.$ apply会在每次调用change事件时更新模型