If clauses in for loop acts weird [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a function, which collects inputted answer and checked if collected answer is the same as it is the solution. Questions are asked randomly. Questions and solutions are in separate .txt file.
I have a file with some words and the program always fulfil its condition if the last word from the list is correctly answered, even though if other answers from other questions are correct.
Any suggestions?
var besedeNemske = ["glava", "voda", "drevo"];
var besedePrevod = ["der Kopf", "das Wasser", "der Baum"];
window.onload = function() {
var fileInput = document.getElementById('fileInput');
var fileDisplayArea = document.getElementById('fileDisplayArea');
fileInput.addEventListener('change', function(e) {
var file = fileInput.files[0];
var textType = /text.*/;
if (file.type.match(textType)) {
var reader = new FileReader();
reader.onload = function(e) {
var lines = this.result.split('\n');
for (var line = 0; line < lines.length; line++) {
if (line % 2 != 0) {
besedeNemske.push(lines[line]);
} else {
besedePrevod.push(lines[line]);
}
}
}
reader.readAsText(file);
} else {
fileDisplayArea.innerText = "File not supported!"
}
});
}
var random = 0;
function nastaviRandom() {
random = Math.floor(Math.random() * 5);
}
function noviGlagol() {
nastaviRandom();
document.getElementById("vprasanje").innerHTML = besedePrevod[random];
}
function preveriOdgovor() {
var odgovorjeno = document.getElementById("mojOdgovor").value;
if (besedeNemske.indexOf(odgovorjeno) == random) {
document.getElementById("odgovor").innerHTML = "Pravilni odgovor";
} else {
document.getElementById("odgovor").innerHTML = "Napačen odgovor. Pravilni odgovor je " + (besedeNemske[random]) + "";
}
}
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="page-wrapper">
<h1>Nemščina glagoli</h1>
<div>
Select a text file:
<input type="file" id="fileInput">
</div>
<pre id="fileDisplayArea"><pre>
<button onclick="noviGlagol()">Novi glagol</button>
<div id="vprasanje"></div>
<div id="odgovor"></div>
<input type="text" id="mojOdgovor">
<button onclick="preveriOdgovor()">Pošlji</button>
</div>
<script>
</script>
</body>
<html>

To submit the comments on the original question as an answer:
var index = 0;
for (var i = 0; i < besedeNemske.length; i++) {
if (odgovorjeno == besedeNemske[i]) {
index = i;
break;
}
}
index will be 0 for both of these cases:
if odgovorjeno == besedeNemske[0]
if odgovorjeno is not an element in the array besedeNemske
This is a really good use case for refactoring your code to use included language functionality or libraries, as it not only shortens your code, but is usually more correct (or at least their bugs are known/understood).
As Baramar pointed out, you can change your solution to:
function preveriOdgovor() {
var odgovorjeno = document.getElementById("mojOdgovor").value;
if (besedeNemske.indexOf(odgovorjeno) == random) {
document.getElementById("odgovor").innerHTML = "Pravilni odgovor";
} else {
document.getElementById("odgovor").innerHTML = "Napačen odgovor. Pravilni odgovor je " + (besedeNemske[random]) + "";
}
}

Related

I have trouble hiding elements in my game if they don't match

I am working on a memory game and I asked a previous question earlier which was answered. I've had this problem and I haven't been able to find a solution with effort. So it's a memory game and when the cards are clicked, they are pushed into an array which can hold two elements at max (you can only click two cards) and then the two elements' frontSrc is checked if they are the same. I set that using an expando property. If so, have them visible and then clear the array so I can do more comparisons. However, it doesn't seem to be working as intended. I'll attach a video below. I've tried using timeout to set the length again, but that didn't work. It works for the first cards, but the other ones after that, it doesn't work.
Here is my code.
<!DOCTYPE html>
<!--
Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license
Click nbfs://nbhost/SystemFileSystem/Templates/Other/html.html to edit this template
-->
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
.card{
width: 35%;
}
#cards{
display: grid;
grid-template-columns:25% 25% 25% 25%;
row-gap: 25px;
}
</style>
</head>
<body onload="init()">
<section id="cards">
</section>
<script>
var arrCards = [];
var arrShowedCards = [];
//appendElements();
function init(){
createCards();
shuffleCards();
appendElements();
}
function createCards(){
var arrCardNames = ["Mouse","Penguin","Pop","Mouse","Penguin","Pop"];
for(var i = 0; i<6; i++){
var card = document.createElement("IMG");
card.src = "Images/red_back.png";
card.className = "card";
card.frontSrc = "Images/" + arrCardNames[i] + ".png";
card.id = "card" + i;
card.addEventListener("click", showCard);
document.getElementById("cards").appendChild(card);
arrCards.push(card);
}
}
function shuffleCards(){
for (let i = arrCards.length-1; i > 0; i--)
{
const j = Math.floor(Math.random() * (i + 1));
const temp = arrCards[i];
arrCards[i] = arrCards[j];
arrCards[j] = temp;
}
return arrCards;
}
function appendElements(){
for(var i = 0; i<arrCards.length; i++){
document.getElementById("cards").appendChild(arrCards[i]);
}
}
function showCard(){
var sourceString = "Images/red_back.png";
this.src = this.frontSrc;
arrShowedCards.push(this);
if(arrShowedCards.length === 2){
if(arrShowedCards[0].frontSrc === arrShowedCards[1].frontSrc){
console.log("Match!");
arrShowedCards = [];
}
else{
console.log("No match!");
setTimeout(function(){
arrShowedCards[0].src = sourceString;
arrShowedCards[1].src = sourceString;
}, 1000);
}
}
}
</script>
</body>
</html>
I am not sure how come it doesn't work for it for the other cards.
Here is the video.
https://drive.google.com/file/d/1aRPfLALHvTKjawGaiRgD1d0hWQT3BPDQ/view
If anyone finds a better way to approach this, let me know.
Thanks!
I think when not match, you need to reset arrShowedCards otherwise its length will be greater than 2 forever.
function showCard() {
var sourceString = "Images/red_back.png";
this.src = this.frontSrc;
arrShowedCards.push(this);
if (arrShowedCards.length === 2) {
var a = arrShowedCards[0], b = arrShowedCards[1];
arrShowedCards.length = 0;
if (a.frontSrc === b.frontSrc) {
console.log("Match!");
} else {
console.log("No match!");
setTimeout(function () {
a.src = sourceString;
b.src = sourceString;
}, 1000);
}
}
}

How do I limit the amount of checkbox checked with JavaScript(no jquery please)

I'm making a Node Express multiple choice test, and each question has different amount of correct answers. I have my answers coming from a database auto-populate in PUG. However my Function doesn't work right, when I click over the limit of correct answers, the alert pops up but then the answer is checked anyways. What am I doing wrong?
I tried making a function that tracks how many answers checked, but can't get it to stop after it reaches the limit.
block content
header.header USA Government Test
main.q-card
p.q-promt #{question}
small (Please choose #{mcLimit} answers)
hr
each answer in answers
label.container
| #{answer.Answer_prompt}
input(type='checkbox' name='answer' onclick="ckLimit()")
span.checkmark
hr
script.
function ckLimit() {
var limit = #{mcLimit};
var total = 0;
var inputTag = document.getElementsByTagName('input');
var x = inputTag.length;
for (var i = 0; i < x; i++) {
if (inputTag[i].checked) {
total += 1;
}
if (total > limit) {
alert(`Please select only ${limit}`);
this.checked = false;
return;
}
}
}
everything works accept the: this.checked = false;
It continues to check answers. This what my code looks like now:
header.header USA Government Test
main.q-card
p.q-promt #{question}
small (Please choose #{mcLimit} answers)
hr
each answer in answers
label.container
| #{answer.Answer_prompt}
input(type='checkbox' name='answer' onclick="return ckLimit()")
span.checkmark
hr
script.
function ckLimit() {
var limit = #{mcLimit};
var total = 0;
var inputTag = document.getElementsByTagName('input');
var x = inputTag.length;
for (var i = 0; i < x; i++) {
if (inputTag[i].checked) {
total += 1;
}
if (total > limit) {
alert(`Please select only ${limit}`);
this.checked = false;
return;
}
}
}
Add return keyword to the below statement.
input(type='checkbox' name='answer' onclick="ckLimit()")
thus becoming
input(type='checkbox' name='answer' onclick="return ckLimit()")
Without return, onclick proceeds on allowing the default action of checking. Once onclick gets false value, it stops the action.
Edit:
In function ckLimit, return should return false.
if (total > limit) {
alert(`Please select only ${limit}`);
this.checked = false;
return false;
}

Animate array from user input like typewriter (javascript)

I suppose my question is a bit similar to this one, but I can't really work out how to do my specific need from it. I'm building a very basic text adventure, and I'd like the returned text - after the user has entered a command - to be returned in a typewriter style. Here's a snippet of my commands so far (there'll be a lot more, I don't mind that this will be built in a bit of a tedious way)
<script>
textIn = document.getElementById("input-textbox");
textOut = document.getElementById("output-textbox");
function process(input) {
if (input == "hi") { textOut.innerHTML += "Hello to you too!<br><br>"; }
else if (input == "exit") { textOut.innerHTML += "No."; }
}
function go() {
var input = textIn.value;
textIn.value = "";
var output = process(input);
textOut.value += output + "\n";
}
</script>
and the HTML
<div id="output-textbox">
Returned text goes here.
</div>
<form onSubmit="go();return false;">
<input id="input-textbox" name="command" value="" autofocus="autofocus"/>
</form>
Thank you so much for your help in advance! This solution doesn't need to be beautiful, code wise, nor very nifty. It just has to work, I have no standards at all with this!
Based on William B's answer, here is a more condensed version:
https://jsfiddle.net/sators/4wra3y1p/1/
HTML
<div id="output-typewriter"></div>
Javascript
function typewriterText(text) {
var outEl = document.querySelector('#output-typewriter');
var interval = 50; // ms between characters appearing
outEl.innerHTML = '';
text.split('').forEach(function(char, i){
setTimeout(function () {
outEl.innerHTML += char;
}, i * interval);
});
}
typewriterText('this is an example');
Create a timeout for each character inside a loop, with each timeout being a bit later than the last. See: https://jsfiddle.net/fswam77j/1/
var outputEl = document.querySelector('#output-textbox');
var charInterval = 50; // ms between characters appearing
function showOutput(text) {
outputEl.innerHTML = '';
for(var i = 0; i < text.length; i++) {
showChar(text, i);
}
}
function showChar(text, i) {
setTimeout(function () {
outputEl.innerHTML += text[i];
}, i * charInterval);
}
showOutput('this is an example');
process the input:
function process(input) {
if (input == "hi") {
showOutput("Hello to you too!");
}
else if (input == "exit") {
showOutput("No.");
}
}

File Size Validation on multiple upload with jquery

I have a multiple file upload input. I'm trying to validate the size for each file. It works kind of but depends on which order the files are selected. I hate javascript & I suck at it, please help.
http://jsfiddle.net/2u9kq7fe/1/
$('input[type="file"]').change(function(){
var imageSizeArr = 0;
var imageSize = document.getElementById('blah');
var imageCount = imageSize.files.length;
for (var i = 0; i < imageSize.files.length; i++)
{
var imageSize = imageSize.files[i].size;
if (imageSize > 5000000) {
$('#test').text('3');
var imageSizeArr = 1;
}
if (imageSizeArr == 1)
{
$('.element').text('files too big');
}
else if (imageSizeArr == 0)
{
$('.element').text('files not too big');
}
}
});
You are defining a reference to input field:
var imageSize = document.getElementById('blah');
and later in the for loop you redefine it again, because:
for (var i = 0; i < imageSize.files.length; i++) {
var imageSize = imageSize.files[i].size;
Remember that there is no block-scope in javascript, so var imageSize in the loop affects previously defined value.
This is your problem. Pick different name for size in the loop and it will work.
try like below example;
<input type="file" id="fileUpload" />
<input type="button" id="upload" value="Upload" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$(function () {
$("#upload").bind("click", function () {
if (typeof ($("#fileUpload")[0].files) != "undefined") {
var size = parseFloat($("#fileUpload")[0].files[0].size / 1024).toFixed(2);
alert(size + " KB.");
} else {
alert("This browser does not support HTML5.");
}
});
});
</script>
All credits go to #dfsq but as a js beginner it took me some time to figure out the vague description of what he meant with "Pick different name for size" so for all the confused ones here is the working code:
html:
<input type=file name=img[] id=files accept=".jpg, .JPG, .jpeg, .JPEG" multiple=multiple>
js:
$('input#files').change(function(){
var imageSizeArr = 0;
var imageArr = document.getElementById('files');
var imageCount = imageArr.files.length;
var imageToBig = false;
for (var i = 0; i < imageArr.files.length; i++){
var imageSize = imageArr.files[i].size;
var imageName = imageArr.files[i].name;
if (imageSize > 5000000){
var imageSizeArr = 1;
}
if (imageSizeArr == 1){
console.log(imageName+': file too big\n');
imageToBig = true;
}
else if (imageSizeArr == 0){
console.log(imageName+': file ok\n');
}
}
if(imageToBig){
//give an alert that at least one image is to big
window.alert("At least one of your images is too large to process, see the console for exact file details.");
}
});

unexpected output value from procedural code

I have this piece of javascript that won't work. It is supposed to take the user input and store it into the player input variable. Then, it splits the string that is returned and splits it into an array which is then converted into an object by the function oc(). Finally, the function analyzeUserInput finds keywords in the input object and places text into the paragraph element called text accordingly. In this example if the user types in slash, poke, slice, hack, etc and the word "sword" the paragraph element is supposed to say "you did 4 damage!" but it doesn't. here's the code:
<!DOCTYPE html>
<html>
<body>
<p>"oh no theres a monster whatchya gonna do?"</p>
<input id="plyrInput" type="text" />
<button onclick="analyzeUserInput()">Try it</button>
<p id="text"></p>
<script>
var plyrInput;
var plyrInputArray;
var plyrInputAnalysis;
function oc() {
plyrInputArray = plyrInput.split(' ');
var plyrInputObj = {};
for (var i = 0; i < plyrInputArray.length; ++i) {
plyrInputObj[plyrInputArray[i]] = ' ';
}
return plyrInputObj;
}
function analyzeUserInput() {
plyrInput = document.getElementById("plyrInput").text;
oc();
if (plyrInputAnalysis in oc(['use', 'slash', 'hack', 'wield', 'slice', 'sever', 'dismember', 'poke', 'cripple', 'maim', 'mutilate', 'chop', 'rend']) && plyrInputAnalysis in oc(['sword'])) {
document.getElementById("text").innerHTML = "You did 4 damage with your sword!";
}
}
</script>
</body>
</html>
var plyrInput;
var plyrInputArray;
var plyrInputAnalysis;
function oc() {
plyrInputArray = plyrInput.split(' ');
var plyrInputObj = {};
for (var i = 0; i < plyrInputArray.length; ++i) {
//storing these values in an object being blank is not really needed at all!
//plyrInputObj[plyrInputArray[i]] = ' ';
plyrInputObj[i] = plyrInputArray[i]; //acceptable or use the array itself!
}
return plyrInputObj;
}
function analyzeUserInput() {
//plyrInput = document.getElementById("plyrInput").text;//no such property as text
plyrInput = document.getElementById("plyrInput").value;
//you ran this function without storing it so we can't use it
//oc();
var plyrAction = oc();
//you call an undefined variable `plyrInputAnalysis`. So what are we going to do with it?
if (plyrInputAnalysis in oc(['use', 'slash', 'hack', 'wield', 'slice', 'sever', 'dismember', 'poke', 'cripple', 'maim', 'mutilate', 'chop', 'rend']) && plyrInputAnalysis in oc(['sword'])) {
document.getElementById("text").innerHTML = "You did 4 damage with your sword!";
}
}
Now for the fix:
var plyrInput;
var plyrInputArray;
var plyrInputAnalysis;
//added an acitonList for later usage for yourself
var actionList = {
'use':4,
'slash':4,
'hack':4,
'wield':4,
'slice':4,
'sever':4,
'dismember':4,
'poke':4,
'cripple':4,
'maim':4,
'mutilate':4,
'chop':4,
'rend':4
};
function oc() {
plyrInputArray = plyrInput.split(' ');
var plyrInputObj = {};
for (var i = 0; i < plyrInputArray.length; ++i) {
plyrInputObj[i] = plyrInputArray[i];
}
return plyrInputObj;
}
function analyzeUserInput() {
plyrInput = document.getElementById("plyrInput").value;
var plyrAction = oc(); //cached the returned value from oc
for(var item in plyrAction){ //looping through the plyrActions object
if(actionList[plyrAction[item]]){ //if there is a plyrAction that matches the actionsList we'll continue.
document.getElementById("text").innerHTML = "You did "+actionList[plyrAction[item]]+" damage with your sword!";
}
}
}
Though this could seems more complicated than it needs to be I went off your original methodology, you could create a better instance of this code for an RPG game, though it would be good to look into an IIFE to wrap this in and minimize a lot of the code instead of multiple functions.
For instance
function analyzeUserInput() {
plyrInput = document.getElementById("plyrInput").value;
var plyrAction = plyrInput.split(' ');
var plyrInputObj = {};
for (var i = 0; i < plyrAction.length; ++i) {
plyrInputObj[i] = plyrAction[i];
}
for(var item in plyrInputObj ){
if(actionList[plyrInputObj[item]]){
document.getElementById("text").innerHTML = "You did "+actionList[plyrInputObj[item]]+" damage with your sword!";
}
}
}

Categories