2

I'm trying to read a file, create a "FileContainer", and a DataUrl from a fileReader so i can send it to a web api.

My problem is that the Api call fires before my object is created, so i send Null to the api. which means that if i send a small file, it works.

My code for the reader look something like this

var reader = new FileReader();
reader.onload = (function (theFile) {
    return function (e) {
        var newFile = {
            name: theFile.name,
            type: theFile.type,
            size: theFile.size,
            lastModifiedDate: theFile.lastModifiedDate
        }
        var binaryString = e.target.result;
        updloadedFile(newFile, binaryString, selectedFolder, scope, fileProgrss);
        }
    };
})(f);
reader.readAsDataURL(f)

And for my http.post call

function updloadedFile(file, data, selectedFolder, scope, fileProgrss) {

    var dummyobj = {
        Name: file.name,
        Extension: file.name.split('.')[0],
        Path: selectedFolder.Path,
        DataString: data,
    }

    $http.post('/api/Files/Upload/',
      JSON.stringify(dummyobj),
      {
          headers: {
              'Content-Type': 'application/json'
          }
      }
  ).success(function (data2) {

  }).error(function (data, status, headers, config) {
  });
}
yeouuu
  • 1,863
  • 3
  • 15
  • 32
DaCh
  • 921
  • 1
  • 14
  • 48
  • 1
    just to clarify, your `updloadedFile` gets called before your `reader.onload` is called if the file is big? – mido Jan 04 '16 at 09:12
  • no, i think that the reader.onload is called first, curse i only call the updloadedFile inside it. But the binaryString only got it's value after the updloadedFile is called. so i somehow need to be sure the binaryString And newFile is done being created, before the updloadedFile is called. – DaCh Jan 04 '16 at 09:19

3 Answers3

2

You need to wrap your FileReader in a promise

function fileReader(file) { // perform async operation
    var deferred = $q.defer();

    var reader = new FileReader();
    reader.onload = function() {
      // Your reader.onload code here
      deferred.resolve(reader.result);
    };        

    reader.readAsDataURL(f);   
    return deferred.promise;
};

You can then call the uploadedFile() function like this:

fileReader().then(function(result){
  updloadedFile(..., ..., ..., ...)
});

By using the promise object, you can access the result of of the async task when it completes by using then. then runs as soon the result is available.

If you want to read more about promises, this SO thread does a great job explaining it.

Community
  • 1
  • 1
sjokkogutten
  • 2,005
  • 2
  • 21
  • 24
  • Cool. just tried, i gives me a error `Uncaught ReferenceError: $q is not defined` – DaCh Jan 04 '16 at 09:45
  • You need to inject $q into the scope you are working with – sjokkogutten Jan 04 '16 at 09:48
  • app.controller("MyController",function($q){ //$q is available here }) – sjokkogutten Jan 04 '16 at 09:49
  • Can i return more then one parms? i need to get the new File and binaryString from my previous method. now i only get the binaryString curse of the reader.result – DaCh Jan 04 '16 at 10:00
  • I sure this is the right way, curse now i get the dataUrl when is done. But as i said in the comment above. i need to get the newFile propertiesas well, an this i can't get to work – DaCh Jan 04 '16 at 10:05
  • I think that you would probably have to create a new function which returns a promise. You would then have multiple functions returning promises, and you could then chain them using multiple `then` – sjokkogutten Jan 04 '16 at 10:10
  • http://stackoverflow.com/questions/24357445/chain-promises-with-angularjs. Check both comments and you will get the general idea – sjokkogutten Jan 04 '16 at 10:12
  • will do, but i actually think my problem right now is that i can't get the file properties from the reader.onload like i did before. got any ideas to how i can get those values? – DaCh Jan 04 '16 at 10:15
  • Hm. Could you have a look at this: http://stackoverflow.com/questions/26165919/filereader-not-loading-file-properly-using-angularjs – sjokkogutten Jan 04 '16 at 10:22
  • Yes, this help me, now i just need to combine the second then with this. and it should work. – DaCh Jan 04 '16 at 10:30
0

I am guessing that the issue here is, you are listening to onload, apparantly it gets called on each read operation, thus might be null in beginning( reference), try changing it to onloadend.

mido
  • 24,198
  • 15
  • 92
  • 117
0

I don't really see the need for wrapping the FileReader API call within a promise. You could do that but according to the docs (https://developer.mozilla.org/en-US/docs/Web/API/FileReader) FileReader.onload gets called when the data is ready. Doing a additional deffered.resolved to be able to use then is just a nice to have.

I have created a fiddle. Even with big files the http call is made only if the data is available. I don't really see an error in your code. May you can try it out with the fiddle.

http://jsfiddle.net/tjruzpmb/212/

ChrisY
  • 1,681
  • 10
  • 12
  • That may be true. but after adjusting to the posted solutions, my code work. – DaCh Jan 04 '16 at 10:53
  • Would be awesome to know the real problem.. :( – ChrisY Jan 04 '16 at 10:56
  • Well. i did make the post call before it had the data ready. an that was my problem. Why it did that, i can't tell. but the "nice to have" secured that the reader was done before posting. that all i can tell you – DaCh Jan 04 '16 at 10:59