I am writing an UploadService. The upload so far works fine. But I'd like to update the scope of the controller with the xhr callbacks, in order to display relevant information and UI.
How would I do that? I think the factory service is not the right place to clutter with controller specific stuff.
adminServices.factory('UploadService', [function() {
return {
beginUpload: function(files, options) {
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", this.onUploadProgress, false);
xhr.addEventListener("load", this.onUploadComplete, false);
xhr.addEventListener("error", this.onUploadFailed, false);
xhr.addEventListener("abort", this.onUploadCanceled, false);
},
onUploadProgress: function(progress) {
console.log("upload progress"); //HERE I CAN'T UPDATE the CONTROLLER's SCOPE
},
onUploadComplete: function(result) {
console.log("upload complete"); //NOR HERE
},
app.directive('fileUpload', function() {
return {
restrict: 'E',
scope: {},
template: '', //omitted for brevity
controller: function($scope, UploadService) {
$scope.upload = function() {
UploadService.beginUpload($scope.files, options);
};
//HERE I'D LIKE TO HAVE NOTIFICATIONS OF THE onXYZ methods...
Try doing the following in the factory:
adminServices.factory('UploadService', [function() {
//Create a UploadService Class
function UploadService (scope) { //Constructor. Receive scope.
//Set Class public properties
this.scope = scope;
this.xhr = new XMLHttpRequest();
//Write any initialisation code here. But reserve event handlers for the class user.
}
//Write the beginUpload function
UploadService.prototype.beginUpload = function (files, options) {
//Upload code goes here. Use this.xhr
}
//Write the onUploadProgress event handler function
UploadService.prototype.onUploadProgress = function (callback) {
var self = this;
this.xhr.upload.addEventListener("progress", function (event) {
//Here you got the event object.
self.scope.$apply(function(){
callback(event);//Execute callback passing through the event object.
//Since we want to update the controller, this must happen inside a scope.$apply function
});
}, false);
}
//Write other event handlers in the same way
//...
return UploadService;
}]);
And now, you can use the UploadService
factory inside the directive controller as follows:
app.directive('fileUpload', function() {
return {
restrict: 'E',
scope: {},
template: '', //omitted for brevity
controller: function($scope, UploadService) {
//Create an UploadService object sending the current scope through the constructor.
var uploadService = new UploadService($scope);
//Add a progress event handler
uploadService.onUploadProgress(function(event){
//Update scope here.
if (event.lengthComputable) {
$scope.uploadProgress = event.loaded / event.total;
}
});
$scope.upload = function() {
uploadService.beginUpload($scope.files, options);
};
Hope it helps. Cheers :)