I have the following function
function draw(i, arrayIdColetor, callback) {
var query = new $kinvey.Query();
query.equalTo('idColetor', arrayIdColetor[i]);
var promise = $kinvey.DataStore.find('myDatabase', query);
var latLong = promise.then(function(response) {
coordenadas = [];
for(var j = response.length - 1; j >= 0 ; j--) {
coordenadas.push( {lat: response[j].lat, lng: response[j].lng});
}
return coordenadas;
});
latLong.then(function(coordenadas) {
$kinvey.poly[i] = new google.maps.Polyline({ path: coordenadas, ... });
$kinvey.poly[i].setMap($kinvey.map); });
callback();
}
This function is called by the following function:
function callFor(j, arrayIdColetor) {
if (j < arrayIdColetor.length){
draw(j, arrayIdColetor, function() {
callFor(j + 1, arrayIdColetor)
});
}
}
The function callFor take a couple of seconds to be executed and I'd like that all the interface buttons be disabled while callFor functions is running. What should I do to solve it?
One more question, I have another function that I'd like that runs always after the callFor function is finished.
Thanks for any help.
Maybe you could try this? I didn't really get why you were using recursion as you're not doing anything that would suggest its use, and it's only complicating your wished behavior.
function callFor(j, arrayIdColetor) {
//disable buttons
for (i = j; i < arrayIdColetor; i++) {
draw(i, arrayIdColetor, function(){});
}
//enable buttons
}
Related
I'm doing a project for school. A memory game that uses the pokéAPI to get images.
I have three buttons depending on the game level (easy, medium, hard) and it generates the amount of cards.
When I click a button it generates the pictures but when I click it again it append the new data into the same selector.
I have tried with: $('#output').html(''), $('#output').append(''), $('#output').remove(), $('#output').empty()
// Settings for game level. Each integer represents number of cards * 2.
let easy = 4;
let medium = 6;
let hard = 8;
// Arrays for PokemonImgUrl.
let originalPokemonImgUrl = [];
let duplicateAllPokemonImgUrl = [];
let allPokemonImgUrl = [];
// PokéAPI URL.
const pokemonDataUrl = 'https://pokeapi.co/api/v2/pokemon/';
// This function creates a random number depending on the settings below.
function randomNumber() {
// Settings for max randomnumbers starting from index 1.
let randomNumberMax = 500;
let fromIndex = 1;
// Math random function with values from randomnumbers.
return Math.floor(Math.random() * randomNumberMax) + fromIndex;
}
// Function for getting data from PokéAPI.
function getData() {
$.ajax ({
type: 'GET',
url: pokemonDataUrl + randomNumber(), // Calling randomnnumber to get a random pokémon.
success: function(pokemonData) {
var pokemonImgUrl = pokemonData.sprites.front_default; // Store and extract pokemon images.
originalPokemonImgUrl.push(pokemonImgUrl); // store ImagesURL to a global array called allPokemonImgUrl.
}
})
}
// Shuffle code from css-tricks.com.
function Shuffle(cards) {
for(var j, x, i = cards.length; i; j = parseInt(Math.random() * i), x = cards[--i], cards[i] = cards[j], cards[j] = x);
return cards;
};
// function iterates through allPokemonImgUrl array and outputs it into the DOM.
function output() {
allPokemonImgUrl.forEach(function (i) {
$('#output').append('<img src="'+ [i] +'">');
}
)}
/* This function copies the array so that we always have two of the same cards.
Then concat into a new array and shuffles it. After that it outputs the result.*/
function startGame(){
setTimeout( function(){
duplicateAllPokemonImgUrl = originalPokemonImgUrl.slice();
}, 1000 );
setTimeout( function(){
allPokemonImgUrl = originalPokemonImgUrl.concat(duplicateAllPokemonImgUrl);
}, 1500 );
setTimeout( function(){
Shuffle(allPokemonImgUrl)
}, 2000 );
setTimeout( function(){
output();
}, 2500 );
}
/* Events for clicking on game levels. It iterates to check how many cards it needs
and calls the function getData accordingly. */
$(document).on('click', '#easy', function() {
for (var cards = 0; cards < easy; cards++) {
getData();
}
startGame();
})
$(document).on('click', '#medium', function() {
for (var cards = 0; cards < medium; cards++) {
getData();
}
startGame();
})
$(document).on('click', '#hard', function() {
for (var cards = 0; cards < hard; cards++) {
getData();
}
startGame();
})
When I click a button I get the images as expected.
But when I click it again it appends the new data after the old data. I want to remove the old ajax data first and then append the new data.
I found the solution:
Adding a clear function:
function clear() {
originalPokemonImgUrl = [];
duplicateAllPokemonImgUrl = [];
allPokemonImgUrl = [];
$('#output').empty();
}
Then just call it:
$(document).on('click', '#easy', function() {
for (var cards = 0; cards < easy; cards++) {
getData();
}
clear();
startGame();
})
Alright, so, hopefully this is a simple enough question. I'm sure that it has to be something simple and stupid that I am not doing right. I'm building an app to program my exercise routine into so I can keep track of it every week (and to learn app development using Cordova). Within the code, each time I come back to the exersetup screen I want to read the saved exercise file, parse it back to an array of objects, convert those objects back into exercise objects, then display them on the screen. I have a loop that is supposed to check each element of the array to process the information, then display, then repeat until it has done this for each element in the array. It works perfectly fine for the first item, then stops. If I manually run the loop multiple times, it functions perfectly. Not listed is the code for the function addRow(), which simply adds a row of formatted dropdown selectors for input, then increments rowNum to keep track of which row it is operating on. Any help you guys can offer is appreciated. If I need to submit more information I would be happy to do so. Here's the loop in question:
EDIT: Fixed some things to the suggestions in the comments below. Code still functions the same. Works perfectly fine on first run through loop, then stops. If I continue to run the loop manually (declaring it over and over again in console) it works fine, but it will not, for some reason, run the "for" loop. I've also included the rest of the function that the for loop is nested in, in case that helps.
function readRout()
{
console.log("Reading routine...");
document.addEventListener('deviceready', getFile, false);
function getFile()
{
window.resolveLocalFileSystemURL(cordova.file.dataDirectory, function(dir)
{
console.log("got main dir",dir);
dir.getFile("exerciseroutine.txt", {create:true}, function(file)
{
console.log("got the file", file);
exerLog = file;
console.log(exerLog);
});
});
document.addEventListener('deviceready', logOut, false);
}
function logOut()
{
setTimeout(readLog, 50);
}
function readLog()
{
exerLog.file(function(file)
{
var reader = new FileReader();
reader.onloadend = function(e)
{
console.log(this.result);
exerRoutine = JSON.parse(this.result);
//console.log(exerRoutine);
//console.log(exerRoutine[0]);
var looper = exerRoutine.length + 1;
for (var i=0; i<looper; i++)
{
console.log("Loop count is: " + i);
console.log(looper);
exerRoutine[i] = new exercise(exerRoutine[i].type, exerRoutine[i].name, exerRoutine[i].sets, exerRoutine[i].reps, exerRoutine[i].pace);
console.log(exerRoutine[i]);
console.log(exerRoutine[i].description());
console.log(exerRoutine[i].type);
console.log(exerRoutine[i].name);
console.log(exerRoutine[i].sets);
console.log(exerRoutine[i].reps);
console.log(exerRoutine[i].pace);
addRow();
setTimeout(fillExer, 50);
console.log(exerRoutine);
}
console.log(looper);
};
reader.readAsText(file);
}, fail);
}
function fillExer()
{
var typeRow = "typeSel" + rowNum;
console.log(typeRow);
console.log(document.getElementById(typeRow));
var nameRow = "nameSel" + rowNum;
var setsRow = "setsSel" + rowNum;
var repsRow = "repsSel" + rowNum;
var paceRow = "paceSel" + rowNum;
fillType(typeRow);
setTimeout(fillName, 10, nameRow);
fillSets(setsRow);
fillReps(repsRow);
fillPace(paceRow);
}
function fillType(typek)
{
for (var k=0; k<document.getElementById(typek).options.length; k++)
{
//console.log(document.getElementById(typek).options.length);
console.log(exerRoutine[rowNum-1].type);
if(document.getElementById(typek).options[k].value == exerRoutine[rowNum-1].type)
{
document.getElementById(typek).selectedIndex = k;
//console.log(document.getElementById(typei).selectedIndex);
var quer = "#" + typek;
//console.log(query);
var typeInput = document.querySelector(quer);
//console.log(typeInput);
TypeSelect(typeInput);
return;
}
}
}
function fillName(namek)
{
for (var k=0; k<document.getElementById(namek).options.length; k++)
{
//console.log(document.getElementById(namek).options.length);
console.log(exerRoutine[rowNum-1].name);
if(document.getElementById(namek).options[k].value === exerRoutine[rowNum-1].name)
{
document.getElementById(namek).selectedIndex = k;
//console.log(document.getElementById(namei).selectedIndex);
return;
}
}
}
function fillSets(setsk)
{
for (var k=0; k<document.getElementById(setsk).options.length; k++)
{
console.log(exerRoutine[rowNum-1].sets);
if(document.getElementById(setsk).options[k].value === exerRoutine[rowNum-1].sets)
{
document.getElementById(setsk).selectedIndex = k;
//console.log(document.getElementById(setsk).selectedIndex);
return;
}
}
}
function fillReps(repsk)
{
for (var k=0; k<document.getElementById(repsk).options.length; k++)
{
console.log(exerRoutine[rowNum-1].reps);
if(document.getElementById(repsk).options[k].value === exerRoutine[rowNum-1].reps)
{
document.getElementById(repsk).selectedIndex = k;
//console.log(document.getElementById(repsi).selectedIndex);
return;
}
}
}
function fillPace(pacek)
{
for (var k=0; k<document.getElementById(pacek).options.length; k++)
{
console.log(exerRoutine[rowNum-1].pace);
if(document.getElementById(pacek).options[k].value === exerRoutine[rowNum-1].pace)
{
document.getElementById(pacek).selectedIndex = k;
//console.log(document.getElementById(pacek).selectedIndex);
return;
}
}
}
}
I want to create a recursive JavaScript loop which can display all the Frames (either using IFRAMES Tag or using FRAME Tag). The result should give FrameName, NestingLevel, FrameURL, etc.
For example, when we open 'Developer Tools' in Google Chrome, we can see in all the FRAMES(even nested Frames too) in the console tab.
Please give a recursive loop with error handling (iframe security issue) for the same.!
Sample Code:
function getFramesInfo(oWin) {
arrFrames = oWin.frames;
//alert(arrFrames.length);
if (arrFrames.length == 0) {
alert('document do not have frame(s)');
} else {
for (i = 0; i < arrFrames.length; i++) {
console.log(i + ' ' + arrFrames[i].location.href);
if (arrFrames[i].document) {
getFramesInfo(arrFrames[i]);
}
}
}
}
//Calling This Function
getFramesInfo(window);
Alternate / Improved Code:
function getAllFrames(frame, allFrameArray) {
allFrameArray.push(frame.frames);
for (var i = 0; i < frame.frames.length; i++) {
getAllFrames(frame.frames[i], allFrameArray);
}
return allFrameArray;
}
//Usage:
var allFramesArray = getAllFrames(window, new Array());
console.log(allFramesArray.length); // number of frames in array
for (var i = 0; i < allFramesArray.length; i++) {
console.log('\n\n No.'+ (i+1) + '.');
try {
console.log(allFramesArray[i].id);
console.log(allFramesArray[i].name);
console.log(allFramesArray[i].location.href); // location of first frame in array}
} catch (e) {
console.log('Error in Accessing Frame No.' + (i+1) ); // location of first frame in array}
}
}
After googling and exploring I have found a simple solution, but I think this answer should be improved to avoid any possible errors (i.e. precise error handling should be done to avoid cross-domain frames issue):
Sample Solution:
// first parameter is frame (window) in which to get sub frames
// second is the array to build on
function getAllFrames(frame, allFrameArray) {
allFrameArray.push(frame.frames);
for (var i = 0; i < frame.frames.length; i++) {
getAllFrames(frame.frames[i], allFrameArray);
}
return allFrameArray;
}
Usage:
var allFramesArray = getAllFrames(window, new Array());
console.log(allFramesArray.length); // number of frames in array
for (var i = 0; i < allFramesArray.length; i++) {
try {
console.log(allFramesArray[i].location.href); // location of first frame in array}
} catch (e) {
console.log('Error in Accessing Frame No.' + i); // location of first frame in array}
}
}
Here is another one (shortcut example)
var i = new Array;
function wow(a, n) {
t = '';
for (i[n] = 0; i[n] < a.length; i[n]++) {
try {
t += a[i[n]].name + ' \n';
} catch (e) {
t += 'Error \n';
}
if (a[i[n]].frames.length) t += wow(a[i[n]].frames, n + 1);
}
return t;
}
//Usage:
console.log(wow(top.frames, 0));
While browsing for a code, I recently have learnt a new code, using this code which takes a javascript window object as input and returns all its nested windows (including multiple levels of nesting). This function however is an efficient/elegant way that can be used to grab a reference to all the windows (objects) and all the child windows (objects). I have checked this function and found that it works well, it could be understood that making/writing this function completely recursively, as the DOM object tree is actually an n-ary, not binary.
function getAllNestedWindows(window) {
var windows = [window];
if (window.length === 0) {
return windows;
} else {
for (var i = 0; i < window.length; i++) {
windows = windows.concat(getAllNestedWindows(window[i]));
}
}
return windows;
}
I am using Jasmine for JS testing, and unfortunately I can't get the following test to pass.
it('should know the total game score', function() {
frame1 = new Frame;
frame2 = new Frame;
game = new Game;
frame1.score(3, 4);
frame2.score(5, 5);
expect(game.totalScore()).toEqual(17)
});
The error message I get is as follows: Error: Expected 0 to equal 17.
The code is as follows:
function Game() {
this.scorecard = []
};
Game.prototype.add = function(frame) {
this.scorecard.push(frame)
};
// Why is this not working!!???
Game.prototype.totalScore = function() {
total = 0;
for(i = 0; i < this.scorecard.length; i++)
{
total +=this.scorecard[i].rollOne + this.scorecard[i].rollTwo;
}
return total;
};
function Frame() {};
Frame.prototype.score = function(first_roll, second_roll) {
this.rollOne = first_roll;
this.rollTwo = second_roll;
return this
};
Frame.prototype.isStrike = function() {
return (this.rollOne === 10);
};
Frame.prototype.isSpare = function() {
return (this.rollOne + this.rollTwo === 10) && (this.rollOne !== 10)
};
Adding the numbers together manually seems to work e.g. total = game.scorecard[0].rollOne + this.scorecard[0].rollTwo , but the for loop (even though it looks correct) doesn't seem to work. Any help would be greatly appreciated :)
I am not pretty sure, but it seems that you are not calling the "Add" method, so no data is added to the scorecard.
You have to add the Frames to your game i guess
it('should know the total game score', function () {
frame1 = new Frame;
frame2 = new Frame;
game = new Game;
// those lines are missing
game.add(frame1);
game.add(frame2);
frame1.score(3, 4);
frame2.score(5, 5);
expect(17).toEqual(game.totalScore())
});
otherwise, the scorecard-array is empty and the total score is therefore equal to 0.
missing (so no data is added to the scorecard.)
game.Add(frame1);
game.Add(frame2);
I have code that creates an object array in a layer as shown below:
var labels = layer.get('Label');
var labelCount = labelLeft.length;
var tweens = [];
var tweenCounter = 1;
var duration=5;
for(var i=0; i<labelCount; i++)
{
var tween = new Kinetic.Tween({
node: labelLeft[i],
duration: animspeed[i],
x: 0,
onFinish: function() {
if (tweenCounter !== labelCount) { //Prevent an undefined tween from being played at the end
tweens[tweenCounter].play();
tweenCounter++;
}
}
});
tweens.push(tween);
}
tweens[0].play();
The problem is that I want to hide the object once done scrolling to left using onFinish. I tried using labelLeft[i].hide()
onFinish: function() {
labelLeft[i].hide();
if (tweenCounter !== labelCount) { //Prevent an undefined tween from being played at the end
tweens[tweenCounter].play();
tweenCounter++;
}
}
But this triggers TypeError: labelLeft[i] is undefined
Any ideas? Please help. Thanks
It seems as closure problem. Could you try this, I am not sure if it will work but anyway:
for(var i=0; i<labelCount; i++)
{
var label = labelLeft[i];
var tween = new Kinetic.Tween({
node: labelLeft[i],
duration: animspeed[i],
x: 0,
onFinish: function(l) {
return function()
hide(l);
}(label)
});
tweens.push(tween);
}
function hide(label) {
labelLeft[label].hide();
if (tweenCounter !== labelCount) { //Prevent an undefined tween from being played at the end
tweens[tweenCounter].play();
tweenCounter++;
}
}
Try to debug your code and check of i is defined.
I think its not because you are in a for loop and execute the code when the loop has finished. You easily can solve this problem with a anonymous function to induce a scope.
for(var i=0; i<labelCount; i++)
{
(function(i){
//put code here
}(i))
}