user2656127
user2656127

Reputation: 665

parsing CSV in Javascript and AngularJS

So I'm trying to create a basic angular application that parses some CSV input, and fills a table with the parsed data.

You can see a plunker of what I'm trying to achieve here - http://plnkr.co/edit/6QFT4AcV4KpiSG23EdOS

Basically - as you can see - I have a <textarea> where the user will paste in some CSV, and the table below should then be filled with the data.

<div class="excelArea">
    <textarea name="excelData" ng-model="excelData"></textarea>
</div>

This is the javascript I have so far, but I'm struggling with a few things 1. Seperating the email from the name 2. Pushing the data back into the $scope.inviteList;

app.controller("InviteController", function($scope) {

    //Initliase objects
    $scope.excelData = "";
    $scope.errorMessage = "";
    $scope.inviteList = [];

    $scope.$watch("excelData", function() {

        var lines, lineNumber, data, length;

        lines = $scope.excelData.match(/[^\r\n]+/g);
        lineNumber = 0;

        for (var i = lines.length - 1; i >= 0; i--) {

            l = lines[i];
            lineNumber++;
            data = l.split(/\t/);

            var email = ? ? ?
            var name = ? ? ?

            $scope.inviteList.push({
                name: name,
                email: email,
                status: "not sent"
            });

        };

    });

});

Some basic information:

The CSV will be two columns (name, email) and will look like this:

John Thompson,[email protected]
Robin Peters, [email protected]
Bill Bob, [email protected]

Upvotes: 2

Views: 17079

Answers (3)

Florian F.
Florian F.

Reputation: 4700

Many problems in your code :

  • You could juste use split on your input instead of regexes, it makes everything easier
  • Your HTML isn't valid td should be inside tr and not the other way around
  • Your array was never cleared
  • Your bindings inside ng-repeat didn't use variable i defined here : i in inviteList
  • You should avoid unscoped variables (without var keyword) whenever possible

Otherwise, when you split a string, just access the splitted elements through their index.

Corrected code :

JS

$scope.$watch("excelData", function() {
    var lines, lineNumber, data, length;
    $scope.inviteList = [];
    lines = $scope.excelData.split('\n');
    lineNumber = 0;
    for (var i = lines.length - 1; i >= 0; i--) {
        l = lines[i];

        lineNumber++;
        data = l.split(',');

        var name = data[0];
        var email = data[1];

        $scope.inviteList.push({
            name: name,
            email: email,
            status: "not sent"
        });
    }
});

HTML

  <table>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th>Status</th>
    </tr>
    <tr ng-repeat="i in inviteList">
      <td>{{i.name}}</td>
      <td>{{i.email}}</td>
      <td>{{i.status}}</td>
    </tr>
  </table>

Your code (especially JS) can still be improved a lot and i encourage you to read docs/tutorials more.

And here is the plunker to your working code.

Upvotes: 3

HaukurHaf
HaukurHaf

Reputation: 13806

When you split a string, the return value is an array. I believe that you only have to access the correct indexes of the data array:

app.controller("InviteController", function($scope) {

    //Initliase objects
    $scope.excelData = "";
    $scope.errorMessage = "";
    $scope.inviteList = [];

    $scope.$watch("excelData", function() {

        var lines, lineNumber, data, length;

        lines = $scope.excelData.match(/[^\r\n]+/g);
        lineNumber = 0;

        for (var i = lines.length - 1; i >= 0; i--) {

            l = lines[i];
            lineNumber++;
            data = l.split(/\t/);

            var email = data[1];
            var name = data[0];

            $scope.inviteList.push({
                name: name,
                email: email,
                status: "not sent"
            });

        };

    });

});

Upvotes: 1

guru
guru

Reputation: 4022

I would create a filter to parse the data and reuse it anywhere I want it to. Logic:

app.controller('MainCtrl', function($scope, $filter) {
  $scope.data = 'John Thompson,[email protected]\nRobin Peters, [email protected]\nBill Bob, [email protected]';

  $scope.$watch('data', function(val){
    $scope.inviteList = $filter('csvToObj')(val);
  });
});

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({
        name: o[0],
        email: o[1],
        status: "not sent"
      });
    });
    return obj;
  };
});

Sample Demo:http://plnkr.co/edit/SOtMMLft3amlVm4RROd0?p=preview

Upvotes: 1

Related Questions