タイプファイルの入力タグで ng-model を使用しようとしました:
<input type="file" ng-model="vm.uploadme" />
しかし、コントローラーでファイルを選択した後、 $scope.vm.uploadme はまだ定義されていません。
コントローラーで選択したファイルを取得するにはどうすればよいですか?
タイプファイルの入力タグで ng-model を使用しようとしました:
<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;
});
});
}
}
}]);
私はこのディレクティブを使用します:
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
これは、@endy-tjahjono のソリューションの補遺です。
スコープからuploadmeの値を取得できなくなりました。HTML のuploadmeがディレクティブによって明らかに更新されたにもかかわらず、$scope.uploadme によってその値にアクセスできませんでした。ただし、スコープから値を設定することはできました。神秘的ですよね..?
結局のところ、ディレクティブによって子スコープが作成され、子スコープには独自のuploadmeがありました。
解決策は、プリミティブではなくオブジェクトを使用して、uploadmeの値を保持することでした。
私が持っているコントローラで:
$scope.uploadme = {};
$scope.uploadme.src = "";
そしてHTMLで:
<input type="file" fileread="uploadme.src"/>
<input type="text" ng-model="uploadme.src"/>
ディレクティブに変更はありません。
これで、すべてが期待どおりに機能します。$scope.uploadme を使用して、コントローラーからuploadme.srcの値を取得できます。
ディレクティブを作成し、bower に登録しました。
このライブラリは、入力ファイルをモデリングするのに役立ちます。ファイル データを返すだけでなく、ファイル dataurl または base 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="
}
これはわずかに変更されたバージョンで、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] );
}
});
}
}
});