Ben tür dosyası ile giriş etiketinde ng-modelini kullanmaya çalıştım:
<input type="file" ng-model="vm.uploadme" />
Ancak bir dosya seçtikten sonra, denetleyicide $ scope.vm.uploadme hala tanımsız.
Seçilen dosyayı denetleyicime nasıl alabilirim?
Ben tür dosyası ile giriş etiketinde ng-modelini kullanmaya çalıştım:
<input type="file" ng-model="vm.uploadme" />
Ancak bir dosya seçtikten sonra, denetleyicide $ scope.vm.uploadme hala tanımsız.
Seçilen dosyayı denetleyicime nasıl alabilirim?
Yanıtlar:
Yönerge ile bir geçici çözüm oluşturdum:
.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]);
});
}
}
}]);
Ve giriş etiketi:
<input type="file" fileread="vm.uploadme" />
Veya yalnızca dosya tanımı gerekiyorsa:
.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;
});
});
}
}
}]);
Bu yönergeyi kullanıyorum:
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
});
ve şu şekilde çağırın:
<input type="file" ng-model="editItem._attachments_uri.image" accept="image/*" app-filereader />
(EditItem.editItem._attachments_uri.image) özelliği, veri uri (!) Olarak seçtiğiniz dosyanın içeriğiyle doldurulur.
Bu komut dosyasının hiçbir şey yüklemeyeceğini lütfen unutmayın. Modelinizi yalnızca dosya kodlu reklamınızın içeriğiyle bir data-uri (base64) dolduracaktır.
Çalışan bir demoya buradan göz atın: http://plnkr.co/CMiHKv2BEidM9SShm9Vv
ngModel
'ın $render
fonksiyonunu?
<input type="file">
çalışmak için nasıl etkinleştirilirng-model
ng-model
Temel ng-model
direktif <input type="file">
kutudan çıktığı haliyle çalışmaz .
Bu özel yönerge sağlayan ng-model
ve etkinleştirme yararı vardır ng-change
, ng-required
ve ng-form
birlikte çalışmaya direktifleri <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>
Bu @ endy-tjahjono'nun çözümü için bir ek.
Uploadme değerini kapsamından alamadım . HTML'deki uploadme direktif tarafından görsel olarak güncellenmiş olsa da , yine de değerine $ scope.uploadme ile erişemedim. Yine de değerini kapsamdan belirleyebildim. Gizemli, değil mi?
Anlaşıldığı üzere, direktif tarafından bir alt kapsam oluşturuldu ve alt kapsamın kendi uploadme'si vardı .
Çözüm, uploadme değerini korumak için ilkelden ziyade bir nesne kullanmaktı .
Denetleyicide:
$scope.uploadme = {};
$scope.uploadme.src = "";
ve HTML'de:
<input type="file" fileread="uploadme.src"/>
<input type="text" ng-model="uploadme.src"/>
Direktifte değişiklik yapılmamıştır.
Şimdi, hepsi beklendiği gibi çalışıyor. $ Scope.uploadme kullanarak denetleyicimden uploadme.src değerini alabilirim.
$scope.uploadme = { src: '' }
Merhaba millet i bir direktif oluşturmak ve çardak kayıtlı.
bu lib, sadece dosya verilerini döndürmekle kalmaz, aynı zamanda dataurl veya base 64 dosyalarına da giriş dosyası modellemenize yardımcı olur.
{
"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/
Umut sana yardım edecek
reader.readAsDataURL
Yöntem, eski. Modern kod URL.create ObjectURL () kullanır .
Bu, ng-modelinde, kullanımda olduğu gibi, kapsamda özniteliğin adını belirtmenize izin veren biraz değiştirilmiş bir sürümdür:
<myUpload key="file"></myUpload>
Direktif:
.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 veya alt çizgi kullanarak birden fazla dosya girmek için:
.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);
});
});
}
}
}]);
function filesModelDirective(){
return {
controller: function($parse, $element, $attrs, $scope){
var exp = $parse($attrs.filesModel);
$element.on('change', function(){
exp.assign($scope, this.files[0]);
$scope.$apply();
});
}
};
}
app.directive('filesModel', filesModelDirective);
Birden fazla girişte aynı şeyi yapmak zorunda kaldım, bu yüzden @Endy Tjahjono yöntemini güncelledim. Okunan tüm dosyaları içeren bir dizi döndürür.
.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] );
}
});
}
}
});
Ben Lasty Değiştirilmiş, lastModifiedDate, adı, boyutu, türü ve veri almak yanı sıra bir dizi dosya almak mümkün böylece Endy yönergesini değiştirmek zorunda kaldı. Bu ekstra özelliklere ihtiyaç duyanlarınız için işte buradasınız.
GÜNCELLEME: Dosya (lar) ı seçip tekrar seçerseniz ancak iptal ederseniz, dosyaların göründüğü gibi hiçbir zaman seçimi kaldırılmazsa bir hata buldum. Bunu düzeltmek için kodumu güncelledim.
.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] );
}
});
}
}
});
Biraz daha zarif / entegre bir şey istiyorsanız , direktifin desteğiyle genişletilmesi için bir dekoratör kullanabilirsiniz . Akılda tutulması gereken ana uyarı , IE9 Dosya API'sını uygulamadığı için bu yöntemin IE9'da çalışmayacağıdır . XHR aracılığıyla türden bağımsız olarak ikili verileri yüklemek için JavaScript kullanmak IE9 veya daha eski sürümlerde yerel olarak mümkün değildir ( yerel dosya sistemine erişmek için kullanımı ActiveX kullanmak sayılmaz, sadece güvenlik sorunları ister).input
type=file
ActiveXObject
Bu kesin yöntem ayrıca AngularJS 1.4.x veya daha yenisini gerektirir, ancak bunu $provide.decorator
yerine kullanmak için uyarlayabilirsiniz angular.Module.decorator
- John Papa'nın AngularJS stil kılavuzuna uyurken nasıl yapılacağını göstermek için bu özeti yazdım :
(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;
};
}
})();
Bu neden ilk etapta yapılmadı? AngularJS desteğinin yalnızca IE9'a kadar ulaşması amaçlanmıştır. Bu karara katılmıyorsanız ve bunu yine de koymaları gerektiğini düşünüyorsanız, vagonu Açısal 2 + 'ya atlayın, çünkü daha iyi modern destek tam anlamıyla Açısal 2'nin var olmasıdır.
Sorun (daha önce de belirtildiği gibi), dosya api desteği olmadan bunu düzgün yapmak temel bizim IE9 ve bu şeyler çok dolgu doldurma çekirdek göz önüne alındığında çekirdek için mümkün değildir.
Ayrıca, bu girdiyi çapraz tarayıcı uyumlu olmayan bir şekilde işlemeye çalışmak, artık çekirdek çözümle mücadele etmek / devre dışı bırakmak / geçici çözüm bulmak zorunda olan 3. taraf çözümleri zorlaştırmaktadır.
...
# 1236'yı kapattığımız gibi bunu kapatacağım. Açısal 2, modern tarayıcıları desteklemek için oluşturuluyor ve bu dosya desteği ile kolayca sunulacak.
Bunu deneyin, bu benim için açısal JS'de çalışıyor
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);