I am running into strange issue. This is regarding google Place search of type "textsearch". I am searching map for the results with a keyword and have a callback function to create result ("li" in html).
The problem is that google Place search api only gives 20 results for text search. To retrieve more results, we have to call pagination.nextPage(). This calls the same callBack function and gives more result.
So,
My code is
var request = {query: 'pizza in newyork'};
var service = new google.maps.places.PlacesService(map);
service.textSearch(request, callBack1);
function callBack1(results, status,pagination) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
//add place as li
}
if (pagination.hasNextPage) {
pagination.nextPage();
}
doOtherOperation();
}
function doOtherOperation() {
//do manipulations on "li" which are created from callBack1
}
The problem is that doOtherOperation() starts executing before callBack1() completes execution.
Anybody can help? how to make sure that callBack1 will executed fully (including recursive calls by pagination.nextPage())?
Not an expert, but looks like a small logic flaw, so I will do it this way:
if (pagination.hasNextPage) {
pagination.nextPage();
}
else
{
doOtherOperation();
}
Otherwise doOtherOperation(); gets called each time regardless of the fact that you have to go trough nextPage again.
Hope it helps
try to wrap doOtherOperation() with setTimeout(function() { /* */}, 0)
UPDATE... how about that?
var flag = false;
function callBack1(results, status,pagination) {
/* since callback1 is the same callback for textSearch() and nextPage() -
you need to call dootherOperation at the beginning of statement */
if (flag) {
doOtherOperation();
}
for (var i = 0; i < results.length; i++) {
var place = results[i];
//add place as li
}
if (pagination.hasNextPage) {
flag = true;
pagination.nextPage();
}
else {
flag = false;
}
}
Related
tl;dr: my function doesn't run while I've got setInterval() running another function every 3 seconds.
I'm making a text-based gardening game that runs "plant()" when I type plant. I've also got a setInterval(updatePlots, 3000) going.
both of these functions work fine on their own, but when I try to run plant() while setInterval() is going, it brings up the error Uncaught TypeError: plant is not a function
(I know it's the setInterval() because I tested planting without it running, and it worked fine.)
what I tried (didn't work):
if (command == "plant") {
clearInterval(timer);
plant(a, b);
var timer = setInterval(updatePlots, 3000);
}
I'm not really sure what code I've got to show, since it seems more of a fundamental problem than single-line error... but here it is.
function updatePlots() {
fullplots = [];
for (i = 0; i < plots.length; i++) {
if (plots[i].length) {
fullplots.push(i);
}
}
for (i = 0; i < fullplots.length; i++) {
plant = plots[fullplots[i]][0];
status = plots[fullplots[i]][1];
growth = plots[fullplots[i]][2];
if (growth < 100) {
plots[fullplots[i]][2]++;
}
}
if (document.getElementById('plots').style.display == 'block') {
getPlots();
}
}
...
function processTwo(command, a) {
if (command == 'plant') {
clearInterval(timer);
console.log('about to plant 1'+a);
plant(1, a);
var timer = setInterval(updatePlots, 3000);
}
else { createError() }
}
update: solved!
function updatePlots() {
// this way, the global plant function is not overwritten
// #see JavaScript variable scope
var plant;
// You might want to 'var' your other local (?) variables, too
// var fullplots, i, status, growth;
fullplots = [];
for (i = 0; i < plots.length; i++) { //get fullplots
if (plots[i].length) {
fullplots.push(i);
}
}
for (i = 0; i < fullplots.length; i++) {
// at this line of code you overwrite the global plant, which is not a function anymore then
plant = plots[fullplots[i]][0];
status = plots[fullplots[i]][1];
growth = plots[fullplots[i]][2];
if (growth < 100) { //increment
plots[fullplots[i]][2]++;
}
}
if (document.getElementById('plots').style.display == 'block') {
getPlots();
}
}
The problem arises in the updatePlots method called by setInterval. What you're doing in there is assigning a new value to "plant"
plant = plots[fullplots[i]][0];
Then, when plant is called, it points to the new value you assigned to it in updatePlots instead of the function you originally had. You have to declare a new variable in updatePlots to avoid changing the plant method. I'd use a different name to avoid confusion.
I am trying to load interactivly some questins from questions' array (q) into my page and after student clicks at one of the 2 questions register the answer and change the question using js while loop. What is my mistake that it doesn't work?
var q = [
['NFR', 'Reusability'],
['NFR', 'Robustness'],
['FR', 'Reporting Requirements'],
['FR', 'Historical Data']
];
var correct = 0;
var incorrect = 0;
var total = q.length;
var i = 0;
document.getElementById('nick').innerText = name;
document.getElementById('question').innerText = q[0][1];
var nfr = document.getElementById('non-functional');
var fr = document.getElementById('functional');
function callback(ans) {
if (q[i][0] === ans) {
correct++;
} else {
incorrect++;
};
if (i < q.length - 1) {
i++;
document.getElementById('question').innerText = q[i][1];
} else {
location.href = "answer.html";
}
}
nfr.addEventListener('click', callback('NFR'));
fr.addEventListener('click', callback('FR'));
Your while loop is looping endlessly, because the only thing it does logically is set toNext to False, set some event listener callbacks and then evaluate toNext again, which will always be False. So i++ will never be called and i < q.length will always be True.
Get rid of the while loop. Write a separate function that evaluates the answer and updates your window with the next question. Use that function as callback for the click events.
In a callback function this will be set to the object calling the function, so you could write a function like this:
function callback() {
if (this.id == q[i][0]) {
window.correct++;
} else {
window.incorrect++;
}
i++;
set_question(i); // Logic to set the i-th question.
}
Edit
function callback(ans) {
// This function will return
// another function with the ans
// variable set, which in turn
// will be called as a callback
// when needed by the 'click' event.
return function () {
if (q[i][0] === ans) {
correct++;
} else {
incorrect++;
};
if (i < q.length - 1) {
i++;
document.getElementById('question').innerText = q[i][1];
} else {
location.href = "answer.html";
}
}
}
Event listeners are executed asynchronously and the code you write might assumes that the listeners can block loop execution.
To fix this, try removing the loop and move the logic of switching to the next question into the listener callback.
I have the following code
startProgressTimer: function () {
var me = this,
updateProgressBars = function (eventItems) {
alert("updateProgressBars: looping");
alert("me.eventProgressTimerId:" + me.eventProgressTimerId);
var i = 0;
if (eventItems.length === 0) {
alert("internal Stop Begin")
clearInterval(me.eventProgressTimerId);
alert("internal Stop End")
eventItems = [];
}
for (i = 0; i < eventItems.length; i++) {
if (eventItems[i]._eventId) {
eventItems[i].updateProgressBar();
}
}
};
alert("Start Progress Timer");
this.eventProgressTimerId = setInterval(function () {
updateProgressBars([]);
}, 10000);
}
When the function is called I would expect it to run and bottom out only it keeps on looping.
screen output
ALERT:updateProgressBars: looping
ALERT:me.eventProgressTimerId:10
ALERT:internal Stop Begin
ALERT:internal Stop End
ALERT:updateProgressBars: looping
ALERT:me.eventProgressTimerId:10
ALERT:internal Stop Begin
ALERT:internal Stop End
Any ideas
I suspect the problem might be that the code you don't show calls the startProgressTimer() method more than once for the same instance of whatever object it belongs to, and then within the method you store the interval id in an instance property this.eventProgressTimerId - so multiple calls overwrite the property and you'd only be able to cancel the last one.
If that's the case, a simple fix is to declare your eventProgressTimerId as a local variable within startProgressTimer().
whenever i try to run something like the following, firebug tells me that "markers is undefined" at the line "for (var i=0 ..."
but i declared markers as a global variable at the top right...?
var markers;
function load() {
$.get("phpsqlajax_genxml.php", function(data) {
markers = data.documentElement.getElementsByTagName("marker");
});
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name")
//do more stuff
}
}
but when i do this, it works.
var markers;
function load() {
$.get("phpsqlajax_genxml.php", function(data) {
markers = data.documentElement.getElementsByTagName("marker");
makeMarkersWithXMLinfo();
});
function makeMarkersWithXMLinfo() {
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name")
//do more stuff
}
}
}
i'm not even passing "markers" as an argument to my makeMarkersWithXMLinfo() function. but yet it works. what's going on? thnx
The problem you're having is that get starts an asynchronous operation. So your code immediately following the call to get happens before the success callback on the get is run. E.g. (see the comments):
var markers;
function load() {
// ===> This happens FIRST
$.get("phpsqlajax_genxml.php", function(data) {
// ===> This happens THIRD, some time after `load` returns
markers = data.documentElement.getElementsByTagName("marker");
});
// ===> This happens SECOND
for (var i = 0; i < markers.length; i++) {
var name = markers[i].getAttribute("name")
//do more stuff
}
}
Your second example is the correct way to code it (although I'd recommend avoiding a global entirely), because you're using markers only after the GET has completed.
$.get is asynchronous, that means that if you call something immediatly after $.get, it's callback function wouldn't be invoked yet, and your global would still be undefined.
I need to wait for an ajax response inside a for loop. If I could I'd simply make a synchronous call instead of asynchronous, but I don't have that level of control: I'm using somebody else's API which in turn calls eBay's Javascript API.
Below are my two functions, actually methods on the same closure/object, with categoryStack and categoryMap in scope for each. In essence I'm trying to recursively build up a map, though I want to use a stack for management, rather than true recursion.
I've tried a few variations on setInterval/setTimeout but I always get one of two results: one iteration of the loop, or an endless loop. Note that m_eBay.getChildCategories specifies the second of the two functions below as a callback, and I have confirmed that I am getting there successfully.
function getChildCategories() {
categoryStack.push(-1);
while (categoryStack.length > 0) {
catId = categoryStack.pop();
m_eBay.getChildCategories({
'success':getChildCategoriesSuccess,
'failure':getChildCategoriesFailure},
{'siteid':0, 'CategoryID':catId, 'IncludeSelector':'ChildCategories'}
);
/*
use response from getChildCategoriesSuccess to reset categoryStack
*/
}
}
function getChildCategoriesSuccess(data){
if (data.categoryCount > 0) {
var categoryObjs = data.categoryArray.category;
for (var i=0, n=categoryObjs.length; i<n; i++) {
var catObj = categoryObjs[i];
if (catObj.categoryID != -1) { //skip root
categoryStack.push(catObj.categoryID);
categoryMap[catObj.categoryName] = catObj.categoryID;
}
}
}
}
Using asynchronous ajax you need to do something like:
function getChildCategories(onload) {
var categoryStack = [-1];
function doNextOrFinish() {
if (categoryStack.length) {
m_eBay.getChildCategories({
'success': function(data) {
if (data.categoryCount > 0) {
var categoryObjs = data.categoryArray.category;
for (var i=0, n=categoryObjs.length; i<n; i++) {
var catObj = categoryObjs[i];
if (catObj.categoryID != -1) { //skip root
categoryStack.push(catObj.categoryID);
categoryMap[catObj.categoryName] = catObj.categoryID;
}
}
}
doNextOrFinish();
},
'failure':getChildCategoriesFailure},
{'siteid':0, 'CategoryID':categoryStack.shift(), 'IncludeSelector':'ChildCategories'}
);
} else {
if (onload) onload();
}
}
doNextOrFinish();
}
Still uses recursion though.
Another solution to this problem is to use Arrows.