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.

7
  • you need to use $parse I think Commented Oct 2, 2014 at 17:43
  • @aarosil What do you mean? Where? Commented Oct 2, 2014 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 Commented Oct 2, 2014 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. :) Commented Oct 2, 2014 at 19:01
  • Side note #1: onchange="angular.element(this).scope().fileChanged()" is not proper Angular way, you should use ng-change, like ng-change="fileChanged()" Commented Oct 2, 2014 at 19:24

3 Answers 3

19

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

Sign up to request clarification or add additional context in comments.

3 Comments

It now worked because of $scope.$apply(function() {$scope.csvFile = reader.result;});
just what i was looking for!
By far the simplest and nicest solution to this problem I've seen. :thumbsup
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

5 Comments

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.
how can I add a link if I do not get any rep yet? I want to add this plnkr.co/edit/v65J4T?p=preview
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.
ok got it, but the code that I put, are you going to delete it?
Me? No. CC-BY-SA allows copying and modifying as long as you credit the author.
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);
};

...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.