Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing a CSV file provided by an input in Angular

I'm creating a webapp which features uploads of .csv file.

Instead of uploading the whole file on my server, then adding every lines in a table thanks to PHP, I'd like to parse the file in Angular, then add parsed lines (thanks to Restangular). This way, I should be able to retrieve some "errors" before uploading them (or not).

In a view, I've created a simple file input, with a directive called file (source : http://angularjstutorial.blogspot.fr/2012/12/angularjs-with-input-file-directive.html)

<input type="file" data-file="param.file" />

The filedirective :

app.directive('file', function(){
  return {
    scope: {
      file: '='
    },
    link: function(scope, el, attrs){
      el.bind('change', function(event){
        var files = event.target.files;
        var file = files[0];
        scope.file = file ? file.name : undefined;
        scope.$apply();
      });
    }
  };
});

This way, I can retrieve when the user chooses a file. Unfortunately, I'm getting only the file name.

I'd like to parse the csv in a string, which i'll split thanks to this filter (source : parsing CSV in Javascript and AngularJS) :

app.filter('csvToObj',function(){
  return function(input){
    var rows=input.split('\n');
    var obj=[];
    angular.forEach(rows,function(val){
      var o=val.split(';');
      obj.push({
        designation:o[1],
        ...
        km:o[11]
      });
    });
    return obj;
  };
});

How can I retrieve the data in the csv file provided by the input instead of the file name ?

Thanks in advance.

like image 296
aknorw Avatar asked Jan 21 '15 15:01

aknorw


1 Answers

Ok, I found the solution by searching on existing modules to upload files. I just post it here if this interests someone.

In the view, I've changed the directive to trigger the event :

<input type="file" file-change="handler($event,files)" ng-model="MyFiles" />

The directive is now :

app.directive('fileChange',['$parse', function($parse){
  return{
    require:'ngModel',
    restrict:'A',
    link:function($scope,element,attrs,ngModel){
      var attrHandler=$parse(attrs['fileChange']);
      var handler=function(e){
        $scope.$apply(function(){
          attrHandler($scope,{$event:e,files:e.target.files});
        });
      };
      element[0].addEventListener('change',handler,false);
    }
  }
}]);

In the controller (don't forget to add $filter in the controller if you want to use it) :

$scope.MyFiles=[];

$scope.handler=function(e,files){
    var reader=new FileReader();
    reader.onload=function(e){
        var string=reader.result;
        var obj=$filter('csvToObj')(string);
        //do what you want with obj !
    }
    reader.readAsText(files[0]);
}

The filter is still the same (except I've shifted the rows array to not import the header of my csv files).

like image 108
aknorw Avatar answered Oct 09 '22 01:10

aknorw