parsing CSV in Javascript and AngularJS - javascript

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,john#thompson.com
Robin Peters, robin#peters.com
Bill Bob, bill#bob.com

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.

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,john#thompson.com\nRobin Peters, robin#peters.com\nBill Bob, bill#bob.com';
$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

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"
});
};
});
});

Related

Build JavaScript Options Array From Multiple Returned Values

I am trying to build a baseline JS file to include in my some of my pages to return information from my SharePoint site. I would like to make three ajax calls to the server for the following: siteGroups, siteRoles and currentUser information and build an options array that I can use later by accessing it using dot notation. (e.g. options.siteGroup, options.siteRoles, options.currentUser.UserName, etc)
var options = (function(){
var currentUser = (function(){
var userInfo = [];
function complete(data){
for(i = 0; i < data.d.Groups.results.length; i++){
var user = {groupId : data.d.results[i].groupId, groupName :
data.d.results[i].groupName, UserName : data.d.UserName, UserId :
data.d.UserId};
UserInfo.push(user);
}
};
getCurrentUser(url, query, complete);
return userInfo;
})();
// Get All Site Permission Groups
var siteGroups = (function(){
function complete(data){
var siteGroups = [];
for(j = 0; j < data.d.results.length; j++){
var group = {groupName : data.d.results[j].Title, groupId :
data.d.results[j].Id};
siteGroups.push(group);
};
$('.SiteGroups').append(option);
};
getSiteGroups(url, complete);
return siteGroups;
})();
// Get All Role Definitions to be used for role assignment
var siteRoles = (function(){
var roles = [];
function complete(data){
var option;
for(s = 0; s < data.d.results.length; s++){
var role = {roleId : data.d.results[s].Id, roleName :
data.d.results[s].Name};
roles.push(role);
}
}
getRoleDefinitions(url, complete);
return roles;
})();
return {currentUser, siteRoles, siteGroups};
})();
When I console.log(options); I get an array with the correct values, however every combination (options.currentUser, options.currentUser.userName, etc) has yielded either userName is undefined or currentUser[0] cannot find value at position 0. Appreciate the help in advance!
http://imgur.com/Ubtb5nD "Image of console.log"

repopulating table with "filtered" data

See the code below.
I have a table populated with JSON data. The following is intended to clear the table and retrieve only the data with the last name criteria specified by the user.
So far, I'm successful in creating the filter criteria and wiping the table clean. However, I'm having trouble repopulating the table with the filtered results.
Possible hang-ups:
-the Regex: I'm new to RegExp with JS and I'm thinking the syntax is correct, but I'm not entirely sure. I'm also not sure if I'm able to use it the way I am (setting it: filterCriteria = new RegExp("^" + filter.value) and then calling on it to check if last_name object is equal to it: if (contacts.last_name === filterCriteria)
or even if the Regex is working properly, am I able to create a new array based on it the way I'm trying to in that If statement? I.e. is that enough to say, "Take only the objects with a last name that matches the criteria and throw them into a new array"?
Thanks for the help!
var filter = document.getElementById("filter");
filter.addEventListener("keydown", function (event) {
if (event.keyCode === 13) {
event.preventDefault();
if ((xhr.readyState === 4) && (xhr.status === 200)) {
var contacts = JSON.parse(xhr.responseText).data,
filterCriteria = new RegExp("^" + filter.value),
i;
for (i = 0; i < contacts.length; i += 1) {
var contactTableBody = document.getElementById("contactTable").lastElementChild,
lastRow = contactTableBody.lastElementChild;
contactTableBody.removeChild(lastRow);
}
if (contacts.last_name === filterCriteria) {
var filterResults = [contacts];
for (i = 0; i < contacts.length; i += 1) {
contactTableBody = document.getElementById("contactTable").lastElementChild;
var newRow = [],
newNameCell = document.createElement("td"),
newPhoneCell = document.createElement("td"),
newEmailCell = document.createElement("td"),
newNameNode = document.createTextNode(contacts[i].last_name + ", " + contacts[i].first_name),
newPhoneNode = document.createTextNode(contacts[i].phone),
newEmailNode = document.createTextNode(contacts[i].email);
newRow[i] = document.createElement("tr");
newRow[i].id = "contact" + i;
newNameCell.appendChild(newNameNode);
newPhoneCell.appendChild(newPhoneNode);
newEmailCell.appendChild(newEmailNode);
newRow[i].appendChild(newNameCell);
newRow[i].appendChild(newPhoneCell);
newRow[i].appendChild(newEmailCell);
contactTableBody.appendChild(newRow[i]);
}
}
}
EDIT:
not 100% on the brace/bracket notation but that should give an idea on how the data is oriented
contacts = JSON.parse(XMLHttpResponse.responseText).data = { [
{ "first_name":"Jim", "last_name":"Cooper", "phone":"8435555555", "email":"jim#halpert.com" },
{ "first_name":"Jim", "last_name":"Aaron", "phone":"1234567890", "email":"jim#beam.com" },
{ "first_name":"Mark", "last_name":"Smith", "phone":"4567891236", "email":"mark#smith.com" },
{ "first_name":"Sally", "last_name":"Smith", "phone":"5469876622", "email":"sally#smith.com" },
{ "first_name":"Mary", "last_name":"Coppersmith", "phone":"6854895212", "email":"mary#coppersmith.com" }
] }
from Santosh initial comment:
I do not know the context, but shouldnt the contacts.last_name be
inside the for loop? Something like this contacts[i].last_name == filterCriteria. If you can the mock up data for contact or a jsfiddle,
it would help.
It was in fact a for loop that was needed. Thanks.

returning nested json values using loop (google spreadsheet)

I have this google spreadsheet script that pulls in json formatted book data. I have no problem displaying book title and author, but he "offerData" object can contain a different amount of elements (prices from sellers) depending on the book. Right now I created a loop and am storing the offerData values like so:
price[i] = offerdata.offers[i]["price"];
condition[i] = offerdata.offers[i]["condition"];
seller[i] = offerdata.offers[i]["seller"]["displayName"];
and am returning the data like this:
var resultRow = [[title, specstag, price[0], condition[0], seller[0], price[1], condition[1], seller[1], price[2], condition[2], seller[2]]];
Obviously this only returns 3 sellers with price, condition, seller info. The issue is that a book doesn't always have 3 sellers, it can be anywhere from 1 to 10 or so.
My question is how can I return all offerData (price/condition/seller) here? :
var resultRow = [[title, specstag, price[0], condition[0], seller[0], price[1], condition[1], seller[1], price[2], condition[2], seller[2]]];
--
function getBookDetails(isbn) {
// Query the book database by ISBN code.
if (isbn !== "") {
var url = "https://api.bol.com/catalog/v4/search/?apikey=myapi6&offers=all&format=json&q=" + isbn;
var response = UrlFetchApp.fetch(url);
var results = JSON.parse(response);
if (results.totalResultSize) {
// There'll be only 1 book per ISBN
var book = results.products[0];
// get Title and Authors
var title = (results.products[0]["title"]);
var specstag = (results.products[0]["specsTag"]);
var offerdata = results.products[0]["offerData"];
if (typeof offerdata.offers !== 'undefined' && offerdata.offers.length > 0) {
var arrayLength = offerdata.offers.length;
var price = [];
var condition = [];
var seller = [];
for (var i = 0; i < arrayLength; i++) {
price[i] = offerdata.offers[i]["price"];
condition[i] = offerdata.offers[i]["condition"];
seller[i] = offerdata.offers[i]["seller"]["displayName"];
}
}
}
var resultRow = [[title, specstag, price[0], condition[0], seller[0], price[1], condition[1], seller[1], price[2], condition[2], seller[2]]];
return resultRow;
}
}
the answer
var resultRow = [];
resultRow[0] = [];
resultRow[0][0]=title;
resultRow[0][1]=specstag;
for (var i = 0; i < arrayLength; i=1+3) {
resultRow[0][3*i+2]=price[i];
resultRow[0][3*i+3]=condition[i];
resultRow[0][3*i+4]=seller[i];
}
how you should think about it is to see the index of the elements in the array and then find relation between i and the index you want
var resultRow = [
[
title, //[0][0]
specstag, //[0][1]
price[0], //[0][2]
condition[0], //[0][3]
seller[0], //[0][4]
price[1], //[0][5]
condition[1], //[0][6]
seller[1], //[0][7]
price[2], //[0][8]
condition[2], //[0][9]
seller[2]//[0][10]
]
];
You might be looking for something like this;
var data = { title: null,
spcstag: null,
pcs: [],
};
offerData.offers.forEach( p => { var pcsData = {};
!!data.title || data.title = p.title;
!!data.specstag || data.specstag = p.specstag;
pcsData.price = p.price;
pcsData.condition = p.condition;
pcsData.seller = p.seller;
data.pcs.push(pcsData);
});

Javascript module pattern with array

I have an exercise which i don´t really understand, so I hope for some help for this.
I should hardcode a simple array and the exercise tells me this:
Often, when we create our web applications, we have the need for test data. Implement a reusable nodejs module, using JavaScripts module pattern, which can provide random test data as sketched below:
var data = dataGenerator.getData(100,"fname, lname, street, city, zip");
This should return a JavaScript array (not JSON) with 100 test data on the form:
[{fname: "Bo", lname:"Hansen", street: "Lyngbyvej 26", city: "Lyngby", zip: "2800"},..]
If you call it like this:
var data = dataGenerator.getData(25,fname, lname);
it should return 25 test data as sketched below:
[{fname: "Bo", lname:"Hansen"},..]
I have some code here, but this dosen´t work yet:
var dataGenerator = (function () {
var data = [
{
fname : "Bo",
lname : "Bosen",
...
},
{
fname : "jashkjh",
lname : "jhsdkfj",
...
},
...
];
return {getData : function (count, fields) {
var result = [];
var i = 0;
var field;
var j;
fields = fields.split(/\s*,\s*/);
while (i < count && i < data.length) {
result.push({});
// Det objekt vi arbejder på lige nu er i result[i]
for (j = 0; j < fields.length; j++) {
result[i][fields[j]] = data[i][fields[j]];
}
i++;
}
return result;
}};
})();
module.exports = dataGenerator;
I do not know the data body, but could try:
var data=[{fname:"Bo",lname:"Bosen",street:"Lyngbyvej 26",city:"Lyngby",zip:"2800"},{fname:"jashkjh",lname:"jhsdkfj",street:"Fmsn 9",city:"Pra",zip:"1600"},{fname:"eeee",lname:"aaaa",street:"Eda 5",city:"Pre",zip:"3500"}];
var dataGenerator = {
getData: function(count, fieldsStr){
var result = [], fields = fieldsStr.split(/\s*,\s*/), i = 0;
while(i < count && data[i]){
var item = {};
fields.forEach(function(key){
item[key] = data[i][key]
});
result.push(item);
i++
}
return result
}
}
var results = dataGenerator.getData(2,"fname, zip");
document.write(JSON.stringify(results))

JSON.stringify comes back empty?

I'm trying to json serialize an array as follows:
function postToDrupal(contacts, source, owner) {
(function ($) {
var contact, name, email, entry;
var emails = [];
var post_object = {};
for (var i = 0; i < contacts.length; i++) {
contact = contacts[i];
emails[i] = {};
emails[i]['name'] = contact.fullName();
emails[i]['email'] = contact.selectedEmail();
console.log(contacts.length)
}
post_object['emails']=emails;
post_object['source']=source;
post_object['owner']=owner;
$.post("/cloudsponge-post",JSON.stringify(post_object),function(data) {
window.location.href = "/after-import";
});
}(jQuery));
}
The problem is, the post comes back empty. Without JSON.stringify() I get all the elements (but there are thousands of them, which can hit some servers limits, so they need to be serialized). Any help would be much appreciated.
The problem was this. When the request to the server is of type JSON, it's not strictly a POST, so PHP does not populate the $_POST field. In order to retrieve the data, it must be read directly from the request, in other words, instead of using $_POST, use:
$data=file_get_contents("php://input");
You don't need to call JSON.stringify, $.post accepts an object, check $.post.
Code to post just a few emails at a time :
function postToDrupal(contacts, source, owner) {
var pending = 0, limit = 10;
var post_patch = function(emails) {
var post_object = {};
post_object['emails']=emails;
post_object['source']=source;
post_object['owner']=owner;
pending++;
$.post("/cloudsponge-post", post_object,function(data) {
if(pending-- == 0) {
window.location.href = "/after-import";
}
});
}
(function ($) {
var contact, emails = [];
for (var i = 0; i < contacts.length; i++) {
contact = contacts[i];
emails[i] = {};
emails[i]['name'] = contact.fullName();
emails[i]['email'] = contact.selectedEmail();
console.log(contacts.length)
if(limit-- == 0) {
limit = 10
post_patch(emails);
contact = null; emails = {};
}
}
}(jQuery));
}

Categories