Store score in a variable after an event - javascript

Desirable result: After the user choose an answer, I want to modify score variable in:
score += 1 if the answer is right either not changing at all if the answer is wrong.
Current result: For every choice user is making, the score remains the same: 0.
First, I store the paragraph that will be changed in question_paragraph and the button that will be clicked by user in next_button. Also, I stored the value(I put the attribute value on every input using the array notation - 0 first, 1 second etc.) in user_answer.
var question_paragraph = document.getElementById('question');
var next_button = document.getElementById('next');
var i = 0;
var user_answer = getCheckedValue(document.getElementsByName('choice'));
var y = 0;
var score = 0;
The getCheckedValue function will return the value attribute of my input if exists.
function getCheckedValue(radioObj) {
var radioLength = radioObj.length;
for(var z = 0; z < radioLength; z++) {
if(radioObj[z].checked) {
return radioObj[z].value;
}
}
return "Error!";
}
Here is the problem. The function works fine, except the isolated area. allQuestion is my object where I stored the questions, the possible answers and the right answer, correctAnswer(I don't included it here but works correctly). I put a conditional statement to increase y and code>score with one if the allQuestions[y].correctAnswer is qual with the value of the user_choice.
function changeQuestion() {
//PROBLEM
if(allQuestions[y].correctAnswer == user_answer){
score += 1;
y++;
} else{y++;}
//PROBLEM
i = (i < allQuestions.length) ? (i + 1) : 0;
if (i == allQuestions.length) {
i = 0;
return question_paragraph.replaceChild(document.createTextNode(allQuestions[0].question), question_paragraph.firstChild);
}
var newNode = document.createTextNode(allQuestions[i].question);
console.log(score);
return question_paragraph.replaceChild(newNode, question_paragraph.firstChild);
}
Finnaly, I called the addHandler function.
function addHandler(name, type, handler){
if (name.addEventListener){
name.addEventListener(type, handler, false);
} else if (name.attachEvent){
name.attachEvent("on" + type, handler);
} else {
name["on" + type] = handler;
}
}
addHandler(next_button, 'click', changeQuestion);

Well, something just appears to be funny here so far. First of all, I don't see any initialization to the variable y. If y is a global variable that is retaining its value, then maybe there is an issue with your object: allQuestions{}. Could you provide the code for building your object allQuestions{}? Without it, I don't think that I could fully answer this question, but I believe that is where your problem lies.
Oops, this was supposed to be a comment, not an answer, sorry...

Related

Variable Set to undefined

I am fairly new to Javascript and i ran into a problem when creating a chess game . I have already made the board, but when i tried incorporating JS code that would move these peices when i clicked on them, a problem arose. See i declared the variable "x" to hold the value of the chess peice value that had been clicked on when count=0 but when i tried it out, the code just outputs x as 'undefined'.What have i done wrong, any help would be appreciated :)
(below is a snippet of my JS code)
<div onclick="changeText(63)"id="63"class="black">♘</div>
<div onclick="changeText(64)"id="64"class="white">♖</div>
</div>
<script>
var count = 0;
var x;
function changeText(id) {
if (count > 1){
count = 0;
}
if(count=0){
x = document.getElementById(id).innerHTML;
document.getElementbyId(id).innerHTML="";
}
if(count=1){
document.getElementById(id).innerHTML=x;
}
count = count + 1;
}
</script>
The second and third if statements will not be evaluating the variable value - because rather than comparison (count=== 0) what happens there is a variable assignment (count = 0).
The if (count = 0) is evaluated to false, so, the variable x never gets a value.
On the other hand if (count = 1) is evaluated to true. So, the HTML element gets an undefined string. Your code should look like this:
...
if (count === 0){
x = document.getElementById(id).innerHTML;
document.getElementbyId(id).innerHTML="";
}
if( count === 1){
document.getElementById(id).innerHTML=x;
}
Reference: https://www.w3schools.com/js/js_comparisons.asp
You don't need to pass the id to that handler function if it's doing the same thing. If you want a function that changes the innerHTML of the thing that was clicked, try passing event to the handler, and then using event.target.innerHTML like this:
<div onclick="changeText(event)" class="black">♘</div>
<div onclick="changeText(event)" class="white">♖</div>
<script>
function changeText(event) {
if (event.target.innerHTML === 'x') {
event.target.innerHTML = 'y' // you can do anything here
} else {
event.target.innerHTML = 'x'
}
}
</script>

How to change variable content getting the variable name from a data-attribute in a loop?

I have a loop that checks the content of an element's data-attribute and then uses this content to match it in a switch function. I want to simplify this code because the data-attribute value may vary in the next future and every time I have to add a case to the switch.
What I have now (this works fine):
var a = $('#el').attr('data-x'); // String
for (var i = 0; i <= 2; i++) {
switch (a) {
case "abc":
abc++; // variable initially set to 0
$('#abc').text(abc); // Overwrite the content with the new value
break;
case "dfg":
dfg++;
$('#dfg').text(dfg);
break;
[ ...Many cases like the ones listed here ]
}
if (i === 0) { a = $('#el').attr('data-x1')}
else if (i === 1) { a = $('#el').attr('data-x2');}
else if (i === 2) { a = $('#el').attr('data-x3');}
}
What I want to achieve is take the 'a' value, use the value taken as a var name and then work on the variable content.
EDIT: Mostly my need is a function non-depending from the cases, the way I've used in the code above it's ok for now but every 2 months I have to add another case to make it work. The question is: how can I change my code above to make it more "universal" and "elegant" in less line of code?
Something like:
var a = $('#el').attr('data-x');
for (var i = 0; i <= 2; i++) {
a++; // 'a' must be the name of the var, the name of the variable it's the same as $('#el').attr('data-x').
// So, 'a' var will change every time the function it's executed as in the switch version of the first block of code above (abc++ or dfg++).
$('#'+a).text(a);
if (i === 0) { a = $('#el').attr('data-x1')}
else if (i === 1) { a = $('#el').attr('data-x2');}
else if (i === 2) { a = $('#el').attr('data-x3');}
}
Here lies my problem: 'a' will be a string ('abc' for example), abc is a global var with the number needed to be incremented and placed in $('#abc'). Here we have for example:
abc = 0; (global var)
a = abc; (scoped var)
abc++; (abc === 1)
$('#abc').text(abc); (equivalent to $('#abc').text(1);)
So I need to call in the loop the 'a' value as the name of the global var, increment it, and then use 'a' as a jquery selector to text the value of the incremented global var inside it.
How can I do that?
If I understand what you need to do, you should try to use eval()
The eval() function evaluates JavaScript code represented as a string.
var a = $('#el').attr('data-x');
for (var i = 0; i <= 2; i++) {
eval(a + "++");
$('#'+a).text(eval(a));
if (i === 0) { a = $('#el').attr('data-x1')}
else if (i === 1) { a = $('#el').attr('data-x2');}
else if (i === 2) { a = $('#el').attr('data-x3');}
}

Counting unknown/dynamic array length of class element

I wrote a simple code/userscript to notify me about changes on a webiste:
function notifier(){
setTimeout(function () {
location.reload(true);
},60000)
}
function notiCounter() {
console.log("Counting notifications");
var noti = document.getElementsByClassName("notification");
for(var i = 0; i < 2; i++) {
if(noti[i].innerHTML != undefined) {
console.log(noti[i].innerHTML);
notifications++;
console.log("Notifications: " + notifications);
}
}
}
function notification(){
setTimeout(function () {
notiCounter();
if(notifications > 0){
document.title = "(" + notifications + ") new notifcations";
sound.play();
}
notifier();
},50)
}
notification();
The problem is, that the actual final number of noti[i] is unknown/dynamic and changes all the time, so if i < 2 is replaced with a higher number the for loop ends up in an infinite loop - and if I pick it too low (2 for example), data will gets lost if the actual number is above 2.
Any idea about that problem? Maybe it's really obvious and I can't see, as it is really late haha.
Rather than checking for i < 2, check for i < noti.length. Or you can iterate through using a for(var i in noti) type loop. Or better yet, if you just want the number of notifications directly, just use the value in noti.length

Unwanted return from JavaScript functions with DOM

I am designing a JavaScript function checkForm(), which is meant to check if at least half of the answers of a form have been completed. It returns ”true” if the condition is met and an alert message and ”false” if not. The answers are given in input text fields, whose content mustn't be the empty string in order to be regarded as answered.
In order to make the check, the function checkForm() calls two other functions: totalNumberOfQuestions() and totalCompletedAnswers(), as follows:
function totalNumberOfQuestions() /* Returns the total number of questions in the form */
{ total
numberOfQuestions = 0;
i = 1;
do
{
nameOfAnswer = 'answer_' + i;
if(document.getElementsByName(nameOfAnswer)[0] != null)
{
totalnumberOfQuestions ++;
}
i++;
}
while (document.getElementsByName(nameOfAnswer)[0] != null);
return totalnumberOfQuestions;
}
function totalCompletedAnswers() /* Returns the total number of completed answers in the form */
{
numberOfCompletedAnswers = 0;
i = 1;
for(i = 1; i<= totalNumberOfQuestions(); i++)
{
nameOfAnswer = 'answer_' + i;
if ( form[nameOfAnswer].value != '')
{
numberOfCompletedAnswers ++;
}
}
return numberOfCompletedAnswers;
}
function checkForm()
{
if ( totalCompletedAnswers() < 7 )
{
alert("Please answer at least half of the questions.");
return false;
}
return true;
}
But, surprisingly, the function checkForm() does not work correctly in this form, but returns true even when the number of completed answers is less than a half of the total number of answers. However, the function works properly if the function totalCompletedAnswers() is checked against a constant value, e.g.:
function checkForm()
{
if ( totalCompletedAnswers() < 7 )
{
alert("Please answer at least half of the questions.");
return false;
}
return true;
}
This means that using the function totalNumberOfQuestions() in the body of the checkForm() function is ”importing” some unwanted returned value. This happens even if I call the former separately (x= totalNumberOfQuestions() and then rewriting the condition: if ( totalCompletedAnswers() < x )
). Does anyone know how one can avoid such unwanted returned values when calling a function?
In totalComletedAnswers you have the snippet:
if(numberOfCompletedAnswers < totalNumberOfQuestions() )
{
alert("Please answer at least half of the questions.");
return false;
}
So totalCompletedAnswers will return false if all the answers are not completed not the number of questions answered.
In checkForm the the following will evaluate to true: false < 7
See: http://jsfiddle.net/5mURZ/
Have a look at these two articles for more information on truthiness/falsiness in javascript:
http://11heavens.com/falsy-and-truthy-in-javascript
http://www.sitepoint.com/javascript-truthy-falsy/
UPDATE
Upon closer inspection you have a scoping issue. All your variables have a global scope. This will cause the most issues with the variable i. Declaring the variable with the var key word will restrict the scope of the variable to the function. It is best practice in javascript to delvare all variable with the var keyword to explicitly declare the scope of the variable.
Working Fiddle: http://jsfiddle.net/Dr5Hx/1/
Article on scoping: http://coding.smashingmagazine.com/2009/08/01/what-you-need-to-know-about-javascript-scope/
Update 2
For a completely different approach, try the magic of jQuery. This approach relies on wrapping the answers in some kind of container. In this case a div. This is required as elements such as check boxes and radio buttons would be multiple elements, but each set should only be counted once.
//The selector below finds DOM elements with a name beginning with "answer"
var answers = $("[name^='answer']"); //'Cache' answers
var answerDivs = $("div").has("[name^='answer']"); //'Cache' answer divs
var totalAnswers = answerDivs.length; //'Cache' number of answers
$("#checkIt").click(function(){ //Add a click listener to the button
var numAnswered = $(answerDivs).filter(function(){ //Filter our answer divs to answered question
var answer = $(this).find("[name^='answer']"); //Get the answer element(s) in the div
var textCheck = $(answer).is("input:text") && $(answer).val() != ''; //Check For Text Value
var selCheck = $(answer).is("select") && $(answer).val() != ''; //Check for selected
var radioCheck = $(answer).is(":checked"); // Check for Checked, WOrks for radio & checkbox
//console.log($(answer).attr("name") + " " + textCheck + " " + selCheck + " " + radioCheck)
return (textCheck || selCheck || radioCheck); //End of the filter
}).length;
if(numAnswered < (totalAnswers/2))
{
alert("Please answer atleast half the questions");
return false;
}
alert("We're good to go");
return true;
});
Just make sure to wrap the above in $(document).ready();
http://jsfiddle.net/Dr5Hx/3/

Javascript accidental closure

I have this piece of code on my website which counts the number of image and then output a list each time the user clicks on desired category.
The problem is, my image counter variable (noIMG) does not clear itself every time the function is called. I tried adding a reset(noIMG) at the end of the function but it seemed like a bad idea.
I did some research and i've stumbled upon articles about closures. After trying numerous methods to fix it, my code is still not acting the way I want it to.
function thumbCounter(){
var noIMG = $(".artwork img").size()+1;
for (var count = 1; count < noIMG; count++){
if (count == 1){
$('#list_here').append('<li class="active">' +count+ '</li>');
} else{
$('#list_here').append('<li>' +count+ '</li>');
}
}
};
If you mean you want to clear the list every time the function is called, then do it like this:
function thumbCounter() {
var noIMG = $(".artwork img").size() + 1;
var myList = $('#list_here'); // reference to list
myList.html(""); // clear the contents
for (var count = 1; count < noIMG; count++) {
if (count == 1) {
myList.append('<li class="active">' +count+ '</li>');
} else {
myList.append('<li>' +count+ '</li>');
}
}
};

Categories