How to merge array into JSON array - javascript

I have a JSON file that I need to add Comments into and then update the file.
I've created an array for the new comments
//ADDING NEW COMMENTS
//add new comment within project
$scope.updatecomments = [];
$scope.addnewcomment = function() {
$scope.updatecomments.push({
"Author": "test",
"Text": $scope.NewComment
})
}
I can post the new comments into the JSON file but it overrides the past comments.
I have tried to merge the older comments with the new comments with the following
$scope.updatecomments = [];
$scope.addnewcomment = function() {
$scope.updatecomments.push({"Author": "test" ,"Text": $scope.NewComment}).concat($scope.Comments, $scope.updatecomments);
}
$scope.updatecomments = [].concat($scope.updatecomments,
$scope.projectDetails.Comments);
$scope.addnewcomment = function() {
$scope.updatecomments.push({
"Author": "test",
"Text": $scope.NewComment
});
}
I also tried making a new function that when called combines the two and then post the combined array
$scope.combine = [];
$scope.combineComments = function (){
var jsonStr = $scope.projectDetails.Comments;
var obj = JSON.parse(jsonStr);
obj['Comments'].push({"Author":"Test","Text":$scope.NewComment});
jsonStr = JSON.stringify(obj);
}
}
I have been going over this for the past few days now and can't seem to get it. Any help would be greatly appreciated!
EDIT
Sample Data of already existing data in JSON file
{
"Comments":[{
"Author": "John Doe",
"Text": "Work completed"
}]
}
Want to add to this (is from html input text tag) stored as NewComment
{
"Comments":[{
"Author": "Test",
"Text": "Project flagged"
}]
}
Edit 2
This is how I'm getting my projects data
/FIND PROJECTS - ADD TO LIST
$scope.projectList = [];
for (var id = 0; id < 30; id++) {
var targetURL = 'https://happybuildings.sim.vuw.ac.nz/api/sooleandr/project.'+id+'.json';
$http.get(targetURL).then(
function successCall(response){
$scope.projectList.push(response.data);
}
);
}
I then use this to access the selected information
//script
$scope.showData = function(x){
$scope.projectDetails = x;
};
//html
<ul class = 'pList'>
<li ng-repeat = 'x in projectList' class = 'pbList'>
<button class = 'pbutton' ng-click = 'showData(x)'>
<label ng-model ='pID'>Project ID: </label>{{x.ProjectID}} <br>
<label id ='pName'>Project Name: </label> {{x.Name}} <br>
<label id ='bID'>Building ID: </label>{{x.BuildingID}}<br>
<label id ='sDate'>Start Date: </label>{{x.StartDate}}
</button>
</li>
</ul>
Then I have the following variables to post
$scope.updateProject = function (projectDetails){
var updateproject = {
"ProjectID":$scope.projectDetails.ProjectID,
"Name":$scope.projectDetails.Name,
"BuildingID":$scope.projectDetails.BuildingID,
"StartDate":$scope.projectDetails.StartDate,
"EndDate":$scope.projectDetails.EndDate,
"Status":$scope.projectDetails.Status,
"ContactPerson":$scope.projectDetails.ContactPerson,
"Contractor":$scope.projectDetails.Contractor,
"ProjectManager":$scope.projectDetails.ProjectManager,
"Works": $scope.projectDetails.works,
"Comments":$scope.updatecomments,
};
$http.post("https://happybuildings.sim.vuw.ac.nz/api/sooleandr/update.project.json", updateproject).then(
function success(){
alert("Project Successfully Posted");
},
function error(){
alert("Error: Couldn't post to server");
}
)
};
It posts perfectly fine but it currently overrides the comments. I want to be able to add a new comment and still keep all the past comments. So I want to be able to push/add the comments into the full POST.JSON array.
Hope this makes a bit more sense

OK, updating answer after looking at provided code.
It appears you may be under the impression that $scope.projectDetails.Comments is a JSON string, when, in fact.. it's the actual Comments array.
I would try this for the addnewcomment function:
//ADDING NEW COMMENTS
//add new comment within project
$scope.updatecomments = undefined;
$scope.addnewcomment = function() {
$scope.updatecomments = $scope.updatecomments || $scope.projectDetails.Comments;
$scope.updatecomments.push({
"Author": "test",
"Text": $scope.NewComment
})
}
IF it just so happens to be a JSON string (highly unlikely), then I would update the combine function to this:
$scope.combineComments = function (){
var jsonStr = $scope.projectDetails.Comments;
var obj = JSON.parse(jsonStr);
obj.push({"Author":"Test","Text":$scope.NewComment});
jsonStr = JSON.stringify(obj);
}
}
EDIT
I'm adding another answer from my original because of the possibility things will break when there are no updated comments
//ADDING NEW COMMENTS
//add new comment within project
$scope.addnewcomment = function() {
$scope.projectDetails.Comments.push({
"Author": "test",
"Text": $scope.NewComment
})
}
Then in the POST, change to:
"Comments":$scope.projectDetails.Comments

I have figured out how to combine the two with
$scope.combinecomments = [];
$scope.combine = function (){
$scope.combinecomments.push($scope.projectDetails.Comments);
$scope.combinecomments.push($scope.updatecomments);
}
Except now it doesn't post the combined comments
$scope.ProjectID='$scope.ProjectID';
$scope.Name = '$scope.Name';
$scope.BuildingID = '$scope.BuildingID';
$scope.StartDate = '$scope.StartDate';
$scope.EndDate = '$scope.EndDate';
$scope.Status = '$scope.Status';
$scope.ContactPerson = '$scope.ContactPerson';
$scope.Contractor ='$scope.Contractor';
$scope.ProjectManager = '$scope.ProjectManager';
$scope.Works = '$scope.works';
$scope.Comments ='$scope.comments';
$scope.updateProject = function (projectDetails){
var updateproject = {
"ProjectID":$scope.projectDetails.ProjectID,
"Name":$scope.projectDetails.Name,
"BuildingID":$scope.projectDetails.BuildingID,
"StartDate":$scope.projectDetails.StartDate,
"EndDate":$scope.projectDetails.EndDate,
"Status":$scope.projectDetails.Status,
"ContactPerson":$scope.projectDetails.ContactPerson,
"Contractor":$scope.projectDetails.Contractor,
"ProjectManager":$scope.projectDetails.ProjectManager,
"Works": $scope.projectDetails.works,
"Comments":$scope.combinecomments,
};
$http.post("https://happybuildings.sim.vuw.ac.nz/api/sooleandr/update.project.json", updateproject).then(
function success(){
alert("Project Successfully Posted");
},
function error(){
alert("Error: Couldn't post to server");
}
)
};
It successfully posts the project except for the comments. It doesn't seem to like my combined array. When I post $scope.updatecomments it will post that but not the $scope.combinecomments.
I'll make a new question for this.

Related

How do I fix TypeError undefined in JavaScript? All fields exist for the object

In my piece of code below I receive a JSON object from a java Servlet and access the properties of that object.
JSON object:
{
"redirect": "/index.html",
"logout": "/_cloudshellProxy/_ah/logout?continue\u003d%2Findex.html",
"status": true,
"register": true,
"user": {
"email": "s#example.com",
"username": "Yevesky",
"college": {
"name": "Lafayette College",
"key": "aglzcHN0ZWFtMTlyFAsSB0NvbGxlZ2UYgICAgICAswgM"
},
"key": "aglzcHN0ZWFtMTlyEQsSBFVzZXIYgICAgICgxAgM"
}
}
Here is how I handle the object from the servlet.
fetch("/getUserInfo").then(response => response.json()).then(object =>
{
jsonObject = object;
console.log(jsonObject);
setUpUserPage(jsonObject);
loadClasses();
});
function setUpUserPage(json){
const jsonData = json;
var name = document.createElement("h3");
name.innerText = String(jsonData.username);
var uni = document.createElement("h6");
uni.innerText = String(jsonData.college.name); // Error occurs here
var classification = document.createElement("h6");
console.log(jsonData.classes);
if (jsonData?.isProf)
{
classification.innerText = "Professor";
}
else
{
classification.innerText = "Student";
}
var email = document.createElement("h6");
email.innerText = String(jsonData.email);
var spacer = document.createElement("BR");
//change nickname link
var changeNicknameP = document.createElement("p");
changeNicknameP.innerText = "Change your nickname: ";
var anchor = document.createElement("A");
var link = document.createTextNode("here");
anchor.setAttribute("href", "#");
anchor.appendChild(link);
changeNicknameP.appendChild(anchor);
var profileContainer = document.getElementById("profile-container");
profileContainer.appendChild(name);
profileContainer.appendChild(uni);
profileContainer.appendChild(classification);
profileContainer.appendChild(email);
profileContainer.appendChild(spacer);
profileContainer.appendChild(changeNicknameP);
}
The problem is I do not understand why I am getting a "TypeError: Cannot read property 'name' of undefined" if the object has such a property?
Is it just JavaScript or I am not following a procedure.
I do print the JSON object on console everytime to see if indeed the property exist.
This is because you probably made a mistake. "college" is a property of user, not your jsonData. Replace your line with this :
uni.innerText = String(jsonData.user.college.name);
Don't forget to check properties of your object if response can change (for example is user or college are optionnal properties in some case)
PS: sorry I can't post a comment because I dont have enough point on SO.

How to insert data in json after crawling through casperjs?

I wrote code that parsing a lot of words (innerHTML) from some webpages.
and I'd like to insert data to json file directly..
Here is my js code...
var words = [];
var casper = require('casper').create();
function getWords() {
var words = document.querySelectorAll('td.subject a');
return Array.prototype.map.call(words, function(e) {
return e.innerHTML;
});
}
casper.start('http://www.todayhumor.co.kr/board/list.php?table=bestofbest', function() {
words = this.evaluate(getWords);
});
for (var i=2; i <=5; i++) {
casper.thenOpen('http://www.todayhumor.co.kr/board/list.php?table=bestofbest&page='+i, function() {
words = words.concat(this.evaluate(getWords));
});
}
casper.run(function() {
// echo results in some pretty fashion
this.echo(words.length + ' links found:').exit();
this.echo(words.join('\n')).exit();
});
and
I run this code through terminal like this!
username#wow:~/workspace/app/assets/javascripts $ casperjs application.js
and the result is (for example)
150 words found:
apple
banana
melon
kiwi
citrus
watermelon
passionfruit
mango
orange
...
So I want to insert this data in "word" part of my json file (example code of json below)
and make other columns("type": "fruit" and "spell":) automatically added
{ "my_initial_words": [
{
"type": "fruit",
"word": "apple",
"spell": "ap"
},
{
"type": "fruit",
"word": "banana",
"spell": "ba"
},
{
"type": "fruit",
"word": "melon",
"spell": "me"
}
]
}
----------------------------------------------------------------------------
thanks for adding more answer!..
but I couldn't catch where should I put these code
Could you tell me once more that... Which code you gave me executes "Saving the results to JSON file?" because I have to read json file(makeyourap.json) in my seeds.rb file like this
require 'json'
file = File.open(Rails.root.join('db','makeyourap.json'))
contents = file.read
json = ActiveSupport::JSON.decode(contents)["my_initial_words"]
So, something like this?
function makeTypeObject(name, type) {
return {
name: name,
type: type,
spell: name.substr(0,2)
};
}
var wordDesc = words.map(function (word) {
return makeTypeObject(word, "fruit");
});
var finalObject = {
my_initial_words: wordDesc
};
var jsonString = JSON.stringify(finalObject);
// if you want prettyprint, try JSON.stringify(finalObject, null, "\t");
I hope this helps.
Write to file via casper
If you want to have a file from which you read and write, appending content, you can do it like this:
var fs = require('fs');
var FILENAME = 'makeyourap.json';
function add_new_fruits(fruits) {
var data;
if ( fs.isFile(FILENAME) ) {
data = fs.read(FILENAME);
} else {
data = JSON.stringify({'my_initial_words' : [] });
}
var json = JSON.parse(data);
fruits.forEach(function(word) {
json.my_initial_words.push({"type": "fruit",
"name": word,
"spell": word.slice(0,2)});
});
data = JSON.stringify(json, null, '\t');
fs.write(FILENAME, data, "w");
}
Use this instead of the older this.echo. Just call it as
casperjs application.js
This either reads the object from a file, or creates it if it does not exist. Then, it appends each new object from the new fruits (including duplicates), and writes it back to FILENAME.
Previous approach: how to roll your own
create Object
So first, you want to create an object that only has the parameter my_initial_words with values as above.
You can create a function via
function createFinal(wordArray) {
var out = [];
wordArray.forEach(function(word) {
out.push({"type": "fruit", "name": word, "spell": word.slice(0,2)});
});
return out;
}
to create the array. Then, create the object via
var my_object = { "my_initial_words": createFinal(words) };
to JSON
Javascript has a built-in JSON-object. With a javascript-object like
var my_object = { "my_initial_words": ...
as above, use
JSON.stringify(my_object)
to get the JSON representation to write.
Older: write to file via redirection
Before, you had
this.echo(words.join('\n')).exit();
which gave you the basic list. Using this.echo, try replacing this by
var my_object = { "my_initial_words": createFinal(words) };
this.echo(JSON.stringify(my_object)).exit();
This prints to standard output. Just remove the other this.echo line (150 words found) and redirect the output via
casperjs application.js > makeyourap.json
If you want to write to file in casperjs, look at write-results-into-a-file-using-casperjs.

Using openexchangerates API for currency conversion using JS/JQuery

I have managed to place JSON data into a form-control using JS which is this:
$("#getRates").ready(function () {
$.getJSON("http://openexchangerates.org/api/currencies.json?app_id="APP_ID", function (data) {
console.log(data);
for (var value in data) {
if (data.hasOwnProperty(value)) {
var text = document.createTextNode(value);
var select = document.getElementsByClassName('form-control')[1];
select.appendChild(document.createElement('option')).appendChild(text);
}
}
The current JSON file only contains the countries names but I wish to use the a different JSON file which is called Latest.JSON and contains the most recent rates, but it has these fields:
"license":
"timestamp": 1417258840,
"base": "USD",
"rates": {
"AED": 3.672743,
"AFN": 57.800375,
How can I just use the append the "rates" to the form-function and use the rates for the conversion?
As I have previously tried I just console.log and receive "License" "timestamp" "base" but no rates?
Not after specific answer maybe just some direction towards where to look?
$.getJSON("http://openexchangerates.org/api/latest.json?app_id=b65b6f0a06204a6087bab9a63a5845b7", function (data) {
console.log(data.rates);
for (var key in data.rates) {
if (data.rates.hasOwnProperty(key)) {
var text = document.createTextNode(key);
var select = document.getElementsByClassName('form-control')[1];
console.log(select);
select.appendChild(document.createElement('option')).appendChild(text);
}
}
for (var value in data.rates) {
if (data.rates.hasOwnProperty(value)) {
var text = document.createTextNode(value);
var select = document.getElementsByClassName('form-control')[2];
console.log(select);
select.appendChild(document.createElement('option')).appendChild(text);
}
}
});
});
I changed the var key to data.rates and this seems to of solved it.
This now populates both of my form-cotrols with the data.rates values from latest.json ..
The console.log() is just for my own usage..

Dynamically fill JSON array of objects using node

I am knew to JSON, this is the first time i have worked with it.
I have created a script using node to pull music(Artists and Song Titles) from a radio stations website as the radio station plays them. Currently i am putting them into a JSON file by appending them to the end of the file.
I would like to fill them into an array each time a new song is found instead. How do i go about doing this?
Here is my current code
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var schedule = require('node-schedule');
var rule = new schedule.RecurrenceRule();
//Timer to run every 3 minutes (average song time)
rule.minute = new schedule.Range(0, 59, 3);
var j = schedule.scheduleJob(rule, function(){
console.log('LOADING.......................');
//URL for site you want to get the Songs from
url = '#';
request(url, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
var artist, stitle;
var songs = {artist : "", stitle : ""};
//ID for artist
$('#').each(function(){
var data = $(this);
artist = data.text();
songs.artist = artist;
})
//ID for song title
$('#').each(function(){
var data = $(this);
stitle = data.text();
songs.stitle = stitle;
})
}
//Reading current list of songs
var content;
content = fs.readFileSync('output.json', "utf8");
//Searching current list for song it wants to add
var text = content;
var search = text.search(stitle);
//Only adding song if it cant find new song in list
if(search >= 0) {
console.log('Song already exists');
} else {
fs.appendFile('output.json', JSON.stringify(songs, null, 4) + ",\n", function (err) {
console.log('Song successfully added!');
});
}
})
});
Currently my JSON output looks like:
{
"artist": "FOO FIGHTERS",
"stitle": "BEST OF YOU"
},
{
"artist": "GAY NINETIES",
"stitle": "LETTERMAN"
},
{
"artist": "VANCE JOY",
"stitle": "RIPTIDE"
},
{
"artist": "NIRVANA",
"stitle": "IN BLOOM"
}
I would like to fill an array of songs like this:
{
songs : [
{
"artist": "FOO FIGHTERS",
"stitle": "BEST OF YOU"
},
{
"artist": "GAY NINETIES",
"stitle": "LETTERMAN"
},
{
"artist": "VANCE JOY",
"stitle": "RIPTIDE"
},
{
"artist": "NIRVANA",
"stitle": "IN BLOOM"
}
]
}
I know that i need to use something alongs the lines:
var songs = [];
for (var song in songs) {
songs.push({artist : "", stitle : ""});
}
But i don't know how to incorporate into my code, any help would be lovely, thanks guys
Okay, so if I understand your question correctly, you would like to load the JSON data; then append a song into the array; and then convert it back into JSON?
// load new song data first:
var newSong = {
artist: "FOO BAR FIGHTERS",
stitle: "IF THEN ELSE"
}
// then load data:
var jsonString = "[{:[,],:}]" // load JSON file here!
var data = JSON.parse(jsonString) // turn JSON string into an actual object
/*
at this point, you have access to data.song,
which is the array of all songs in the list.
*/
// now check if it's already in the list:
var alreadyInList = false
for(var i = 0; i < data.song.length; i ++)
{
if(data.song[i].stitle === newSong.stitle) alreadyInList = true
}
// if not, push it:
if(!alreadyInList) data.song.push(newSong)
// then stringify the object again for storage:
var backToString = JSON.stringify(data)
console.log(data) // output back to file
Is this what you're looking for?

knockout push values array

when I click on button1 I get object with 50 contacts array (containing collection of arrays with phoneNumbers, Addresses...), then when I click on button 2 I get the same object but my first object is erased whereas I would like to display 50 + 50 = 100 contacts array. I tried concat method but I have some difficulties to implement.
viewModel.initializeListener = function() {
$('#button1').click(function() {
document.getElementById("button2").style.visibility = "hidden";
$('#retrievedContactsDiv').html('');
nbDisplayedContacts = 0;
console.info("test");
viewModel.ui.FlashbackReport.MoreContacts();
});
$('#button2').click(function() {
viewModel.ui.FlashbackReport.MoreContacts();
console.info("test");
});
}; `
viewModel.WeHaveMoreContacts = function(data) {
console.info("test:", data)
if (viewModel.MoreContacts) {
var newArray=ko.mapping.fromJS(data, viewModel.MoreContacts);
var concatenated = newArray.concat(dataArray);
viewModel.MoreContacts.contacts(concatenated);
} else {
viewModel.MoreContacts = ko.mapping.fromJS(data);
var dataArray = viewModel.MoreContacts.contacts();
}
I have a parameter with number of contacts to skip for the server.
function which call the server then call the mapping function :
viewModel.ui.FlashbackReport.MoreContacts()
Problem : Object # has no method 'concat'
I made a fiddle that may help you.
The first part of the function generates new contacts and the second one add them to the existing contacts.
var VM = function () {
var self = this;
self.contacts = ko.observableArray();
self.addMore = function () {
// simulate server response
var offset = self.contacts().length;
var dataFromServer = [];
for (var index = 0; index < 10; index++) {
dataFromServer.push({
name: 'contact ' + offset + index
});
}
// add each new item to existing items.
ko.utils.arrayForEach(dataFromServer, function (item) {
self.contacts.push(item);
});
};
}
Feel free to ask more explanation.
I hope it helps.

Categories