Basically I'm making a nice and simple mobile web app for a couple of my friends. It uses some online databases to store position data of shops. I've got the databases working like a charm. No problems there. In fact everything is working except it's all happening in the wrong order I think. The data from the database should be stored in an array and then the objects in that array are displayed on screen. However, using some console logs I've found that the data is being displayed, then being retrieved from the database, then the arrays are filled. But no matter what I do, I can't get it to work! Here is my code:
var latOfSpots;
var lngOfSpots;
var nameOfSpots;
var spotArray;
var spotLatLng;
var spotCollection;
var markers;
var Spot;
var spot;
function init() {
//-------------------------- INITIATE SPOT VARIABLES ---------------------------//
map = new google.maps.Map2(document.getElementById("map"));
latOfSpots= new Array(51.14400,51.02295);
lngOfSpots= new Array(0.25721,0.26450);
nameOfSpots= new Array('Tescos', 'Sainsburys');
spotLatLng= new Array();
markers= new Array();
Spot = Parse.Object.extend("Spot");
spot = new Spot();
//----------------- GET DATA FROM THE PARSE.COM DATABASE ---------------------//
//---------------------- DISPLAY ARRAY DATA ON MAP ---------------------------//
GetData();
DisplayData();
//----------------------- SET MAP SETTINGS -----------------------------------//
map.setCenter(spotLatLng[0],8);
//map.addControl(new google.maps.LargeMapControl());
map.addControl(new google.maps.MapTypeControl());
}; //END OF INIT FUNCTION ------------------------------------------------//
google.setOnLoadCallback(init);
//------------------- PRIMARY FUNCTION TO GET DATA FROM DATABASE ---------------//
function GetData()
{
var query = new Parse.Query(Spot);
spotCollection = query.collection();
spotCollection.fetch({
success: function(spotCollection) {
// spotCollection.toJSON()
// will now be an array of objects based on the query
FillArrays();
console.log('data retreived' + spotCollection);
}
});
}
//----------------- FUNCTION TO LOAD DATABASE INTO ARRAYS -------------------//
function FillArrays()
{
spotArray = spotCollection.toJSON();
for (var j = 0; j<spotArray.length; j++)
{
latOfSpots.push(spotArray[j].Latitude);
lngOfSpots.push(spotArray[j].Longitude);
nameOfSpots.push(spotArray[j].Name);
}
}
//------------------------ FUNCTION TO DISPLAY ALL ARRAY DATA ONSCREEN -----------------//
function DisplayData()
{
for(var i = 0; i<latOfSpots.length; i++)
{
spotLatLng[i] = new google.maps.LatLng(latOfSpots[i], lngOfSpots[i]);
for(var x = 0; x<latOfSpots.length; x++)
{
markers[x] = new google.maps.Marker(
spotLatLng[i], {
"draggable":false,
"title":nameOfSpots[i],
});
map.addOverlay(markers[x]);
}
}
console.log('data displayed');
}
Your database query is asynchronous. You need to use the data in the Get_Data callback function (after it has come back from the server). Currently you are attempting to use it before the server sends it back.
//------------------- PRIMARY FUNCTION TO GET DATA FROM DATABASE ---------------//
function GetData()
{
var query = new Parse.Query(Spot);
spotCollection = query.collection();
spotCollection.fetch({
success: function(spotCollection) {
// spotCollection.toJSON()
// will now be an array of objects based on the query
FillArrays();
console.log('data retreived' + spotCollection);
DisplayData();
}
});
}
Related
I'm building a website using Airtable API to scrape data from an Airtable spreadsheet using JS.
I'm running into a fairly simple(?) problem using JavaScript.
I'm putting data from the spreadsheet into a string array names. console.log(names[0]) prints out the string value correctly, but when I try to do something like:
var test = names[0];
console.log(test),
It prints out undefined
Why does this happen?
My Code:
var names = [];
var locations = [];
//ACCESS AIRTABLE API (GET DATA FROM AIRTABLE SPREADSHEET)
var Airtable = require('airtable');
var base = new Airtable({apiKey: 'keyQ7YUX3SUECVL4C'}).base('appSmUKDnFdEAT1YF');
base('Members').select({
view: "Grid view"
}).eachPage(function page(records, fetchNextPage) {
//Fill arrays with data from spreadsheet
records.forEach(function(record) {
names.push(record.get('parsedName'));
locations.push(record.get('parsedLocation'));
});
fetchNextPage();
}, function done(err) {
if (err) { console.error(err); return; }
});
I have created one Azure function in Azure app which is triggered by IOT Hub, and it saves received messages in SQL database. but it is not able to handle when it receives multiple messages. my function is bellow.
module.exports = function (context, iotHubMessage) {
for (var i = 0; i < iotHubMessage.length; i++) {
var iotMsgObj = iotHubMessage[i];
context.log('Message : ' + JSON.stringify(iotMsgObj));
context.bindings.paraSession = JSON.stringify(iotMsgObj); //to save data in SQL database
context.done(); // will save first message only
}
// context.done(); // will save last message only
};
when iotHubMessage hub has multiple JSON objects, it will save ether first or last message from iotHubMessage will store in database table.
please advice what I am doing wrong?
I haven't tried with SQL binding, but returning an array works for other types (e.g. queue):
module.exports = function (context, iotHubMessage) {
context.bindings.paraSession = [];
for (var i = 0; i < iotHubMessage.length; i++) {
var iotMsgObj = iotHubMessage[i];
context.bindings.paraSession.push(JSON.stringify(iotMsgObj));
}
context.done();
};
Mikhail is right if you are storing data in Azure Table Storage. But when you are using SQL Database you need the following code snippet.
module.exports = function (context, iotHubMessage) {
var tempArr = [];
for (var i = 0; i < iotHubMessage.length; i++) {
var iotMsgObj = iotHubMessage[i];
tempArr.push(iotMsgObj);
}
context.bindings.paraSession = tempArr;
context.done();
};
I have an issue related to database. I am currently working with Gupshup bot programming. There are two different data persistence modes which can be read here and here. In the advanced data persistence, the following code is documented to put data into data base:
function MessageHandler(context, event) {
if(event.message=='update bug - 1452') {
jiraUpdate(context);
}
}
function jiraUpdate(context){
//connect to Jira and check for latest update and values
if(true){
context.simpledb.doPut("1452" ,"{\"status\":\"QA pending\",\"lastUpdated\":\"06\/05\/2016\",\"userName\":\"John\",\"comment\":\"Dependent on builds team to provide right build\"}");
} else{
context.sendResponse('No new updates');
}
}
function DbPutHandler(context, event) {
context.sendResponse("New update in the bug, type in the bug id to see the update");
}
If I want to change only one of column (say status or last Updated) in the table for the row with key value 1452, I am unable to do that. How can that be done?
I used the following code:
function MessageHandler(context, event) {
// var nlpToken = "xxxxxxxxxxxxxxxxxxxxxxx";//Your API.ai token
// context.sendResponse(JSON.stringify(event));
if(event.message=='deposit') {
context.sendResponse("Enter the amount to be deposited");
}
if(event.message=="1000") {
jiraUpdate(context);
}
if(event.message== "show"){
context.simpledb.doGet("1452");
}
}
function HttpResponseHandler(context, event) {
var dateJson = JSON.parse(event.getresp);
var date = dateJson.date;
context.sendResponse("Today's date is : "+date+":-)");
}
function jiraUpdate(context){
//connect to Jira and check for latest update and values
if(true){
context.simpledb.doPut("aaa" ,"{\"account_number\":\"90400\",\"balance\":\"5800\"}");
} else{
context.sendResponse('No new updates');
}
}
/** Functions declared below are required **/
function EventHandler(context, event) {
if (!context.simpledb.botleveldata.numinstance)
context.simpledb.botleveldata.numinstance = 0;
numinstances = parseInt(context.simpledb.botleveldata.numinstance) + 1;
context.simpledb.botleveldata.numinstance = numinstances;
context.sendResponse("Thanks for adding me. You are:" + numinstances);
}
function DbGetHandler(context, event) {
var bugObj = JSON.parse(event.dbval);
var bal = bugObj.balance;
var acc = bugObj.account_number;
context.sendResponse(bal);
var a = parseInt (bal,10);
var b = a +1000;
var num = b.toString();
context.simpledb.doPut.aaa.balance = num;
}
function DbPutHandler(context, event) {
context.sendResponse("testdbput keyword was last put by:" + event.dbval);
}
Since the hosted DB that is provided by Gupshup is the DynamoDB of AWS. Hence you can enter something as a key, value pair.
Hence you will have to set the right key while using doPut method to store data into the database and use the same key to get the data from the database using the doGet method.
To update the data you should first call doGet method and then update the JSON with right data and then call doPut method to update the database with the latest data.
I have also added something which is not present in the documentation, You can now make DB calls and choose which function the response goes to.
I am refactoring your example as using 3 keywords and hard coding few things just for example -
have - this will update the database with these values
{"account_number":"90400","balance":"5800"}
deposit - on this, the code will add 1000 to the balance
show - on this, the code show the balance to the user.
Code -
function MessageHandler(context, event) {
if(event.message=='have') {
var data = {"account_number":"90400","balance":"5800"};
context.simpledb.doPut(event.sender,JSON.stringify(data),insertData); //using event.sender to keep the key unique
return;
}
if(event.message=="deposit") {
context.simpledb.doGet(event.sender, updateData);
return;
}
if(event.message== "show"){
context.simpledb.doGet(event.sender);
return;
}
}
function insertData(context){
context.sendResponse("I have your data now. To update just say \"deposit\"");
}
function updateData(context,event){
var bugObj = JSON.parse(event.dbval);
var bal = bugObj.balance;
var a = parseInt(bal,10);
var b = a + 1000;
var num = b.toString();
bugObj.balance = num;
context.simpledb.doPut(event.sender,bugObj);
}
function EventHandler(context, event) {
if (!context.simpledb.botleveldata.numinstance)
context.simpledb.botleveldata.numinstance = 0;
numinstances = parseInt(context.simpledb.botleveldata.numinstance) + 1;
context.simpledb.botleveldata.numinstance = numinstances;
context.sendResponse("Thanks for adding me. You are:" + numinstances);
}
function DbGetHandler(context, event) {
var accountObj = JSON.parse(event.dbval);
context.sendResponse(accountObj);
}
function DbPutHandler(context, event) {
context.sendResponse("I have updated your data. Just say \"show\" to view the data.");
}
When using the Bing Maps Api and doing geocoding I am trying to store the latitude and longitude in arrays from the callback. Mostly this works, except for one usually. There always seems to be a duplicate latitude and longitude in entitiesToVisit, but not testLocations when CalculateOptimizedDirections is called.
for(var i = 0; i < toVisit.length; i++){
if(toVisit[i].checked){
var count = parseInt(toVisit[i].id.toString().split(":")[0]);
var tempEntity = entitiesToPickFrom[count];
console.log(entitiesToPickFrom[count]);
tempEntity.compositeAddress = document.getElementById("d"+toVisit[i].id.toString().split(":")[1]).innerHTML.split(">")[1].split("<")[0];
config.searchManager.geocode({
where: tempEntity.compositeAddress,
count: 1,
callback: function (result, pinData) {
var topResult = result.results && result.results[0];
if (topResult) {
pinData.latitude = topResult.location.latitude;
pinData.longitude = topResult.location.longitude;
entitiesToPickFrom[count].latitude = topResult.location.latitude;
entitiesToPickFrom[count].longitude = topResult.location.longitude;
//entitiesToVisit.push(pinData);
//setTimeout(10,function (){console.log("Pin Data");});
//console.log(entitiesToVisit);
document.getElementById("BingMap").style.display = "block";
var wizardDiv = document.getElementById("AddressSelectioWizard");
wizardDiv.style.display = "none";
//possible issue
testLocations.push(new Microsoft.Maps.Location(pinData.latitude,pinData.longitude));
entitiesToVisit.push(pinData);
//testLocations.push(new Microsoft.Maps.Directions.Waypoint(tempEntity.latitude,tempEntity.longitude));
if(entitiesToVisit.length >= checkedCheckers){
CalculateOptimizedDirections();
}
}
else{
//console.log("Nothing gotten");
console.log(result);
//console.log(tempEntity.compositeAddress);
}
},
errorCallback: function (error){console.log(error)},
userData: tempEntity
});
}
}
I've noticed that when I set a timeout to just print text to the console in the middle of the callback, everything works perfectly. This seems to be a bad solution though, is there a better way around it?
The pinData object you are passing into the entitiesToVisit array is the tempEntity value you are passing into the userData option of the geocode call. The issue is likely related to this code:
var count = parseInt(toVisit[i].id.toString().split(":")[0]);
var tempEntity = entitiesToPickFrom[count];
I've been using google's charts API and have reached a dead end. I use the API to query a spreadsheet and return some data. For visualizations I'm using Razorflow - a JS dashboard framework - not Google Charts. Getting the data is pretty straight forward using code like this (this code should work - spreadsheet is public):
function initialize() {
// The URL of the spreadsheet to source data from.
var myKey = "12E2fE8GWuPvXJoiRZgCZUCFhRKlW69uJAm7fch71jhA"
var query = new google.visualization.Query("https://docs.google.com/spreadsheets/d/" + myKey + "/gviz/tq?sheet=Sheet1");
query.setQuery("SELECT A,B,C WHERE A>=1 LIMIT 1");
query.send(function processResponse(response) {
var KPIData = response.getDataTable();
var KPIName = [];
myNumberOfDataColumns = KPIData.getNumberOfColumns(0) - 1;
for (var h = 0; h <= myNumberOfDataColumns ; h++) {
KPIName[h] = KPIData.getColumnLabel(h);
};
});
};
google.charts.setOnLoadCallback(initialize);
The above will create an array holding the column labels for column A,B and C.
Once the data is fetched I want to use the data for my charts. Problem is, I need to have the data ready before I create the charts. One way I have done this, is creating the chart before calling google.charts.setOnLoadCallback(initialize) and then populate the charts with data from inside the callback. Like this:
//create dashboard
StandaloneDashboard(function (db) {
//create chart - or in this case a KPI
var firstKPI = new KPIComponent();
//add the empty component
db.addComponent(firstKPI);
//lock the component and wait for data
firstKPI.lock();
function initializeAndPopulateChart() {
// The URL of the spreadsheet to source data from.
var myKey = "12E2fE8GWuPvXJoiRZgCZUCFhRKlW69uJAm7fch71jhA"
var query = new google.visualization.Query("https://docs.google.com/spreadsheets/d/" + myKey + "/gviz/tq?sheet=Sheet1");
query.setQuery("SELECT A,B,C WHERE A>=1 LIMIT 1");
query.send(function processResponse(response) {
var KPIData = response.getDataTable();
var KPIName = [];
myNumberOfDataColumns = KPIData.getNumberOfColumns(0) - 1;
for (var h = 0; h <= myNumberOfDataColumns ; h++) {
KPIName[h] = KPIData.getColumnLabel(h);
};
//use label for column A as header
firstKPI.setCaption(KPIName[0]);
//Set a value - this would be from the query too
firstKPI.setValue(12);
//unlock the chart
firstKPI.unlock();
});
};
google.charts.setOnLoadCallback(initializeAndPopulateChart);
});
It works but, I would like to separate the chart functions from the data loading. I guess the best solution is to create a promise. That way I could do something like this:
//create dashboard
StandaloneDashboard(function (db) {
function loadData() {
return new Promise (function (resolve,reject){
//get the data, eg. google.charts.setOnLoadCallback(initialize);
})
}
loadData().then(function () {
var firstKPI = new KPIComponent();
firstKPI.setCaption(KPIName[0]);
firstKPI.setValue(12);
db.addComponent(firstKPI);
})
});
As should be quite obvious, I do not fully understand how to use promises. The above does not work but. I have tried lots of different ways but, I do not seem to get any closer to a solution. Am I on the right track in using promises? If so, how should i go about this?
Inside a promise you need to call resolve or reject function when async job is done.
function loadData() {
return new Promise (function (resolve,reject){
query.send(function() {
//...
err ? reject(err) : resolve(someData);
});
})
}
And then you can do
loadData().then(function (someData) {
//here you can get async data
}).catch(function(err){
//here you can get an error
});
});
new Promise(resolve => {
google.charts.setOnLoadCallback(resolve);
}).then(getValues);