我尝试使用ng-model的输入标签类型文件:
<input type="file" ng-model="vm.uploadme" />
但是在选择了一个文件后,在控制器中,$scope.vm。Uploadme仍然没有定义。
我如何在我的控制器中获得所选文件?
我尝试使用ng-model的输入标签类型文件:
<input type="file" ng-model="vm.uploadme" />
但是在选择了一个文件后,在控制器中,$scope.vm。Uploadme仍然没有定义。
我如何在我的控制器中获得所选文件?
当前回答
如果你想要一些更优雅/集成的东西,你可以使用一个装饰器来扩展输入指令,支持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.
其他回答
我必须在多个输入上做同样的事情,所以我更新了@Endy Tjahjono方法。 它返回一个包含所有已读文件的数组。
.directive("fileread", function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var readers = [] ,
files = changeEvent.target.files ,
datas = [] ;
for ( var i = 0 ; i < files.length ; i++ ) {
readers[ i ] = new FileReader();
readers[ i ].onload = function (loadEvent) {
datas.push( loadEvent.target.result );
if ( datas.length === files.length ){
scope.$apply(function () {
scope.fileread = datas;
});
}
}
readers[ i ].readAsDataURL( files[i] );
}
});
}
}
});
如果你想要一些更优雅/集成的东西,你可以使用一个装饰器来扩展输入指令,支持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.
对于使用lodash或下划线输入的多个文件:
.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
return _.map(changeEvent.target.files, function(file){
scope.fileread = [];
var reader = new FileReader();
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread.push(loadEvent.target.result);
});
}
reader.readAsDataURL(file);
});
});
}
}
}]);
试试这个,这在angular JS中对我有用
let fileToUpload = `${documentLocation}/${documentType}.pdf`;
let absoluteFilePath = path.resolve(__dirname, fileToUpload);
console.log(`Uploading document ${absoluteFilePath}`);
element.all(by.css("input[type='file']")).sendKeys(absoluteFilePath);
我用指令创建了一个变通方法:
.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
var reader = new FileReader();
reader.onload = function (loadEvent) {
scope.$apply(function () {
scope.fileread = loadEvent.target.result;
});
}
reader.readAsDataURL(changeEvent.target.files[0]);
});
}
}
}]);
input标签变成:
<input type="file" fileread="vm.uploadme" />
或者如果只需要文件定义:
.directive("fileread", [function () {
return {
scope: {
fileread: "="
},
link: function (scope, element, attributes) {
element.bind("change", function (changeEvent) {
scope.$apply(function () {
scope.fileread = changeEvent.target.files[0];
// or all selected files:
// scope.fileread = changeEvent.target.files;
});
});
}
}
}]);