Import Json data in a JS variable simply - javascript

I made a js with data in a const array as below
const messages = [
{ date: '2020-1-1', content:'message1'},
]
In order to make my file cleaner I decide to put the data in a Json file and want to call the Data in my Js in order to use it like before.
my Json is like this
[
{
"date":"2020-1-1",
"content":"message1"
}
]
In order to import my Json I put this code:
let messages = [];
$.getJSON("messages.json", function(data) {
messages = data;
console.log(messages);
});
The result is that my array is loaded in the console but the variable dont work, I tried things with Object.keys but no more result. I dont use framework also and dont find a solution on other questions here. Any help will be appreciated. Thank you very much!

I dont use framework
You are using a library, though, $ === jQuery
in order to make my file cleaner I decide to put the data in a Json file
You can just define a constants.js file and load that before your other scripts.
For example,
constants.js
const messages = [
{ date: '2020-1-1', content:'message1'},
]
main.js
alert(messages);
index.html
<script src="constants.js"></script>
<script src="main.js"></script>

#Alvin Stefanus
Because x,z and messages were undefined and didnt let the code work, I also add
let messages,x,z = [];
And now it works perfectly with your solution.
I will use it as you told also for the other operations.
Thank you very much it helped for my problem and gave me a new technique.
EDIT:
I also tried to delete this part
var start = x;
$.getJSON('messages.json', function(data) {
messages = data;
}); <-- this
var end = z;
And it also works! That means that the problem was not the async function but because I didnt put the loop within the curly bracket of
$.getJSON('messages.json', function(data) {
//The data is finished being filled here
}

Ok this is probably the issue. $.getJSON() is an async function, the code will not wait until the closing curly bracket of the method:
var start = x;
$.getJSON('messages.json', function(data) {
messages = data;
}); <-- this
var end = z;
The code will run var end = z; before the $.getJSON() finished getting the result, because it is asynchronous function. In other word, when the code is currently at var end = z, $.getJSON() is still working to get the data, and has not been finished. That is why the messages = data is not being called yet.
So here is what you want to do:
$.getJSON('messages.json', function(data) {
messages = data;
for (const item of messages) {
if (item.date === todayDay) {
console.log(item.content);
var newPara = document.createElement("p");
var textNode = document.createTextNode(item.content);
newPara.appendChild(textNode);
var nodeParent = document.getElementById("titre");
var nodeChild = document.getElementById("child1");
nodeParent.appendChild(newPara, nodeChild);
}
}
});
Do all your needed operations within the curly bracket of
$.getJSON('messages.json', function(data) {
//The data is finished being filled here
}
This is a callback function. You can learn more about callback function here
Some Info
Yes the loop has to be inside the callback function to run after the data has been retrieved. To give you better understanding about the async function, you can also put your loop outside within a timeout function, but you will never want this, because you will not know how long the operation for retrieving the data will run.
For example:
$.getJSON('messages.json', function(data) {
messages = data;
});
setTimeout(function() {
for (const item of messages) {
if (item.date === todayDay) {
console.log(item.content);
var newPara = document.createElement("p");
var textNode = document.createTextNode(item.content);
newPara.appendChild(textNode);
var nodeParent = document.getElementById("titre");
var nodeChild = document.getElementById("child1");
nodeParent.appendChild(newPara, nodeChild);
}
}
}, 2000); //run after 2 seconds
Im sure the code above will also work, the process of getting the data should not be longer than 2 seconds.
Again this is not a correct way to do it, just to give you better understanding of async function.

Related

Nodejs Webscraping function using Cheerio returns before finished

I'm currently working on a simple web scraping nodejs program. It is based on cheerio and I get items from a website and extract some information from there.
As far as I understand it all functions I call inside the foreach loop are sync so they should execute from top to bottom. And because the foreach loop is also only a normal loop, which executes sync in js, the function should return my finished array. But instead it is getting undefined and when I log it inside directly to console it works(?).
function getIntensiv(){
var intensivregister = [];
request.post({url: 'SOMEURL', form: {SOMEFORM}}, function(err,res,body){
var $ = cheerio.load(body);
$('#dataList').children('tbody').children('tr').each(function(i, elem){
var name = $(elem).children('td').first().text().trim().split("\n")[0].trim();
var zipcity = $(elem).children('td').first().children('small').last().text();
var streetnr = $(elem).children('td').first().children('br').last().prev().text();
intensivregister.push({'name': name, 'zipcity': zipcity, 'streetnr': streetnr});
});
console.log(intensivregister); //works and prints the finished array
return intensivregister; //returns undefined before function finished
});
}
I would appreciate it if you could explain me where my mistake is and help me fix it.
function getIntensiv(){
const cheerio = require('cheerio')
const request = require('request')
var intensivregister = [];
request.get({url: 'https://www.w3schools.com/html/html_tables.asp'}, function(err,res,body){
var $ = cheerio.load(body);
$('#customers').children('tbody').children('tr').each(function(i, elem){
var name = $(elem).children('td').first().text().trim().split("\n")[0].trim();
var zipcity = $(elem).children('td').first().children('small').last().text();
var streetnr = $(elem).children('td').first().children('br').last().prev().text();
intensivregister.push({'name': name, 'zipcity': zipcity, 'streetnr': streetnr});
});
console.log(intensivregister); //works and prints the finished array
return null; //returns undefined before function finished
});
return null; //***<---This is returning and not the above return. If no return statement is written then undefined is passed.***
};
var retrunVal = getIntensiv()
console.log(retrunVal);
Please find the highlighted comment
Ok I figured out that my idea of javascript was not how you should use it. I worked around my problem with getting rid of the idea of returning values from functions (which comes mainly from my experiences from async programming) and instead using callback parameters which I give to my function and call at the end of my request.
function getIntensiv(callback){
var intensivregister = [];
request.post(...);
**callback(intensivregister);**
}
What also is working (and I think a better solution) is working with promises e.g. with request-promise and calling the callback in the finally call.

Not Populating list in HTML with Javascript

I am learning Javascript. I am working on reading RSS feeds for a personal project. I am using 'RSS-parser' npm library to avoid CORS error.
And also I am using Browserify bundler to make it work on the browser.
When I run this code on the terminal it gives me output without any issue. But when I try with the browser it prints nothing.
My knowledge about Asynchronous JS is limited but I am pretty sure it doesn't have errors in here as I added code to it without changing existing code.
let Parser = require('rss-parser');
let parser = new Parser();
let feed;
async () => {
feed = await parser.parseURL('https://www.reddit.com/.rss');
feedTheList();
};
// setTimeout(function() {
// //your code to be executed after 1 second
// feedTheList();
// }, 5000);
function feedTheList()
{
document.body.innerHTML = "<h1>Total Feeds: " + feed.items.length + "</h1>";
let u_list = document.getElementById("list")[0];
feed.items.forEach(item => {
var listItem = document.createElement("li");
//Add the item text
var newText = document.createTextNode(item.title);
listItem.appendChild(newText);
listItem.innerHTML =item.title;
//Add listItem to the listElement
u_list.appendChild(listItem);
});
}
Here is my HTML code.
<body>
<ul id="list"></ul>
<script src="bundle.js"></script>
</body>
Any guidance is much appreciated.
document.getElementById() returns a single element, not a collection, so you don't need to index it. So this:
let u_list = document.getElementById("list")[0];
sets u_list to `undefined, and you should be getting errors later in the code. It should just be:
let u_list = document.getElementById("list");
Also, when you do:
listItem.innerHTML =item.title;
it will replace the text node that you appended on the previous line with this HTML. Either append the text node or assign to innerHTML (or more correctly, innerText), you don't need to do both.
Looks like the async call is not being executed; You need to wrap it
in an anonymous function call:
See the example here:
https://www.npmjs.com/package/rss-parser
Essentially,
var feed; // change let to var, so feed can be used inside the function
// wrap the below into a function call
(async () => {
feed = await parser.parseURL('https://www.reddit.com/.rss');
feedTheList();
})(); // the (); at the end executes the promise
Now it will execute and feed should have items.
CORS errors when making request
As noted in the documentation at https://www.npmjs.com/package/rss-parser, if you get CORS error on a resource, use a CORS proxy. I've updated their example to fit your code:
// Note: some RSS feeds can't be loaded in the browser due to CORS security.
// To get around this, you can use a proxy.
const CORS_PROXY = "https://cors-anywhere.herokuapp.com/"
let parser = new RSSParser();
(async () => {
await parser.parseURL(CORS_PROXY + 'https://www.reddit.com/.rss', function(err, feed) {
feedTheList(feed);
});
})();
function feedTheList(feed)
{
// unchanged
}
One last thing:
The line
document.body.innerHTML = "<h1>Total Feeds: " + feed.items.length + "</h1>";
Will remove all of the content of <body>
I suggest to look into how element.appendChild works, or just place the <h1> tag in your HTML and modify its innerHTML property instead.

How to test node data chunking function

I'm working on a project which uses node and we're trying to achieve 100% coverage of our functions. This is the only function we haven't tested, and it's within another function.
var userInput = "";
req.on("data", function(data){
userInput += data;
});
How do you go about testing this function? We tried exporting the function from another file but no luck.
I should mention that we are using tape as a testing module.
You need to trigger this "data" event on req. So that this callback will be called.
For instance, let's suppose you have req on your test, you could do something like that (this is Mocha):
req.trigger('data', 'sampleData');
expect(userInput).to.equal('sampleData');
req.emit('data', {sampleData: 'wrongOrRightSampleDataHere'}) should do it.
When instantiating the http or hence the req object make sure you instantiate a new one, that no other test receives this event.
To be more complete...
var assert = require('assert')
function test() {
var hasBeenCalledAtLeastOnce = false
var userInput = "";
// req must be defined somewhere though
req.on("data", function(data){
userInput += data;
if(hasBeenCalledAtLeastOnce) {
assert.equal(userInput, "HelloWorld", "userInput is in fact 'HelloWorld'")
}
hasBeenCalledAtLeastOnce = true
});
req.emit('data', "Hello")
req.emit('data', "World")
}
test()

Problems making GET request from jQuery

I'm trying to make an HTTP GET request using the jQuery get() function, but I'm having some trouble.
Here's what my code looks like:
// get the links on the page
var pageLinks = $.find('#pageLinks');
// loop through each of the links
$(pageLinks).find('a').each(function(){
if($(this).attr('title') !== "Next Page"){
// make a GET request to the URL of this link
$.get($(this).attr("href"), function(data) {
console.log("here");
var temp = parse_page(data);
// concatenate the return string with another
bdy = bdy+String(temp);
console.log("done");
});
}
});
There are multiple pages that I need to get data from. Since the get() function is asynchronous, I get the pages in a random order. Secondly, the concatenation does not work. Even though I get each of the pages, they're not put into bdy.
Can anyone suggest how I might deal with this?
Thanks a lot!!
Construct bdy after all pages are retrieved, i.e. store get results in a dictionary or array; wait for all gets to finish; then assemble them in the correct order.
I tried this one and it works:
// get the links on the page
var pageLinks = $('a');
var bdy
// loop through each of the links
$(pageLinks).each(function(){
console.log(this);
// make a GET request to the URL of this link
$.get($(this).attr("href"), function(data) {
// concatenate the return string with another
bdy = bdy + data.toString();
console.log(bdy);
});
});
As an example of what #muratgu has said:
var results = [];
var count = 0;
function allDone() {
var bdy = results.join("");
// do stuff with bdy
}
// get the links on the page
var pageLinks = $.find('#pageLinks');
// filter the links so we're left with the links we want
var wantedLinks = $(pageLinks).find('a').filter(function (idx) {
return $(this).attr('title') !== "Next Page";
});
// remember how many links we're working on
count = wantedLinks.length;
// loop through each of the links
wantedLinks.each(function (idx) {
// make a GET request to the URL of this link
$.get($(this).attr("href"), function (data) {
console.log("here");
var temp = parse_page(data);
results[idx] = temp;
// Decrement the count.
count--;
if (count === 0) {
// All done.
allDone();
}
});
});
You could go further and abstract this into a data type that can perform N async downloads, and then notify you when all are complete.
I just found that there are modules that allow one to manage the control flow in JS. The ones I found are:
Async
Step
For help using the above modules, see my follow up question here.

Nested getJson() & PHP PDO

I have looked at other questions and answers regarding this, but can't seem to wrap my head around it...
I have a javascript function:
function getStates(theDiv){
var stateGroupData;
var stateData;
var theGHtml = "";
var theHtml = "<h4>MyPage</h4>";
theHtml = theHtml+"<h5>select a state...</h5>";
$.getJSON("getStateGroups.php", function(data) {
stateGroupData = data;
theHtml = theHtml+"<ul>";
$.each(stateGroupData, function(i,jsonData) {
theHtml = theHtml+"<li><a href='#"+jsonData.groupName+"'>"+jsonData.groupID+"</a></li><br/>";
var theSQL = "getStates.php?gid="+jsonData.groupName;
theGHtml = theGHtml+"<div id='"+jsonData.groupName+"'>";
$.getJSON(theSQL, function(data2) {
stateData = data2;
$.each(stateData, function(i,jsonData2) {
alert(jsonData2.stateName);
theGHtml = theGHtml+"<span sname='"+jsonData2.stateName+"' lat='"+jsonData2.centerLat+"' lon='"+jsonData2.centerLon+"' zom='"+jsonData2.zoom+"'>"+jsonData2.stateName+"</span> ";
});
});
theGHtml = theGHtml+"</div>";
});
theHtml = theHtml+"</ul>";
});
theDiv.html = theHtml+theGHtml;
}
The second (ie. nested) getJson does not return any thing... Both PHP files just use PDO to request data from the SAME table. I run the SQL in each file without any issues, so the SQL seems OK.
Is this an sync v. async issue with the calls to getJson?
Is this an sync v. async issue with
the calls to getJson?
Probably. I think this is your problem:
stateData = data2;
Try changing that to:
var stateData = data2;
The first one sets a global variable. The second one sets a variable that is local to that function.
You might benefit from refactoring this whole process such that you only need to make one AJAX call. It looked like you were pulling individual people associated with a group. You'd get better performance on the server from a single script which can, when needed, return people associated with the group but otherwise just returns the group.
Remember, every AJAX call is another hit to your server.

Categories

Resources