我尝试使用ng-model的输入标签类型文件:

<input type="file" ng-model="vm.uploadme" />

但是在选择了一个文件后,在控制器中,$scope.vm。Uploadme仍然没有定义。

我如何在我的控制器中获得所选文件?


当前回答

或者你可以获取输入并设置onchange函数:

<input type="file" id="myFileInput" />
document.getElementById("myFileInput").onchange = function (event) {
   console.log(event.target.files);                        
};

其他回答

我必须修改Endy的指令,这样我就可以得到最后修改,lastModifiedDate,名称,大小,类型和数据,以及能够得到一个文件数组。对于那些需要这些额外功能的人,这里就是。

更新: 我发现了一个错误,如果你选择了文件,然后再次选择但取消,这些文件永远不会像它出现时那样取消选择。所以我更新了代码来解决这个问题。

 .directive("fileread", function () {
        return {
            scope: {
                fileread: "="
            },
            link: function (scope, element, attributes) {
                element.bind("change", function (changeEvent) {
                    var readers = [] ,
                        files = changeEvent.target.files ,
                        datas = [] ;
                    if(!files.length){
                        scope.$apply(function () {
                            scope.fileread = [];
                        });
                        return;
                    }
                    for ( var i = 0 ; i < files.length ; i++ ) {
                        readers[ i ] = new FileReader();
                        readers[ i ].index = i;
                        readers[ i ].onload = function (loadEvent) {
                            var index = loadEvent.target.index;
                            datas.push({
                                lastModified: files[index].lastModified,
                                lastModifiedDate: files[index].lastModifiedDate,
                                name: files[index].name,
                                size: files[index].size,
                                type: files[index].type,
                                data: loadEvent.target.result
                            });
                            if ( datas.length === files.length ){
                                scope.$apply(function () {
                                    scope.fileread = datas;
                                });
                            }
                        };
                        readers[ i ].readAsDataURL( files[i] );
                    }
                });

            }
        }
    });

这是一个稍微修改过的版本,允许你在作用域中指定属性的名称,就像你在ng-model, usage中所做的一样:

    <myUpload key="file"></myUpload>

指令:

.directive('myUpload', function() {
    return {
        link: function postLink(scope, element, attrs) {
            element.find("input").bind("change", function(changeEvent) {                        
                var reader = new FileReader();
                reader.onload = function(loadEvent) {
                    scope.$apply(function() {
                        scope[attrs.key] = loadEvent.target.result;                                
                    });
                }
                if (typeof(changeEvent.target.files[0]) === 'object') {
                    reader.readAsDataURL(changeEvent.target.files[0]);
                };
            });

        },
        controller: 'FileUploadCtrl',
        template:
                '<span class="btn btn-success fileinput-button">' +
                '<i class="glyphicon glyphicon-plus"></i>' +
                '<span>Replace Image</span>' +
                '<input type="file" accept="image/*" name="files[]" multiple="">' +
                '</span>',
        restrict: 'E'

    };
});

如果你想要一些更优雅/集成的东西,你可以使用一个装饰器来扩展输入指令,支持type=file。要记住的主要警告是这个方法在IE9中不起作用,因为IE9没有实现File API。在IE9或更早的版本中,使用JavaScript通过XHR上传二进制数据(无论哪种类型)是根本不可能的(使用ActiveXObject访问本地文件系统不被视为使用ActiveX只会带来安全问题)。

这个方法也需要AngularJS 1.4。但是你可以使用$ provider .decorator而不是angular.Module.decorator——我写这个要点是为了演示如何在符合John Papa的AngularJS风格指南的情况下做到这一点:

(function() {
    'use strict';

    /**
    * @ngdoc input
    * @name input[file]
    *
    * @description
    * Adds very basic support for ngModel to `input[type=file]` fields.
    *
    * Requires AngularJS 1.4.x or later. Does not support Internet Explorer 9 - the browser's
    * implementation of `HTMLInputElement` must have a `files` property for file inputs.
    *
    * @param {string} ngModel
    *  Assignable AngularJS expression to data-bind to. The data-bound object will be an instance
    *  of {@link https://developer.mozilla.org/en-US/docs/Web/API/FileList `FileList`}.
    * @param {string=} name Property name of the form under which the control is published.
    * @param {string=} ngChange
    *  AngularJS expression to be executed when input changes due to user interaction with the
    *  input element.
    */
    angular
        .module('yourModuleNameHere')
        .decorator('inputDirective', myInputFileDecorator);

    myInputFileDecorator.$inject = ['$delegate', '$browser', '$sniffer', '$filter', '$parse'];
    function myInputFileDecorator($delegate, $browser, $sniffer, $filter, $parse) {
        var inputDirective = $delegate[0],
            preLink = inputDirective.link.pre;

        inputDirective.link.pre = function (scope, element, attr, ctrl) {
            if (ctrl[0]) {
                if (angular.lowercase(attr.type) === 'file') {
                    fileInputType(
                        scope, element, attr, ctrl[0], $sniffer, $browser, $filter, $parse);
                } else {
                    preLink.apply(this, arguments);
                }
            }
        };

        return $delegate;
    }

    function fileInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
        element.on('change', function (ev) {
            if (angular.isDefined(element[0].files)) {
                ctrl.$setViewValue(element[0].files, ev && ev.type);
            }
        })

        ctrl.$isEmpty = function (value) {
            return !value || value.length === 0;
        };
    }
})();

为什么一开始不这么做呢?AngularJS的支持只支持到IE9。如果你不同意这个决定,并认为他们无论如何都应该把它放进去,那就赶紧转向Angular 2+,因为更好的现代支持正是Angular 2存在的原因。

The issue is (as was mentioned before) that without the file api support doing this properly is unfeasible for the core given our baseline being IE9 and polyfilling this stuff is out of the question for core. Additionally trying to handle this input in a way that is not cross-browser compatible only makes it harder for 3rd party solutions, which now have to fight/disable/workaround the core solution. ... I'm going to close this just as we closed #1236. Angular 2 is being build to support modern browsers and with that file support will easily available.

我使用这个指令:

angular.module('appFilereader', []).directive('appFilereader', function($q) {
    var slice = Array.prototype.slice;

    return {
        restrict: 'A',
        require: '?ngModel',
        link: function(scope, element, attrs, ngModel) {
                if (!ngModel) return;

                ngModel.$render = function() {};

                element.bind('change', function(e) {
                    var element = e.target;

                    $q.all(slice.call(element.files, 0).map(readFile))
                        .then(function(values) {
                            if (element.multiple) ngModel.$setViewValue(values);
                            else ngModel.$setViewValue(values.length ? values[0] : null);
                        });

                    function readFile(file) {
                        var deferred = $q.defer();

                        var reader = new FileReader();
                        reader.onload = function(e) {
                            deferred.resolve(e.target.result);
                        };
                        reader.onerror = function(e) {
                            deferred.reject(e);
                        };
                        reader.readAsDataURL(file);

                        return deferred.promise;
                    }

                }); //change

            } //link
    }; //return
});

然后像这样调用它:

<input type="file" ng-model="editItem._attachments_uri.image" accept="image/*" app-filereader />

属性(editItem.editItem._attachments_uri.image)将使用您选择的文件内容填充为data-uri(!)。

请注意,这个脚本不会上传任何东西。它只会用数据uri (base64)编码的文件内容填充模型。

看看这里的工作演示: http://plnkr.co/CMiHKv2BEidM9SShm9Vv

我创建了一个指令并在bower上注册。

这个库将帮助您建模输入文件,不仅返回文件数据,而且还返回文件dataurl或base64。

{
    "lastModified": 1438583972000,
    "lastModifiedDate": "2015-08-03T06:39:32.000Z",
    "name": "gitignore_global.txt",
    "size": 236,
    "type": "text/plain",
    "data": "data:text/plain;base64,DQojaWdub3JlIHRodW1ibmFpbHMgY3JlYXRlZCBieSB3aW5kb3dz…xoDQoqLmJhaw0KKi5jYWNoZQ0KKi5pbGsNCioubG9nDQoqLmRsbA0KKi5saWINCiouc2JyDQo="
}

https://github.com/mistralworks/ng-file-model/