7

I'm trying to load a csv file into AngularJS so I can do some manipulation on the contents. It is not quite working as I want it to. To test if it is loading properly, I am loading it into a textarea to view the contents.

When I load the file, it says it is loaded properly but the onload() event doesn't seem to be firing until I load a second CSV file, in which case the FIRST file is displayed in the textarea.

HTML:

<div>
  <input ng-model="csv"
            onchange="angular.element(this).scope().fileChanged()"
            type="file" accept=".csv" id="fileInput"/>
</div>
<br/>
<div>
  <textarea ng-model="csvFile" readonly="true" style="width:99%; height:500px" disabled></textarea>
</div>

JS:

$scope.fileChanged = function() {

  $scope.$apply(function() {
      var csvFileInput = document.getElementById('fileInput');
      var reader = new FileReader();
      var csvFile = csvFileInput.files[0];
      reader.onload = function(e) {
          $scope.csvFile = reader.result;
      };
      reader.readAsText(csvFile);
  });
};

And when I put this into JSFiddle, the file doesn't appear in the textarea at all. I'm new with JSFiddle so I don't know why that is happening.

Any help at all would be appreciated.

UpAllNight
  • 1,312
  • 3
  • 18
  • 30
  • you need to use $parse I think – aarosil Oct 02 '14 at 17:43
  • @aarosil What do you mean? Where? – UpAllNight Oct 02 '14 at 18:11
  • 1
    Can you try the following: swap lines `$scope.$apply(function()` and `reader.onload = function(e) {` and now move `var reader = new FileReader();` before `reader.onload` and `reader.readAsText(csvFile);` after `reader.onload` block – przno Oct 02 '14 at 18:49
  • @przno Yes! That worked. If you want to write that into an answer I will upvote and accept it. Also if you could maybe give a short explanation of why that works I would really appreciate it. :) – UpAllNight Oct 02 '14 at 19:01
  • Side note #1: `onchange="angular.element(this).scope().fileChanged()"` is not proper *Angular* way, you should use [ng-change](https://docs.angularjs.org/api/ng/directive/ngChange), like `ng-change="fileChanged()"` – przno Oct 02 '14 at 19:24
  • Side note #2: `accept=".csv"` ... the `accept` unfortunately behaves differently in different browser, so test that if its what you want – przno Oct 02 '14 at 19:26
  • I edited the code to use ng-change. Thanks for the tips! – UpAllNight Oct 02 '14 at 20:36

3 Answers3

18

Reordering some lines of your code, hope the comments are explanatory enough

$scope.fileChanged = function() {

  // define reader
  var reader = new FileReader();

  // A handler for the load event (just defining it, not executing it right now)
  reader.onload = function(e) {
      $scope.$apply(function() {
          $scope.csvFile = reader.result;
      });
  };

  // get <input> element and the selected file 
  var csvFileInput = document.getElementById('fileInput');    
  var csvFile = csvFileInput.files[0];

  // use reader to read the selected file
  // when read operation is successfully finished the load event is triggered
  // and handled by our reader.onload function
  reader.readAsText(csvFile);
};

Reference: FileReader at MDN

przno
  • 3,476
  • 4
  • 31
  • 45
2

This is just a minor improvement in HTML:

<input type="file" onchange="angular.element(this).scope().file_changed(this)"/>
<textarea cols="75" rows="15">{{ dataFile }}</textarea>

and controller:

.controller('MyCtrl', ['$scope', function($scope) {
    var vm = $scope;

    vm.file_changed = function(element){
        var dataFile = element.files[0];
        var reader = new FileReader();
        reader.onload = function(e){
            vm.$apply(function(){
                vm.dataFile = reader.result;
            });
        };
        reader.readAsText(dataFile);
    };
}]);

Ref

Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
  • If this is based on the accepted answer, you should add a link as attribution. There's no need to include "thanks" or similar; that's what upvotes are for, once you get some more rep. – Nathan Tuggy Apr 04 '15 at 04:52
  • how can I add a link if I do not get any rep yet? I want to add this http://plnkr.co/edit/v65J4T?p=preview – Jorge Cortes Apr 04 '15 at 16:29
  • Generally those with less than 10 rep can add up to two links per post, as I understand it. Anyway, there you go. Please edit again to make sure I've understood your meaning correctly. – Nathan Tuggy Apr 04 '15 at 19:39
  • ok got it, but the code that I put, are you going to delete it? – Jorge Cortes Apr 07 '15 at 02:54
  • Me? No. CC-BY-SA allows copying and modifying as long as you credit the author. – Nathan Tuggy Apr 07 '15 at 03:15
1

If you don't want to use $scope.$apply(), you can use $timeout:

const fileReader = new FileReader();
            
fileReader.onload = (event) => {
    this.$timeout(() => {
        // Logic goes here...
    }, 0);
};

...
KimchiMan
  • 4,836
  • 6
  • 35
  • 41