I have one problem. I am trying to get value from one variable but I can't do this. If somebody can help I will appreciate that. This is my code.
function getInfo() {
var ref = firebase.database().ref("db_storage/");
var info = 0;
ref.on("value", function(snapshot) {
info = snapshot.val().length;
}, function (error) {
console.log("Error: " + error.code);
});
return info;
}
var info = getInfo();
alert(info);
Further to my comment above.
The ref.on("value"...) is an event listener that gets triggered when the 'value' event is dispatched by the database ref. When your code runs it goes (roughly speaking) into getInfo(), attaches the event listener, then proceeds to your last line without waiting for the 'value' event.
To hook things up, pass a callback function as follows.
function getInfo(callback) {
var ref = firebase.database().ref("db_storage/");
ref.on("value", function(snapshot) {
var info = snapshot.val().length;
return callback(info);
}, function (error) {
console.log("Error: " + error.code);
return callback(0);
});
}
getInfo(function(info) {
alert(info);
});
Related
I am struggling to understand why my function is failing when trying to loop through a snapshot from Firebase Realtime Database.
The function should read through each 'Topic', from within each 'Topic' there is an 'Articles' field which has approximately 10 articles associated with it. The function reads each article URL and scrapes the URL for the largest image on the article website.
It should then add a new field 'imageURL' to each 'Article'.
When deployed I receive the following:
TypeError: snapshot.forEach is not a function
scraper.js
exports.imageScraper = functions.database.ref("searchTrends/google")
.onUpdate((snapshot, context) => {
functions.logger.error(snapshot);
snapshot.forEach(function(trendSnapshot) {
// TrendSnapshot - Key is topic Num
// Value is topic details with list of articles
const topicNum = trendSnapshot.key;
trendSnapshot.forEach(function(innerChild) {
if (innerChild.key == "articles") {
innerChild.forEach(function(articleData) {
const articleNum = articleData.key;
const myUrl = articleData.child("url").val();
// console.log(myUrl);
const options = {
url: myUrl,
};
// console.log(options);
ogs(options, (error, results, response) => {
if (typeof results.ogImage === "undefined") {
console.log("no Image");
} else {
if (results.ogImage.url === undefined) {
return "done";
}
console.log(articleNum);
const DBRef = admin.database().ref("searchTrends/google/" +
topicNum + "/articles/" + articleNum);
DBRef.update({imageURL: results.ogImage.url});
}
});
});
return "done";
}
}).catch((error) => {
console.log("Transaction failed: ", error);
return null;
});
});
});
The error is telling you that snapshot does not have a method called forEach. It is a not a DataSnapshot object as you are expecting. It is a Change object, specifically Change<DataSnapshot> From the documentation:
For onWrite or onUpdate events, the first parameter is a Change object that contains two snapshots that represent the data state before and after the triggering event.
Also refer to the API documentation for onUpdate.
I have the code snippet bellow which actually is a function that makes a query on a SQL database(used tedious for that).
All I want is to get the data from DB and use them on a web-page.
The issue is that: inside the request.on()... I'm calling date.setMyData() function. Still inside the request.on('row', function(columns)....if calling console.log(date.getMyData()) it successfully returns my data.
BUT, if trying to call date.getMyData outside the request.on('row', function(columns) ...I get NULL...
Is there anything that I'm missing here?
var date = new DBData();
function executeStatement() {
request = new Request(queryString, function(err, rowCount) {
if (err) {
console.log(err);
} else {
console.log(rowCount + ' rows');
}
connection.close();
});
request.on('row', function(columns) {
columns.forEach(function(column) {
if (column.value === null) {
console.log('NULL');
} else {
date.setMyData(columns);
//WHY THIS CODE RETURNS MY DATA?
console.log(date.getMyData());
}
});
});
request.on('done', function(rowCount, more) {
console.log(rowCount + ' rows returned');
});
connection.execSql(request);
}
function DBData(){
var myData = null;
this.setMyData = function(obiect){
myData = obiect;
};
this.getMyData = function(){
return myData;
};
};
console.log(date.getMyData()); //WHY I GET 'NULL' HERE?
When you run that code, the order of execution will be
var date = new DBData()
console.log(date.getMyData()) // null at this point
// end of execution
The function executeStatement() gets defined, but it is not executed right away. It will be presumably executed at a later time when you call it, at which point it will populate your 'var date', hence it will display the correct data correctly when you console.log(date.getMydata()) inside the callback of executeStatement().
I'm been creating a web site following Hottowl's example. However, the value of hasChanges is not changed after saveChanges is called - even the data is actually saved in database table. I use hottowel durandal 2.0.1. I found the durandal version is different from the CCJS-Scratch example. Did I miss anything?
datacontext.js
var manager = configureBreezeManager();
var hasChanges = ko.observable(false);
manager.hasChangesChanged.subscribe(function (eventArgs) {
hasChanges(eventArgs.hasChanges); // The function isn't called when saveChanges is called
});
var cancelChanges = function () {
manager.rejectChanges();
log('Canceled changes', null, true);
};
var saveChanges = function () {
return manager.saveChanges()
.then(saveSucceeded)
.fail(saveFailed);
function saveSucceeded(saveResult) {
log('Saved data successfully', saveResult, true);
}
function saveFailed(error) {
var msg = 'Save failed: ' + getErrorMessages(error);
logError(msg, error);
error.message = msg;
throw error;
}
};
The following code exist in the view model.
var hasChanges = ko.computed(function () {
return datacontext.hasChanges();
});
var cancel = function () {
datacontext.cancelChanges();
};
var canSave = ko.computed(function () {
return hasChanges() && !isSaving();
});
var save = function () {
isSaving(true);
return datacontext.saveChanges().fin(complete);
function complete() {
isSaving(false);
}
};
Maybe you have a timing issue? You have a lot of nested observables and computed observables that I have trouble aligning at this late hour.
What I do know is that the Breeze DocCode:saveTodoTests.js show that hasChangesChanged is called with the correct eventArgs.hasChanges value when both saving changes and reverting (rejectChanges). Here is a passing test from that suite that confirms it.
test("hasChangesChanged event raised after saveChanges", 4, function () {
var em = newTodosEm();
var hasChangesChangedRaised = [];
em.hasChangesChanged.subscribe(
function(eventArgs) {
hasChangesChangedRaised.push(eventArgs.hasChanges);
}
);
// add a Todo (and forget about it)
em.createEntity('TodoItem',{ Description: "Learn to save in breeze" });
stop();
em.saveChanges()
.then ( function() {
equal(hasChangesChangedRaised.length, 2,
"hasChangesChanged should have been raised twice");
ok(hasChangesChangedRaised[0]===true,
"first hasChangesChanged is true after create");
ok(hasChangesChangedRaised[1]===false,
"second hasChangesChanged is false after save");
ok(!em.hasChanges(),
"manager should not have pending changes after save");
})
.fail(handleSaveFailed)
.fin(start);
});
Note that the hasChangesChanged event is raised twice in this test.
Please try debugging again and make sure that the event you're looking at is the one raised after the save, not during some other manipulation.
Also watch out for the nesting of KO events. Race conditions are possible.
I have an IndexedDB containing properties of various elements on the page. I have an index on one of those properties and I use a key range to get a specific list of results.
var key = IDBKeyRange.bound(10, 20);
var cursor = store.index('property').openCursor(key);
The problem I have is with the cursor.onsuccess function. It seems to execute for each result in the result set. Consequently, I can't execute a callback function once all of the results have been parsed.
cursor.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
if (cursor.value.prop1 > 30 && cursor.value.prop2 < 80) {
// Do stuff with result
someArray.push({
prop1: cursor.value.prop1,
prop2: cursor.value.prop2
}):
}
}
cursor.continue();
};
Safest way to know that your action is finished is to use the transaction on complete event. This event is triggered after the cursor is closed.
transaction.oncomplete = function (event) {
console.log('transaction completed');
};
Also to be sure that no error occurred add event listener to transaction events on error and on abort.
transaction.onerror = function (event) {
console.log('transaction error');
};
transaction.onabort = function (event) {
console.log('transaction abort');
};
As it turns out, cursor.onsuccess fires one last time with e.target.result undefined. You can execute a callback function when this happens:
cursor.onsuccess = function (e) {
var cursor = e.target.result;
if (cursor) {
if (cursor.value.prop1 > 30 && cursor.value.prop2 < 80) {
// Do stuff with result
someArray.push({
prop1: cursor.value.prop1,
prop2: cursor.value.prop2
}):
}
} else {
// Execute code here
console.log('There are ' + someArray.length + ' elements in someArray.');
}
cursor.continue();
};
UPDATED CODE: i, I'm new to Javascript programming and getting an undefined variable when trying to assign a new variable from a method.
I'm using node.js and creating a redis server using the redis-client in the "client variable".
var redis = require("redis");
var client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
var numberPosts;
client.get("global:nextPostId", function(err, replies) {
numberPosts = replies;
console.log(numberPosts);
});
console.log(numberPosts);
When I call console.log inside the call back function it returns the proper value, however when I call the console.log outside of the callback function it returns "undefined". I'm trying to assign the value that is inside the callback function to the global variable numberPosts.
Any help is much appreciated, thanks.
Matt
I believe this will work:
client.get("global:nextPostId", function (err, reply) {
console.log("Number of posts: " + reply.toString());
})
The AJAX call is asynchronous so it doesn't have return value.. instead you have to use callback function and only there you have the value returned by the server method.
Edit: to assign the return value to global variable, first declare global variable:
var _numOfPosts = "";
Then:
client.get("global:nextPostId", function (err, reply) {
_numOfPosts = reply.toString());
})
However, the value won't be available until the AJAX call is finished so your original code can't work. There is not direct return value to store.
You can set timer to some reasonable response time, then have the code using the global variable in there.
Edit II: in order to call the method again once it's finished, have such code:
var _nextPostCallCount = 0;
function GetNextPost() {
//debug
console.log("GetNextPost called already " + _nextPostCallCount + " times");
//sanity check:
if (_nextPostCallCount > 1000) {
console.log("too many times, aborting");
return;
}
//invoke method:
client.get("global:nextPostId", function(err, replies) {
numberPosts = parseInt(replies.toString(), 10);
console.log("num of replies #" + (_nextPostCallCount + 1) + ": " + numberPosts);
//stop condition here.... for example if replies are 0
if (!isNaN(numberPosts) && numberPosts > 0)
GetNextPost();
});
//add to counter:
_nextPostCallCount++;
}
GetNextPost();
This will call the method over and over until the result is 0 or you pass some hard coded limit to prevent endless loop.
Try this instead to see errors:
var redis = require("redis");
client = redis.createClient();
client.on("error", function (err) {
console.log("Error " + err); });
//note the error logging
var numberPosts = client.get("global:nextPostId", function (error, response) {
if (error) {
console.log("async: " + error);
} else {
console.log("programming: " + response);
}
});
console.log("is lotsa fun: " + numberPosts);
As Shadow Wizard has pointed out you are trying to use numberPosts before there is something in it, as client.get() hasn't returned anything.
Read this to get a handle on node.js flow:
http://www.scribd.com/doc/40366684/Nodejs-Controlling-Flow
I was facing the the same issue when I applied the MVC framework.
To solve the problem, I employed the render function.
In the posts Model
exports.get = function(id,render) {
client.incr('post:id:'+id, function(err, reply) {
render(reply);
});
};
In the posts Controller
exports.get = function(req, res) {
posts.get('001', function (data){res.render('index',{post:data});});
};