Я попытался использовать ng-модель во входном теге с типом файла:
<input type="file" ng-model="vm.uploadme" />
Но после выбора файла в контроллере $ scope.vm.uploadme все еще не определен.
Как мне получить выбранный файл в моем контроллере?
Я попытался использовать ng-модель во входном теге с типом файла:
<input type="file" ng-model="vm.uploadme" />
Но после выбора файла в контроллере $ scope.vm.uploadme все еще не определен.
Как мне получить выбранный файл в моем контроллере?
Я создал обходной путь с директивой:
.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 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;
});
});
}
}
}]);
<input type="file" fileread="$parent.uploadme" />
. Я нашел это с помощью ionic, потому что многие из его директив создают дочернюю область. Мне пришлось использовать $parent.$parent.$parent.newImage
, чтобы подключиться к моему корневому контроллеру.
- person Simon East; 16.10.2015
require: '^form',
в определение директивы, передайте контроллер формы в функцию ссылки, затем вызовите form.$setDirty()
в функции $apply
.
- person nmgeek; 16.10.2016
$scope.$on('$destroy', function(){ element.unbind("change"); });
исправленный код @Nawlbergs
- person Kugan Kumar; 30.11.2017
reader.readAsDataURL
устарел. Современный код использует URL.create ObjectURL () .
- person georgeawg; 13.05.2019
Я использую эту директиву:
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 (!).
Обратите внимание, что этот скрипт ничего не загружает. Он будет заполнять вашу модель только содержимым вашего файла, закодированного с объявлением data-uri (base64).
Ознакомьтесь с рабочей демонстрацией здесь: http://plnkr.co/CMiHKv2BEidM9SShm9Vv
image in dummy.images
на image in dummy.images track by $index
теперь работала нормально. Благодарность
- person Diego Vieira; 10.01.2014
ngModel
$render
?
- person sp00m; 06.04.2016
restrict: 'A'
?
- person Anders Lindén; 08.11.2016
reader.readAsDataURL
устарел. Современный код использует URL.create ObjectURL () .
- person georgeawg; 13.05.2019
<input type="file">
для работы с ng-model
ng-model
Директива core ng-model
не работает с <input type="file">
из коробки.
Эта настраиваемая директива включает ng-model
и имеет дополнительное преимущество, позволяя директивам ng-change
, ng-required
и ng-form
работать с <input type="file">
.
angular.module("app",[]);
angular.module("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);
})
}
}
});
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
<h1>AngularJS Input `type=file` Demo</h1>
<input type="file" select-ng-files ng-model="fileArray" multiple>
<code><table ng-show="fileArray.length">
<tr><td>Name</td><td>Date</td><td>Size</td><td>Type</td><tr>
<tr ng-repeat="file in fileArray">
<td>{{file.name}}</td>
<td>{{file.lastModified | date : 'MMMdd,yyyy'}}</td>
<td>{{file.size}}</td>
<td>{{file.type}}</td>
</tr>
</table></code>
</body>
Это дополнение к решению @ endy-tjahjono.
В итоге я не смог получить значение uploadme из области видимости. Несмотря на то, что uploadme в HTML был явно обновлен директивой, я все еще не мог получить доступ к его значению с помощью $ scope.uploadme. Однако я смог установить его значение из области видимости. Загадочно, правда ..?
Как оказалось, дочерняя область была создана директивой, а у дочерней области была собственная uploadme.
Решением было использовать объект, а не примитив для хранения значения uploadme.
В контроллере у меня есть:
$scope.uploadme = {};
$scope.uploadme.src = "";
и в HTML:
<input type="file" fileread="uploadme.src"/>
<input type="text" ng-model="uploadme.src"/>
В директиву нет изменений.
Теперь все работает, как ожидалось. Я могу получить значение uploadme.src со своего контроллера с помощью $ scope.uploadme.
$scope.uploadme = { src: '' }
- person maxathousand; 05.09.2017
Создаю директиву и регистрируюсь на bower.
Эта библиотека поможет вам моделировать входной файл, не только возвращать данные файла, но также и dataurl файла или базу 64.
{
"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/
reader.readAsDataURL
устарел. Современный код использует URL.create ObjectURL () .
- person georgeawg; 13.05.2019
Это немного измененная версия, которая позволяет вам указывать имя атрибута в области, как если бы вы это делали с ng-model, использование:
<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'
};
});
Для ввода нескольких файлов с использованием 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);
});
});
}
}
}]);
Мне пришлось сделать то же самое при множественном вводе, поэтому я обновил метод @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] );
}
});
}
}
});
Мне пришлось изменить директиву Энди, чтобы я мог получать Last Modified, 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] );
}
});
}
}
});
Если вам нужно что-то более элегантное / интегрированное, вы можете использовать декоратор, чтобы расширить input
директива с поддержкой type=file
. Главное предостережение, о котором следует помнить, заключается в том, что этот метод не будет работать в IE9, поскольку IE9 не реализует File API. Использование JavaScript для загрузки двоичных данных независимо от типа через XHR просто невозможно изначально в IE9 или более ранних версиях (использование ActiveXObject
для доступа к локальной файловой системе не считается, поскольку использование ActiveX просто вызывает проблемы с безопасностью).
Этот точный метод также требует AngularJS 1.4.x или более поздней версии, но вы можете адаптировать его для использования $provide.decorator
, а не angular.Module.decorator
- я написал эту суть, чтобы продемонстрировать, как это сделать в соответствии с Руководство по стилю 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.
Проблема в том (как упоминалось ранее) в том, что без поддержки файлового api, выполняющей это должным образом, это невозможно для ядра, учитывая, что наш базовый уровень - IE9, и о полифилдинге этого материала для ядра не может быть и речи.
Кроме того, попытка обработать этот ввод способом, несовместимым с кроссбраузерностью, только усложняет работу сторонних решений, которым теперь приходится бороться / отключать / обходить основное решение.
...
Я собираюсь закрыть это так же, как мы закрыли # 1236. Angular 2 создается для поддержки современных браузеров, и с его помощью поддержка файлов будет легко доступна.
В качестве альтернативы вы можете получить ввод и установить функцию onchange:
<input type="file" id="myFileInput" />
document.getElementById("myFileInput").onchange = function (event) {
console.log(event.target.files);
};
Попробуйте, это работает для меня в 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);