All we need is an easy explanation of the problem, so here it is.
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]
How to solve :
I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.
Method 1
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 insidetr
and not the other way around - Your array was never cleared
- Your bindings inside
ng-repeat
didn’t use variablei
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.
Method 2
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
Method 3
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"
});
};
});
});
Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0