Trying to use a module pattern to safely get data - javascript

I'm attempting to not have to use a global variable called 'data'
In my js file I now have this function:
var Module_BarDataDaily = (function() {
var data;
d3.csv("myData.csv", function(rows) {
data = rows;
});
return {
dataX: data
}
})();
I was then (probably wrongly) under the impression that I can access this data via Module_BarDataDaily.dataX - so in a subsequent function I do the following:
function TOPbarChart(
grp, meas, colorChosen) {
TOPbarData = Module_BarDataDaily.dataX.map(function(d) { //line 900
return { ...
Console then just gives me an exception on line 900 of the following:
TypeError: Module_BarDataDaily.dataX is undefined
What am I doing wrong & how do I fix it?

The issue here is that d3.csv is asynchronous, so data is filled at a different time than accessed.
If you want to run d3.csv once, get the data and save them elsewhere, you can try something like this or this or this
In general:
// define your module here
var Module_BarDataDaily = function(data) {
this.dataX = data; //this.dataX will store the data
this.process = function(){// do whatever you need afterwards
console.log(this.dataX);
}
};
var process = function(myModule){
// or use another function to do what you need etc
console.log(myModule.dataX);
}
// load your csv once and save the data
d3.csv("path/to/your.csv", function(error, data) {
// after some proper error handling...
var myModule = new Module_BarDataDaily(data);
// so then you can do anything after that and
// your myModule will have data without calling d3.csv again
myModule.process();
//or
process(myModule);
});
Hope this helps!
Good luck!

I've used the following based on mkaran's answer:
var Module_BarDataDaily = function(data) {
this.dataX = data;
};
d3.csv("data/BarChart_data.csv", function(error, rows) {
var myModule = new Module_BarDataDaily(rows);
var chart = barChart();
chart.render(myModule.dataX);
d3.selectAll('input[name="meas"]').on("change", function change() {
chart.currentMeasure(this.value)
chart.render(myModule.dataX);
});
});

Related

Electron webContents.send does not always work

I use the following to send some data to another window;
try{
win.webContents.once('dom-ready', () => win.webContents.send('send-data', data));
}
catch(err){
console.log("Caught ",err);
}
And for receivig;
ipcRenderer.on('send-data', function (event,data) {
console.log("Loaded ", data);
});
The thing is, the "data" here is sometimes assembled very quickly and it works fine. However, sometimes it takes a while and the other window is already loaded at this point. No data is received in that case, and no error message either. But then I can simply use the following to send it without problems;
win.webContents.send('send-data', data)
I couldn't find a way to apply for both cases. Any suggestions?
The short answer is no.
Electron doesn't have a function to wait for the window to load, then send a message, or send a message right away if the window's already loaded.
However this can be done with some simple code:
var hasWindowLoaded = false;
var hasDataBeenSent = false;
var data = {};
win.webContents.once('dom-ready', () => {
hasWindowLoaded = true;
if (!hasDataBeenSent && data) {
win.webContents.send('send-data', data);
hasDataBeenSent = true;
}
});
// Now add this where you build the `data` variable.
function loadData () {
data = {'sampleData': 'xyz'};
if (!hasDataBeenSent && hasWindowLoaded) {
win.webContents.send('send-data', data);
hasDataBeenSent = true;
}
}
Once the data's loaded in loadData it'll check if the window's finished loading and if it has then it sends the data right away.
Otherwise it stores the data in a varible (data) and once the window loads it sends it to the window.
Another approach that you may want to consider is sending data to the browserWindow using query strings.
const data = { hello: "world" }; // sample data
// send it using query strings
browserWindow.loadFile(YOUR_HTML_FILE_PATH, {
query: { data: JSON.stringify(data) },
});
// parse this data in the browserWindow
const querystring = require("querystring");
const query = querystring.parse(global.location.search);
const data = JSON.parse(query["?data"]);
console.log(data); // { hello: "world" }

Dynamically get data from firebase realtime database during runtime in javascript

I have the following problem: I want to get data from a specific node from firebase during runtime. It should display "stats" of a player that was selected before. Now I could use on() to get all the data in the beginning, but I want to save data transfers by only downloading the data of on player if I need to, so I tried to use once like this:
var firebaseRef = firebase.database().ref();
function getScoresOfPlayer(player) {
console.log(player);
var selectedPlayerScores = [];
firebaseRef.once('value').then(function(snap) {
snap.child('scores').child('thierschi').forEach(function(child) {
selectedPlayerScores.push([child.key, child.val()]);
});
});
return selectedPlayerScores;
}
The problem is that it retruns the array before the data was loaded into it. Also I checked the docs and didn't find a better solution.
Thanks in advance!
This is because the getScoresOfPlayer function returns selectedPlayerScores before the promise returned by the once() method resolves.
You should include the return within the then(), as follows:
var firebaseRef = firebase.database().ref();
function getScoresOfPlayer(player) {
console.log(player);
var selectedPlayerScores = [];
return firebaseRef.once('value') //return here as well
.then(function(snap) {
snap.child('scores').child(player).forEach(function(child) { //I guess it should be child(player) and not child('thierschi') here
selectedPlayerScores.push([child.key, child.val()]);
});
return selectedPlayerScores;
});
}
which means that you have to call your function as follows, since it is going to be asynchronous and to return a promise:
getScoresOfPlayer('xyz')
.then(function(selectedPlayerScores) {
....
})

Socket.IO node js saving data to client

currently I want to save an int assigned from the server to my client
server side:
socket.emit('clientId', id);
Client Side:
var clientId;
socket.on('clientId', function(data){
clientId = data;
});
however, when I use console.log(clientId); outside the function, it becomes undefined. Is there a solution to this. Thanks
It's not that it becomes undefined outside of the function but it's most likely not defined yet. You didn't show how you want to access it outside of the function but if it's anything like this:
var clientId;
socket.on('clientId', function(data){
clientId = data;
});
console.log(clientId);
then the console.log line will be run before clientId = data so it is the same variable, it's just not defined yet.
You need to access that variable from your socket.on handler, or from some function that is run by that handler, or after that handler has already been run.
It's hard to tell anything more specific since you didn't say how do you want to access the variable and what do you want to do with it. You can see my example that I put on GitHub that does something like that to see if that could help you:
https://github.com/rsp/node-websocket-vs-socket.io/blob/master/si.html#L36-L46
It looks like this:
var l = document.getElementById('l');
var log = function (m) {
var i = document.createElement('li');
i.innerText = new Date().toISOString()+' '+m;
l.appendChild(i);
}
log('opening socket.io connection');
var s = io();
s.on('connect_error', function (m) { log("error"); });
s.on('connect', function (m) { log("socket.io connection open"); });
s.on('message', function (m) { log(m); });
Here, the log function is called from within the handler so that it is guaranteed to be called after the message has already been passed. The data is passed as an argument to that function but it could use a global variable as well.
Update
Here is a simpler example:
var clientId;
socket.on('clientId', function (data) {
clientId = data;
clientReady();
});
function clientReady() {
// you can access it here:
console.log(clientId);
}
Here you can access your variable in the clientReady function which is outside of the on handler. Think of it like you would about the window.onload handler:
window.onload = function() {
// ...
};
or $(document).ready() in jQuery:
$(document).ready(function () {
// ...
});
It is a piece of code that gets called on a certain moment to guarantee that everything that you need is ready.
Another example using a promise:
var clientIdPromise = new Promise(function (resolve, reject) {
socket.on('clientId', function (data) {
resolve(data);
});
});
// now everywhere in your code you can access it as:
clientIdPromise.then(function (clientId) {
// you have access to clientId here
});
Or shorter, using the fat arrow notation:
var clientIdPromise = new Promise(
(res, rej) => socket.on('clientId', data => res(data));
// and somewhere else:
clientIdPromise.then(clientId => {
// you have access to clientId here
});
JavaScript is async, it will only print the real value once the .on('clientId') event has been called. You should console.log it inside the function or after, but using EventEmitter.

Passing csvtojson converter's value to a variable outside of its scope

I'm currently fiddling around with Node.js and I stuck with this issue.
I'm using the csvtojson converter (https://github.com/Keyang/node-csvtojson) as a separate module that I can call in my other JS files as many times as I want.
Here is my tools.js:
module.exports = {
csvToJson: function (csvPath) {
var Converter = require('csvtojson').Converter;
var converter = new Converter({});
var transfer = "DEFAULT";
converter.fromFile(csvPath, function(err, result){
if (err) {
return console.log(err);
}
else {
transfer = result;
}
});
return transfer;
}
};
And here is how I call it:
var countriesCsvFile = path.join(__dirname, '..', 'testDataFiles', 'countries.csv');
//GRAB TOOLS
var tools = require('../app/tools');
console.log(tools.csvToJson(countriesCsvFile));
The result is always the "DEFAULT" value which indicates, that the converter is not touching it.
I want to pass it as the return value of the function, to further be able to process the data on the fly, without creating a file, and read that.
It is surely some scope issue, but after scratching my scalp for a few hours, and browsing the questions I couldn't retrieve anything remotely useful.
Also, another note: If I call console.log(result) instead of transfer = result, it shows me my precious and desired data.
You have to pass in a callback function because the csvToJson function is returning 'transfer' before any value is assigned to it. Like Sirko said, it's asynchronous. You can also use promises instead of callbacks but that's another topic in itself.
module.exports = {
csvToJson: function (csvPath, callback) {
var Converter = require('csvtojson').Converter;
var converter = new Converter({});
converter.fromFile(csvPath, function(err, result){
if (err) {
callback(err);
}
else {
callback(null, result);
}
});
}
};

JavaScript - function in for loop not performing as expected

I am building a dashboard that graphs some data. Using splunk js charts to display the data.
My problem is not with the charting. But I would suspect my logic.
What is happening:
Client - requests chart data from server
Server - returns this object:
a
Object { splunkResults: Array[3],
metricHTML: "<div id="MetricOne" class="metric"><p class="lead"…s="metric">
<p class="lead">Metric Three</p></div>", metricID: Array[3]}
Client - model.js calls view.insertMetricContainers via callback and inserts object.metricHTML into the correct container
Client - model.js calls view.graphsReady in for loop via callback and creates a chart and inserts it into the correct metric div based on object.metricID[i]
Client - charts are displayed
My problem is that only one of the charts is being displayed, the first one.
If you look at this function in view.js:
splunkjs.UI.ready(chartToken, function() {});
I have a console.log("test"); Which is only printed once.
What is my mistake here?
Let me know if I can provide any more information, I have tried a few approaches and have run out of ideas.
Model.js
dashboard.getSystemMetrics = function(callback) {
var url = "/services/systemMetrics/?";
if (dashboard.url[1]) {
url = url + dashboard.url[1];
}
if (dashboard.limit) {
url = url + "&limit=" + dashboard.limit;
}
$.get(url, function(response) {
callback(response.metricHTML, null);
for (var i = 0; i < response.splunkResults.length; i++) {
console.log(i);
callback(null, response.splunkResults[i], response.metricID[i]);
}
});
};
View.js
view.graphsReady = function (data, id) {
console.log(id);
var chart = null;
var chartToken = splunkjs.UI.loadCharting('/javascripts/splunk.ui.charting.js', function() {
// Once we have the charting code, create a chart and update it.
chart = new splunkjs.UI.Charting.Chart($("#" + id), splunkjs.UI.Charting.ChartType.AREA, false);
});
splunkjs.UI.ready(chartToken, function() {
chart.setData(data, {
"chart.stackMode": "stacked",
"legend.placement": "top",
"axisTitleX.text": "Time",
"axisTitleY.text": "Data"
});
chart.draw();
});
};
Controller.js
$(function(){
// Grab user params
dashboard.url = window.location.href;
dashboard.url = dashboard.url.split("/?");
dashboard.limit = "day";
// Get Service Statuses
//dashboard.getQuickStatus(controller.quickStatusReady);
// TODO listener events
dashboard.getSystemMetrics(controller.systemMetricsReady);
});
controller.systemMetricsReady = function(html, data, id) {
if (html) {
view.insertMetricContainers(html);
} else if (data && id) {
view.graphsReady(data, id);
}
};
If you would like to suggest a better question title, please by all means go ahead.
EDIT - i have checked the logs yes. No errors, I wouldn't ask the question if I had errors.
I did a console.log in the set data function (view.js) and it was only logged once not 3 times like it should have. Although the function graphReady is called 3 times
UPDATE - I have found in the view.js code that this function is only run once. Despite the function view.graphsReady being called 3 times.
var chartToken = splunkjs.UI.loadCharting('/javascripts/splunk.ui.charting.js', function() {
// Once we have the charting code, create a chart and update it.
chart = new splunkjs.UI.Charting.Chart($("#" + id), splunkjs.UI.Charting.ChartType.AREA, false);
console.log(chart);
});
console.log(chartToken);
So, chartToken is printed 3 times. chart however is only printed once.

Categories