[英]How do I two-way bind to a type=“file” input with ng-model?
Basically I want to do this: 基本上我想这样做:
<input type="file" ng-model="variable_in_scope">
When I pick a file, variable_in_scope
should get assigned to the file object picked. 当我选择一个文件时,
variable_in_scope
应该分配给所选择的文件对象。 Also, if the value of variable_in_scope
gets changed anywhere else in my page, it should update the text next to the "Choose File" button to indicate that the chosen file has changed. 另外,如果
variable_in_scope
的值在我页面的其他位置更改了,它应该更新“选择文件”按钮旁边的文本以指示所选文件已更改。
With any other type of input, this would just work. 使用任何其他类型的输入,这将起作用。
I don't need to do anything fancy like actually see the contents of the file. 我不需要做任何花哨的操作,例如实际看到文件的内容。 Ultimately, I want to post it, but I've found out you can do this by setting the file object you get into a FormData object , without actually reading the contents into Javascript-land.
最终,我想发布它,但是我发现您可以通过将获取到FileData对象的文件对象设置为FormData对象来完成此操作,而无需将内容实际读入Javascript领域。
I've found other questions about picking files with angular, but none had a two-way binding solution. 我还发现了其他有关选择角度文件的问题,但是没有一个双向绑定解决方案。
My answer on another question provides a way to do this with ng-model
, but since that question is not specifically about two way binding (and my answer is fairly hard to find there), I'll reproduce it here: 我对另一个问题的回答提供了使用
ng-model
做到这一点的方法,但是由于该问题不是专门针对双向绑定的(我的回答在那儿很难找到),因此我将在此处进行重现:
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("");
}
});
}
};
}]);
To use it, you simply need to add this to your angular module and include a bind-file
attribute on the file pickers where you want to use it. 要使用它,您只需要将其添加到您的angular模块中,并在您要使用它的文件选择器中包含
bind-file
属性。
Angular doesn't support binding to file-type inputs , but I cobbled together a solution using a number of other answers. Angular不支持绑定到文件类型的输入 ,但是我使用许多其他答案将解决方案拼凑在一起。
app.directive('filePicker', filePicker);
filePicker.$inject = ['$log', '$document'];
function filePicker($log,$document) {
var directive = {
restrict: 'A',
require: 'ngModel',
scope: {
ngModel: '='
},
link: _link
};
return directive;
function _link(scope, elem, attrs, ngModel) {
// check if valid input element
if( elem[0].nodeName.toLowerCase() !== 'input' ) {
$log.warn('filePicker:', 'The directive will work only for input element, actual element is a', elem[0].nodeName.toLowerCase());
return;
}
// check if valid input type file
if( attrs.type != 'file' ) {
$log.warn('filePicker:', 'Expected input type file, received instead:', attrs.type, 'on element:', elem);
return;
}
// listen for input change
elem.on('change', function(e) {
// get files
var files = elem[0].files;
// update model value
scope.$apply(function() {
attrs.multiple ? scope.ngModel = files : scope.ngModel = files[0];
});
});
scope.$watch('ngModel', function() {
if (!scope.ngModel)
elem[0].value = ""; // clears all files; there's no way to remove only some
});
}
}
This solution showed me how to use a directive to implement a custom binding to ng-model. 该解决方案向我展示了如何使用指令来实现对ng-model的自定义绑定。 It enables accessing the contents of the file, so if you need that functionality you can add it back to my solution.
它使您能够访问文件的内容,因此,如果需要该功能,可以将其重新添加到我的解决方案中。
However, it had some problems with its binding. 但是,它的绑定存在一些问题。 It would correctly set the value of my
variable_in_scope
, but if there were other things bound to the value of variable_in_scope
, they wouldn't update. 它将正确设置我的
variable_in_scope
的值,但是如果variable_in_scope
的值绑定了其他内容,则它们不会更新。 The trick was to use isolate scope and $apply
. 诀窍是使用隔离范围和
$apply
。 Then you don't need to mess with this $setViewValue
business. 这样,您就不必为此
$setViewValue
业务搞乱了。 Just set it and forget it. 只需设置它,然后忘记它。
That got me as far as one-way-binding. 那使我达到了单向绑定的目的。 If I set a value to
variable_in_scope
, however, the file picker still showed that I had the original file selected. 但是,如果将值设置为
variable_in_scope
,则文件选择器仍显示我已选择原始文件。 In my case all I really want to do is clear the selected file. 就我而言,我真正想做的就是清除所选文件。 I found out the Javascript magic to do this and set up a
$watch
on the ngModel
to trigger it. 我发现了执行此操作的Javascript魔术,并在
ngModel
上设置了一个$watch
来触发它。
If you want to set the file to a different value programmatically, good luck to you, because FileList
is read-only . 如果要通过编程将文件设置为其他值,请祝您好运,因为
FileList
是只读的 。 The magic trick lets you clear the FileList
, but you can't add anything back. 魔术使您可以清除
FileList
,但不能添加任何内容。 Maybe you can create a new FileList
and assign it to .files
, but at a cursory glance I didn't see a way to do that. 也许您可以创建一个新的
FileList
并将其分配给.files
,但是粗略地看一眼,我看不到这样做的方法。
Helped for me: FileUploader 对我有帮助: FileUploader
Hide the input element with display: none; 使用display隐藏输入元素:none; then use a label to go on top of the input element, and a label you connect to your scope variable.
然后使用标签放在输入元素的顶部,然后使用标签连接到范围变量。 See numerous posts on SO.
在SO上看到许多帖子。 Like this:
像这样:
<label for="idFileUpload" class="custom-file-upload">
SelectFile
</label>
<input type="file" id="idFileUpload" nv-file-select uploader="uploader">
<label id="idSelectedFile">{{selectedFile}}</label>
<md-button id="idUploadBtn" md-no-ink class="md-primary settingsBtns" ng-click="uploader.uploadAll()" ng-disabled="!uploader.getNotUploadedItems().length">Upload</md-button>
CSS: CSS:
input[type="file"] {
display: none;
}
.custom-file-upload {
background-color: green;
color: white;
border: 1px solid #ccc;
display: inline-block;
padding: 6px 12px;
cursor: pointer;
}
In the events the FileUploader fires, you can fetch the value of the input element. 在FileUploader触发的事件中,您可以获取输入元素的值。 HTH
HTH
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.