画像をアップロードしているAngularJS$http POSTリクエストから「progress」イベントを取得するにはどうすればよいですか?これをクライアント側で行うことは可能ですか、それともサーバーがデータを受信するときに進行状況を報告する必要がありますか?
6 に答える
純粋な角度の使用:
function upload(data) {
var formData = new FormData();
Object.keys(data).forEach(function(key){formData.append(key, data[key]);});
var defer = $q.defer();
$http({
method: 'POST',
data: formData,
url: <url>,
headers: {'Content-Type': undefined},
uploadEventHandlers: { progress: function(e) {
defer.notify(e.loaded * 100 / e.total);
}}
}).then(defer.resolve.bind(defer), defer.reject.bind(defer));
return defer.promise;
}
そしてどこか他の場所..。
// file is a JS File object
upload({avatar:file}).then(function(responce){
console.log('success :) ', response);
}, function(){
console.log('failed :(');
}, function(progress){
console.log('uploading: ' + Math.floor(progress) + '%');
});
これらを処理するsimple/lightweightangular -file-uploadディレクティブを使用することもできます。FileAPIフラッシュシムを使用したHTML5以外のブラウザのドラッグアンドドロップ、ファイルの進行状況/中止、およびファイルのアップロードをサポートします
<div ng-controller="MyCtrl">
<input type="file" ng-file-select="onFileSelect($files)" multiple>
</div>
JS:
//inject angular file upload directive.
angular.module('myApp', ['angularFileUpload']);
var MyCtrl = [ '$scope', '$upload', function($scope, $upload) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var $file = $files[i];
$upload.upload({
url: 'my/upload/url',
file: $file,
progress: function(e){}
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}
}
}];
$ http.post()をこれに使用できるとは思いません。
クライアント側に関しては、HTML5ブラウザーで動作するはずですが、おそらく独自のXMLHttpRequestオブジェクトとonprogress
リスナーを作成する必要があります。アイデアについては、AngularJS:同時にアップロードされている各ファイルのステータスの追跡を参照してください。
Angularにはアップロードを処理するための何かが組み込まれているとは思いません。
あなたの最善の策は、jQueryFileUploadのようなものを使用することだと思います。ソリューションのアイデアは、{progress:0}
デフォルトとして返され、それ自体の内部にサービスを作成し、jQuery File Uploadの進行状況更新コールバックを実装します。これにより、進行状況が更新され続けます。Angularのバインディングのおかげで、アップロードの進行状況は同期されます。
angular.module('myApp.services', [])
.factory('Uploader', function() {
var uploaderService = {};
var status = { progress: 0 };
uploaderService.upload = function(inputEl) {
inputEl.fileupload({
/* ... */
progressall: function (e, data) {
status.progress = parseInt(data.loaded / data.total * 100, 10);
}
});
};
return uploaderService;
});
別の解決策は次のとおりです。
window.XMLHttpRequest = (function (orig) {
if (orig) {
var intercept = [],
result = function () {
var r = new orig();
if (r.upload) {
$(r).on(
'abort error load loadend loadstart progress',
function (e) {
$(document).trigger('upload.XHR', e);
}
);
}
if (intercept.length) {
intercept[0].push({
request:r
});
}
return r;
};
result.grab = function (f) {
intercept.unshift([]);
f();
return intercept.shift();
};
return result;
}
return function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) {}
throw new Error("This browser does not support XMLHttpRequest.");
};
}(window.XMLHttpRequest));
ノート:
AngularJSは現在、への参照を
window.XMLHttpRequest
プライベートXHR
変数として保存し、次のように使用しますnew XHR()
。これが変わるとは思えないので、上記のシムのようなコードは問題なく機能するはずです。Mozillaにはいくつかの拡張機能があります:
XMLHttpRequest
オプションの引数を受け入れます。上記のコードはこれを処理しませんが、AngularJSはこれらの拡張機能を使用しません。考えられる使用法の1つ(現在のすべてのリクエストを表示し、[キャンセル]ボタンを実装する場合):
$(document).on('upload.XHR', function (_e, e) {
switch (e.type) {
// do your thing here
}
});
- 別の可能な使用法:
var list = window.XMLHttpRequest.grab(function () {
// start one or more $http requests here, or put some code
// here that indirectly (but synchronously) starts requests
$http.get(...);
couchDoc.save();
couchDoc.attach(blob, 'filename.ext');
// etc
});
list[0].request.upload.addEventListener(...);
- または、上記のコードにいくつかの変更を加えて、両方のアプローチを組み合わせることができます。
これを使用して、単純な角度関数を使用してファイルをアップロードし、$scope.progressBar変数を使用してアップロードの進行状況を確認できます...
$scope.functionName = function(files) {
var file = files[0];
$scope.upload = $upload.upload({
url: 'url',
method: 'POST',
withCredentials: true,
data: {type:'uploadzip'},
file: file, // or list of files ($files) for html5 only
}).progress(function(evt) {
console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
$scope.progressBar = parseInt(100.0 * evt.loaded / evt.total);
}).success(function(data, status, headers, config) {
console.log('upload succesfully...')
}).error(function(err) {
console.log(err.stack);
})
}