27

我想用 AngularJS 获取一个文件:

HTML:

<div ng-controller="TopMenuCtrl">
    <button class="btn" ng-click="isCollapsed = !isCollapsed">Toggle collapse</button>
    <input type="file" ng-model="filepick" ng-change="pickimg()" multiple />
    <output id="list"></output> 
</div>

javascript:

angular.module('plunker', ['ui.bootstrap']);
function TopMenuCtrl($scope) {
    $scope.pickimg = function() {
        alert('a');
    };
}

如何onchange在 AngularJSpickimg函数上绑定输入文件操作?以及如何操作之后上传的文件?

4

8 回答 8

49

Angular 还不支持ng-change for input[type=file]所以你必须自己滚动 onchange 实现。

首先,在 HTML 中,为 onchange 定义 Javascript,如下所示:

<input ng-model="photo"
       onchange="angular.element(this).scope().file_changed(this)"
       type="file" accept="image/*" />

然后在你的 Angular 控制器代码中,定义函数:

$scope.file_changed = function(element) {

     $scope.$apply(function(scope) {
         var photofile = element.files[0];
         var reader = new FileReader();
         reader.onload = function(e) {
            // handle onload
         };
         reader.readAsDataURL(photofile);
     });
};
于 2013-05-19T08:36:03.203 回答
17

我使用上述方法尝试在选择新文件时加载预览图像,但是当我这样尝试时它不起作用:

$scope.file_changed = function(element, $scope) {

     $scope.$apply(function(scope) {
         var photofile = element.files[0];
         var reader = new FileReader();
         reader.onload = function(e) {
            $scope.prev_img = e.target.result;
         };
         reader.readAsDataURL(photofile);
     });
});

我深入研究了它,发现 $scope.$apply 应该在 reader.onLoad 内,否则更改 $scope 变量将不起作用,所以我做了以下并且它起作用了:

$scope.file_changed = function(element) {

        var photofile = element.files[0];
        var reader = new FileReader();
        reader.onload = function(e) {
            $scope.$apply(function() {
                $scope.prev_img = e.target.result;
            });
        };
        reader.readAsDataURL(photofile);
 };
于 2013-10-13T13:21:03.823 回答
6

Teemu 解决方案不适用于 IE9。

我已经为不支持 HTML5 FormData 的浏览器编写了一个简单的带有 Flash polyfill 的 angular 指令,您还可以收听上传进度事件。

https://github.com/danialfarid/ng-file-upload 演示:http ://angular-file-upload.appspot.com/

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

<div ng-controller="MyCtrl">
  <input type="text" ng-model="additionalData">
  <div ngf-select ng-model="files" >
</div>

控制器:

Upload.upload({
    url: 'my/upload/url',
    data: additionalData,
    file: files
  }).then(success, error, progress); 
于 2013-08-20T20:39:49.430 回答
4

以下是我使用指令的方法。

指示

angular
  .module('yourModule')
  .directive('fileChange', function() {
    return {
     restrict: 'A',
     scope: {
       handler: '&'
     },
     link: function (scope, element) {
      element.on('change', function (event) {
        scope.$apply(function(){
          scope.handler({files: event.target.files});
        });
      });
     }
    };
});

HTML

<input type="file" file-change handler="fileSelect(files)">

控制器

fileSelect = function (files) {
      var file = files[0];
      //you will get the file object here
}
于 2016-03-02T13:22:15.713 回答
3

使用上面的 Madura 回答,这是读取本地 JSON 文件的完整流程:

创建指令:

angular
  .module('app.services')
  .directive('fileChange', function() {
    return {
     restrict: 'A',
     scope: {
       handler: '&'
     },
     link: function (scope, element) {
      element.on('change', function (event) {
        scope.$apply(function(){
          scope.handler({files: event.target.files});
        });
      });
     }
    };
});

HTML:

<input type="file" file-change handler="fileSelect(files)">

Javascript:

$scope.fileSelect = function(files) {
  var file = files[0];
  var reader = new FileReader();
  reader.onload = function(e) {
    console.log("on load", e.target.result);
  }
  reader.readAsText(file);
}
于 2016-12-11T17:06:13.927 回答
2

这是我为解决这个问题而编写的一个轻量级指令,它反映了附加事件的角度方式。

您可以像这样使用指令:

HTML

<input type="file" file-change="yourHandler($event, files)" />

如您所见,您可以将选定的文件注入到您的事件处理程序中,就像您将 $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);
      }
    };
  }]);
于 2014-10-27T15:34:31.970 回答
0

我做了一个指令。这是小提琴
该应用程序用于选择 csv 并将它们显示为 html 表。
使用 on-file-change 指令,您将能够在控制器本身中定义文件读取和解析(可能是服务)逻辑,这将提供更大的灵活性。只是为了说明,ac.onFileChange传递给 on-file-change 属性的函数将成为指令内输入更改事件的处理程序。

(function (angular, document) {

   angular
      .module("app.directives", [])
      .directive("onFileChange", ["$parse", function ($parse) {
         return {
            restrict: "A",
            link: function (scope, ele, attrs) {
               // onFileChange is a reference to the same function which you would define 
               // in the controller. So that you can keep your logic in the controller.
               var onFileChange = $parse(attrs.onFileChange.split(/\(/)[0])(scope)
               ele.on("change", onFileChange)
               ele.removeAttr("on-file-change")
            }
         }
      }])

   angular
      .module("app.services", [])
      .service("Parse", ["$q", function ($q) {
         var Parse = this
         Parse.csvAsGrid = function (file) {
            return $q(function (resolve, reject) {
               try {
                  Papa.parse(file, {
                     complete: function (results) {
                        resolve(results.data)
                     }
                  })
               } catch (e) {
                  reject(e)
               }
            })
         }
      }])

   angular
      .module("app", ["app.directives", "app.services"])
      .controller("appCtrl", ["$scope", "Parse", function ($scope, Parse) {
         var ac = this
         ac.fileName = ""
         ac.onFileChange = function (event) {
            if (!event.target.files.length) {
               return
            }
            Parse.csvAsGrid(event.target.files[0]).then(outputAsTable)
         }

         ac.clearInput = function (event) {
            var input = angular.element(event.target)
            input.val("")
            document.getElementById("output").innerHTML = ""
         }

         function outputAsTable(grid) {
            var table = ['<table border="1">']
            grid.map(function (row) {
               table.push('<tr>')
               row.map(function (cell) {
                  table.push('<td>' + cell.replace(/["']/g, "") + '</td>')
               })
               table.push('</tr>')
            })
            table.push('</table>')
            document.getElementById("output").innerHTML = table.join("\n")
         }
      }])

})(angular, document)
table {
  border-collapse: collapse;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.2/papaparse.min.js"></script>

<div ng-app="app" ng-controller="appCtrl as ac">
  <label>Select a comma delimited CSV file:-</label>  
  <input id="filePicker" type="file" on-file-change="ac.onFileChange(event)" ng-click="ac.clearInput($event)"/>{{ac.fileName}}  
</div>
<div id="output"></div>

于 2016-10-15T05:05:59.373 回答
0

使用 ng-model-controller 的指令:

app.directive("selectNgFiles", function() {
  return {
    require: "ngModel",
    link: function postLink(scope,elem,attrs,ngModel) {
      elem.on("change", function(e) {
        var files = elem[0].files;
        ngModel.$setViewValue(files);
      })
    }
  }
});

用法:

<input type="file" select-ng-files ng-model="fileArray"
       ng-change="pickimg()" multiple>

有关更多信息,请参阅使用 ng-model 的指令的工作演示

于 2019-02-25T18:41:02.623 回答