Javascript function works for a while, then freezes the browser - javascript

I'm using this JS code to make a banner:
var images = ["../../images/g11.jpg","../../images/g9.jpg","../../images/g10.jpg"];
var titulos = ["title1","title2","title3"];
var resumos = ["ddd","aaa","bbb"];
var noticias = ["190","204","200"];
var total = 3;
var indice = 0;
function rotate() {
document.getElementById('imageb').src = images[indice];
document.getElementById('titulob').innerHTML = titulos[indice];
document.getElementById('resumob').innerHTML = resumos[indice];
document.getElementById('noticiab').value = noticias[indice];
indice++;
if (indice > total - 1) indice = 0;
}
function banner() {
rotate();
setTimeout(banner, 5000);
}
It works how expected, but after some loops it freezes the browser. Pretty sure I'm not using setTimeout properly. Any ideas?
Edit:
Working so far:
function rotate(indice) {
document.getElementById('imageb').src = images[indice];
document.getElementById('titulob').innerHTML = titulos[indice];
document.getElementById('resumob').innerHTML = resumos[indice];
document.getElementById('noticiab').value = noticias[indice];
}
function banner(indice) {
var f1 = function() { banner(indice); };
var total = 3;
rotate(indice);
indice++;
if (indice > total - 1) indice = 0;
setTimeout(f1, 5000);
}

I'm posting this as a CW because it's a total guess.
Completely FWIW, here's how I'd minimally change that code: Live Copy | Live Source
(function() {
var entries = [
{
img: "../../images/g11.jpg",
titulo: "title1",
resumo: "ddd",
noticia: "190"
},
{
img: "../../images/g9.jpg",
titulo: "title2",
resumo: "aaa",
noticia: "204"
},
{
img: "../../images/g10.jpg",
titulo: "title3",
resumo: "bbb",
noticia: "200"
}
];
var indice = 0;
function rotate() {
var entry = entries[indice];
document.getElementById('imageb').src = entry.img;
document.getElementById('titulob').innerHTML = entry.titulo;
document.getElementById('resumob').innerHTML = entry.resumo;
document.getElementById('noticiab').value = entry.noticia;
indice = (indice + 1) % data.length;
}
function banner() {
rotate();
setTimeout(banner, 5000);
}
banner();
})();
Changes:
Put everything in a scoping function to avoid creating global variables.
Use an array of objects rather than parallel arrays.
Use the array's length rather than a separate total variable.
Use the remainder trick for getting the wrap-around on the indice variable.
I added a call to banner(); at the end to get things started, but I assume you have that and just didn't show it.
But again, I don't see any reason your code shouldn't be working as is, other than the possibility of some weird global variable conflict.

Related

JQuery - How can I check my cards in memory game?

I have a course where I learn JS+JQuery and I have to write a memory game. I want to check if the turned cards are in the same classes so I can delete them and count the points, but I just cannot do it. I tried a lot of ways but I cannot figure it out.
I tried with .is(), === but nothing...
Here's my code:
let gameArea;
let size = 6;
let card_size = 600 / size;
let images = ['arbalest', 'armored', 'arms', 'cannoner', 'cataphract', 'cavalier', 'centurion', 'champion', 'composite',
'conquistador', 'eagle', 'heavy', 'heavyhorse', 'hussar', 'knight', 'legion', 'paladin', 'skirmisher'
];
$(function() {
gameArea = $('<div></div>');
gameArea.appendTo('body');
gameArea.attr('id', 'gameArea');
drawMap();
gameArea.on("click", "div", function(e) {
if ($(e.target).is(".unturned")) {
$(e.target).removeClass("unturned");
}
let unturnedCardNum = $("#gameArea").find("div:not(.unturned)").length;
if (unturnedCardNum === 3) {
$("#gameArea").find("div:not(.unturned)").addClass("unturned");
}
//I'd like to check here
});
});
function generate() {
let generatedImage = images[Math.floor(Math.random() * images.length)];
if ($("#gameArea").find(`.${generatedImage}`).length === 2) {
images = images.filter(function(e) {
return e !== generatedImage
});
generatedImage = generate();
}
return generatedImage;
}
function drawMap() {
for (let i = 0; i < size; i++) {
for (let j = 0; j < size; j++) {
let pic = $('<div></div>');
let shuffledImages = generate();
pic.addClass(shuffledImages);
pic.addClass("unturned");
pic.css({
width: card_size,
height: card_size,
top: i * card_size,
left: j * card_size
});
pic.appendTo(gameArea);
}
}
}
Assuming that the string in the images array will have been assigned to the associated card as a class name and that, after removing the "unturned" class, this will be the only class name left then maybe the following might help you:
Inside the $("#gameArea").on("click"...) function replace the lines
let unturnedCardNum = $("#gameArea").find("div:not(.unturned)").length;
if (unturnedCardNum === 3) {
$("#gameArea").find("div:not(.unturned)").addClass("unturned");
}
with
let unturnedCards = $("#gameArea").find("div:not(.unturned)");
switch(unturnedCards.length){
case 3:
unturnedCards.addClass("unturned");
break;
case 2:
if (unturnedCards[0].className===
unturnedCards[1].className){
console.log("you found a pair!");
// score[currentPlayer]++;
}
}
Further hint:
Instead of calling the generate() function recursively, you could simply shuffle an array made up of two copies of the images array by using a Fisher-Yates algorithm:
function shuffle(a,n){ // shuffle array a in place (Fisher-Yates)
let m=a.length;
n=n||m-1;
for(let i=0,j;i<n;i++){
j=Math.floor(Math.random()*(m-i)+i);
if (j-i) [ a[i],a[j] ] = [ a[j],a[i] ]; // swap 2 array elements
}
}

Replace and loop images after X milliseconds

I am having trouble getting this to work, I just want the images to loop endlessly. What isn't right here?
var croppingImages = new Array()
croppingImages[0] = "https://img.f1today.eu/x/topstory/58c7e187745517a1c90fc5ebe21c55da49223c999500b.jpg";
croppingImages[1] = "https://pbs.twimg.com/media/C69Y8aWW0AEkCIW.jpg:small";
setTimeout("animateImages()", 100);
var cropImg = 0;
function animateImages() {
document.getElementById("cropping__animation").src = croppingImages[cropImg]
x++;
}
<img src="https://img.f1today.eu/x/topstory/58c7e187745517a1c90fc5ebe21c55da49223c999500b.jpg" id="cropping__animation">
There are a couple of things here.
1) cropImg is never incremented, so animateImages will always show the same image
2) animateImages will only ever be called once by setTimeout
This code works better:
var cropImg = 0;
var croppingImages = new Array()
croppingImages[0] = "https://img.f1today.eu/x/topstory/58c7e187745517a1c90fc5ebe21c55da49223c999500b.jpg";
croppingImages[1] = "https://pbs.twimg.com/media/C69Y8aWW0AEkCIW.jpg:small";
animateImages();
function animateImages() {
document.getElementById("cropping__animation").src = croppingImages[cropImg];
if (++cropImg > croppingImages.length - 1)
{
cropImg = 0;
}
setTimeout(function() {
animateImages();
}, 3000);
}
https://jsfiddle.net/y6bhgm53/5/
if you want to loop them endless you maybe should use setInterval() and not setTimeout(). Also you should make it that your cropImg variable loops by checking if the value is greater than the array length.
https://jsfiddle.net/nyxeen/y6bhgm53/6/
I hope it helps
var croppingImages = new Array()
croppingImages[0] = "https://img.f1today.eu/x/topstory/58c7e187745517a1c90fc5ebe21c55da49223c999500b.jpg";
croppingImages[1] = "https://pbs.twimg.com/media/C69Y8aWW0AEkCIW.jpg:small";
setInterval(animateImages, 100);
var cropImg = 0;
function animateImages() {
document.getElementById("cropping__animation").src = croppingImages[cropImg]
cropImg++;
if(cropImg>=croppingImages.length)cropImg=0
}
<img src="https://img.f1today.eu/x/topstory/58c7e187745517a1c90fc5ebe21c55da49223c999500b.jpg" id="cropping__animation">

Using a Passed Dot-Notated Parameter as Property Accessor within a Function

I'm fairly certain this is a simple mistake, but I'm confused as to why this won't work. I've been unable to find any documentation on using multiple brackets in a row when accessing properties. This is part of my code that creates a link that when clicked runs the "dropItem" function:
var dropDest = "screwdriver";
var dropCat = "supplies.tools";
dropButton.onclick= function() {dropItem(dropCat, dropDest)};
The "dropItem" function:
var dropItem = function(category, droppedItem) {
player.inventory[category][droppedItem].amount = player.inventory[category][droppedItem].amount - 1; };
I get a "Cannot read property 'screwdriver' of undefined" error. How would one properly pass this? Both properties need to be variables for it to work. Is this an error due to multiple brackets?
EDIT:
I realized I forgot to include how the player object is structured, and this is critical for understanding why I needed to pass a dot-notated category:
var player = {
"health": 100,
"hydration": 100,
"hunger": 100,
"energy": 100,
"inventory": {
"supplies": {
"tools": {
"screwdriver": {
"amount": 0,
"condition": 0
}
},
"buldingMaterials": {
"wood": {
"amount": 0,
"condition": 0
}
}
},
"aidPacks": {
"healthPacks": 0
}
}
}
This is why I need to be able to access both player.inventory.supplies.tools and player.inventory.aidPacks.healthpacks with the same function.
You can make your code more generic and easier. This is useful when you have more than two categories - then you dont need to work with [0] and 1 - here is the code:
var player = { "inventory": { "supplies": { "tools" : { "screwdriver" : { "amount" : 1}}}}};
var dropDest = "screwdriver";
var dropCat = "supplies.tools";
function getProperty(obj, str) {
return str.split(".").reduce(function(o, x) { return o[x] }, obj);
}
function dropItem(category, droppedItem) {
var accessString = dropCat + "." + droppedItem;
getProperty(player.inventory, accessString).amount -= 1;
alert(getProperty(player.inventory, accessString).amount);
}
dropItem(dropCat, dropDest);
Here is the fiddle: https://jsfiddle.net/j7g0d8kz/3/
After looking at lightstalker89's code I realized that my issue was not the brackets, but rather the category that was being passed was not parsing the dot notation in the middle, thus staying as "supplies.tools" instead of separating fully. However, due to the way the player object is structured I needed to be able to pass dot notated categories, so I split the string:
var player = { "inventory": { "supplies": { "tools" : { "screwdriver" : { "amount" : 1}}}}};
var dropDest = "screwdriver";
var dropCat = "supplies.tools";
function dropItem(category, droppedItem) {
if(category.indexOf(".") > 0) {
var newCat = category.split(".");
var cat1 = newCat[0];
var cat2 = newCat[1];
player.inventory[cat1][cat2][droppedItem].amount = player.inventory[cat1][cat2][droppedItem].amount - 1;
alert(player.inventory[cat1][cat2][droppedItem].amount);
}else {
player.inventory[category][droppedItem].amount = player.inventory[category][droppedItem].amount - 1;
alert(player.inventory[category][droppedItem].amount);
}
}
dropItem(dropCat, dropDest);
Here's the JSFiddle: https://jsfiddle.net/j7g0d8kz/
Again, huge thanks to #lightstalker89 for making me realise my mistake.
How does your player object look like? Is it an empty object when you want to change the properties.
Basically you can use multiple brackets as you did.
If the player object does not have the needed properties, then your code should look like this:
var player = {};
var dropDest = "screwdriver";
var dropCat = "supplies.tools";
function dropItem(category, droppedItem) {
if(!player.inventory){
player.inventory = {};
}
if(!player.inventory[category]){
player.inventory[category] = {};
}
if(!player.inventory[category][droppedItem]){
player.inventory[category][droppedItem] = { amount: 0};
}
player.inventory[category][droppedItem].amount = player.inventory[category][droppedItem].amount - 1;
}
dropItem(dropCat, dropDest);
alert(JSON.stringify(player));
alert(player.inventory[dropCat][dropDest].amount);
Here is the fiddle: https://jsfiddle.net/csqbjnd7/1/
If the player object exists you can use multiple brackets. The code should then look like this:
var player = { "inventory": { "supplies.tools" : { "screwdriver" : { "amount" : 1}}}};
var dropDest = "screwdriver";
var dropCat = "supplies.tools";
function dropItem(category, droppedItem) {
player.inventory[category][droppedItem].amount = player.inventory[category][droppedItem].amount - 1;
}
dropItem(dropCat, dropDest);
alert(player.inventory[dropCat][dropDest].amount);
alert(JSON.stringify(player));
Here is the fiddle: https://jsfiddle.net/9o1949oz/2/

Javascript for loop doesn't work (adding numbers to a total)

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);

Javascript code not working properly(works for some time and crashes)

I've made a javascript slideshow for text but it gets bugged after a couple of loops.
This is what it should be like(don't mind the cursor in gif):
This is what happens after a couple of loops:
The Javascript code:
var quote_array = [
"Aš supratau, kad kuo daugiau dirbu,<br/>tuo labiau man sekasi.",
"Dirbdamas sau malonų darbą<br/>pasieki tobuliausių rezultatų.",
"Tikras darbas yra darbas<br/>kurio tu nemėgsti."
];
var quoteName_array = [
"-Tomas Džefersonas",
"-Aristotelis",
"-Bilas Watersonas"
];
var quote_i = Math.floor(Math.random()*quote_array.length);
var quote_elem;
var quoteName_elem;
var patikrinti
function quoteNext()
{
quote_i = Math.floor(Math.random()*quote_array.length);
if(patikrinti==quote_i)
{
quoteNext();
}
quote_elem.style.opacity = 0;
quoteName_elem.style.opacity = 0;
setTimeout("quoteSlide()",1100);
}
function quoteSlide()
{
patikrinti = quote_i;
quote_elem.innerHTML = quote_array[quote_i];
quoteName_elem.innerHTML = quoteName_array[quote_i];
quote_elem.style.opacity = 1;
quoteName_elem.style.opacity = 1;
setTimeout("quoteNext()",13900);
}
I didn't see the recurion at first, but in quoteNext() you're (randomly) calling quoteNext() a second time - which will add another setTimeout("quoteSlide()",1100) so over time more and more "loops" are running in parallel, leading to total flickering in the end. Change your function to
function quoteNext() {
quote_i = Math.floor(Math.random()*quote_array.length);
if (patikrinti==quote_i) {
quoteNext(); // try again
} else { // but do not continue
quote_elem.style.opacity = 0;
quoteName_elem.style.opacity = 0;
setTimeout(quoteSlide, 1100); // pass functions, not code strings
}
}

Categories

Resources