0

I'm creating an architecture for a SPL (software production line) and I need to make things as easy as possible for the purpose of industrial productivity. The architecture is RESTful, Web API at the server side, Angular 2 & Material 2 at the client side in a nutshell.

I just have this question

Since I write the front-end and back-end, is it possible that in my forms which have file-upload control, I just get binary data from that file and send it to the server in JSON alongside other properties?

In other words, instead of multipart/form-data, I want to send something like this:

{  
   "title":"we in the garden",
   "tags":[  
      "family",
      "holidy"
   ],
   "file":" is it possible to include file's binary data here? "
}

If yes, what do I miss, If no, why not?

georgeawg
  • 48,608
  • 13
  • 72
  • 95
Ali Fallah
  • 753
  • 1
  • 7
  • 17

1 Answers1

1

Possible but not recommended

One can use the FileReader.readAsDataURL() API to bring the file into memory as a base64 encoded string.

  vm.previewFile = function() {
    readBase64(vm.files[0]).then(function(data) {
      vm.data = data;
    })
  }  

  function readBase64(file) {
    var reader  = new FileReader();
    var future = $q.defer();

    reader.addEventListener("load", function () {
      future.resolve(reader.result);
    }, false);

    reader.addEventListener("error", function (event) {
      future.reject(event);
    }, false);

    reader.readAsDataURL(file);

    return future.promise;
  }

The Demo on PLNKR.

However, base64 encoding is inefficient. Converting a binary file to a base64 encoded DOMstring (UTF-16) will take 266% more memory. The browser will likely crash with large video files.

It is more efficient to POST a file directly:

//RECOMMENDED
//Send binary file directly
var config = { headers: { "Content-Type": undefined },
               params: { filename: vm.files[0].name,
                         size: vm.files[0].size,
                         type: vm.files[0].type
                       } 
             );
$http.post(url, vm.files[0], config);

The $http service will use the XHR send method to stream the browser File object to the server.

<input type="file" files-input 
       ng-model="files" ng-change="previewFile()"
/>

The files-input directive:

app.directive("filesInput", function() {
  return {
    require: "ngModel",
    link: function postLink(scope,elem,attrs,ngModel) {
      elem.on("change", function() {
        ngModel.$setViewValue(elem[0].files);   
      });
    }
  };      
});
georgeawg
  • 48,608
  • 13
  • 72
  • 95