Pregunta

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...
¿Fue útil?

Solución

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 :)

Otros consejos

Try binding an object on the scope to a return value or object in your factory. For example:

controller: function($scope, UploadService) {
         $scope.upload = function() {             
             UploadService.beginUpload($scope.files, options);
             $scope.uploadProgress = UploadService.onUploadProgress();
         };

Then in the factory:

onUploadProgress: function(progress) {
      return "Some message";
    },

Then in the view/html:

<div>{{ uploadProgress }}</div>

Or try:

return {
    theProgress: "",
    beginUpload: function(files, options) {...},
    onUploadProgress: function(progress) {
      theProgress = "some value";
    }
}

then:

controller: function($scope, UploadService) {
         $scope.upload = function() {             
             UploadService.beginUpload($scope.files, options);
             $scope.uploadProgress = UploadService.theProgress;
         };
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top