0

I am trying to create a simple question-answer "flash card" program. The user types what the word means in the opposite language. Everything is working fine, except for one thing:

When you click the button to go to the next level, it works fine. However, when you enter a correct answer, it goes back to level 1. Why is this? Is the next() function level parameter resetting itself back to 1? Please help!

fiddle

HTML:

  </head>

  <body>
    <h1>Spanish</h1>
    <div id="main">
      <h1 id="topic_name">Subject Pronouns</h1>
      <p>Type the word/phrase below in the opposite language</p>
      <p>If there is an accent or ~ above a letter, put ^ before that letter. Example: diecis^eis</p>
      <hr id="margin-bottom">
      <h1 id="question"></h1>
      <input id="answer_box"/>
      <button id="next"></button>
      <button id="answer">Show Answer</button>
    </div>

  </body>
</html>

JS:

$(document).ready(function(){

    var lvl1=
    [
      [["I"],["yo"]],
      [["you (formal)"],["usted"]],
      [["you (informal)"],["t^u"]],
      [["he"],["^el"]],
      [["she"],["ella"]],
      [["we (masculine)"],["nosotros"]],
      [["we (feminine)"],["nosotras"]],
      [["you all (formal)"],["ustedes"]],
      [["you all (informal)"],["vosotros"]],
      [["they (masculine or mixed)"],["ellos"]],
      [["they (feminine)"],["ellas"]],
      ];

  var lvl2=
  [
    [["yo"],["I"]],
    [["usted"],["you (formal)"]],
    [["t^u"],["you (informal)"]],
    [["^el"],["he"]],
    [["ella"],["she"]],
    [["nosotros"],["we (masculine)"]],
    [["nosotras"],["we (feminine)"]],
    [["ustedes"],["you all (formal)"]],
    [["vosotros"],["you all (informal)"]],
    [["ellos"],["they (masculine)"]],
    [["allas"],["they (feminine)"]],
    ];

  var lvl3=
  [
    [["yo soy"],["I am"]],
    [["tú eres"],["you (informal) are"]],
    [["él es"],["he is"]],
    [["ella es"],["she is"]],
    [["usted es"],["you (formal) are"]],
    [["nosotros somos"],["we are"]],
    [["vosotros sois"],["you all (informal) are"]],
    [["ellos/ellas son"],["they are"]],
    [["ustedes son"],["you all (formal) are"]],
    ];

  var lvl4=
  [
    [["I am"],["yo soy"]],
    [["you (informal) are"],["t^u eres"]],
    [["he is"],["^el es"]],
    [["she is"],["ella es"]],
    [["you (formal) are"],["usted es"]],
    [["we are"],["nosotros somos"]],
    [["you all (informal) are"],["vosotros sois"]],
    [["you all (formal) are"],["ustedes son"]],
    ];

    next(1);

  function next(level){
    random=(Math.floor(Math.random()*10));

    switch(level){
      case 1:
        question=lvl1[random][0];
        answer=lvl1[random][1];
        $('#next').text("Level 2");
        break;
      case 2:
        question=lvl2[random][0];
        answer=lvl2[random][1];
        $('#next').text("Level 3");
        break;
      case 3:
        random=(Math.floor(Math.random()*9));
        question=lvl3[random][0];
        answer=lvl3[random][1];
        $('#next').text("Level 4");
        break;
      case 4:
        var random=(Math.floor(Math.random()*8));
        question=lvl4[random][0];
        answer=lvl4[random][1];
        $('#next').text("Done");
        break;
      default:
        alert("switch error");
    }


    $('#question').text(question);



    $('#answer_box').keyup(function(){
      if($(this).val()==answer){
        $('#answer_box').attr("placeholder","");
        $('#answer_box').val("");
        next(level);
      }
    });



    $('#next').click(function(){
      next(level+1);
    });



    $('#answer').click(function(){
      $('#answer_box').attr("placeholder",answer);
    });


  }//function next

});//end

CSS:

#main{
  border:3px solid blue;
  height:500px;
  width:600px;
  top:50%;
  left:50%;
  position:fixed;
  margin-top:-230px;
  margin-left:-300px;
  border-radius:5%;
}

h1{
  text-align:center;
}


p{
  text-align:center;
}

#margin-bottom{
  margin-bottom:80px;
}

#next{
  display:block;
  margin:0 auto;
}

#answer_box{
  display:block;
  margin:0 auto;
  margin-bottom:20px;
}

#answer{
  display:block;
  margin:0 auto;
}
Blake Allen
  • 347
  • 1
  • 10

2 Answers2

2

The problem is failing to declare variables and creating a closure by accident.

question= and answer= are creating window properties of the same name because they have not been declared.

level is a formal parameter of function next and is first set to 1 by the statement next(1)

The click functions are declared as nested functions within next and access the value stored in the level parameter (creating a closure when next() returns). They are also reapplied to the button elements each time next is called.

Proposed solution: declare question answer and level variables within the "on ready" IIFE. Declare and apply button event handlers once, outside the call to next. Maintain level using explicit code.


Update with details:

Remove

 next(1);

And replace with variable definitions and a call to next() with no parameter. Level is being maintained outside of the next function.

var question = "";
var answer = "";
var level = 1;
next();

Remove the level parameter from function next(level)... and replace with

function next(){
random=(Math.floor(Math.random()*10));

switch(level){
  case 1:
    question=lvl1[random][0];
    answer=lvl1[random][1];
    $('#next').text("Level 2");
    break;
  case 2:
    question=lvl2[random][0];
    answer=lvl2[random][1];
    $('#next').text("Level 3");
    break;
  case 3:
    random=(Math.floor(Math.random()*9));
    question=lvl3[random][0];
    answer=lvl3[random][1];
    $('#next').text("Level 4");
    break;
  case 4:
    var random=(Math.floor(Math.random()*8));
    question=lvl4[random][0];
    answer=lvl4[random][1];
    $('#next').text("Done");
    break;
  default:
    alert("switch error");
}

$('#question').text(question);


}//  end of function next body

This is largely the same as the code posted, but move keyup and next button handlers to follow function next body; don't define them inside it:

$('#next').click(function(){
   level = level + 1;  // increase level
   next();
});

$('#answer_box').keyup(function(){
  if($(this).val()==answer){
    $('#answer_box').attr("placeholder","");
    $('#answer_box').val("");
    next();  // stay on current level
  }
});

I haven't put code in to handle what happens when you click the next button when "done" is showing. The closure you asked about is created by registering keyup and click handler anonymous functions created inside the next function: the anonymous functions look for variable and parameter definitions within next, corresponding to their value when the anonymous function was created. If you are unfamiliar with the concept, please do a search on closures in javascript.

traktor
  • 17,588
  • 4
  • 32
  • 53
  • Thank you, but I have some questions: 1) If I put the button click functions outside of the next() function, how would the #next click function know what level to go to next (what argument of 1-4 should it pass to next())? Or how would the #answer click function know what answer to display? These variables that they would need would not be in their scope. Is this what you mean by explicit code? 2) What do you mean when you say that returning next() "creates a closure"? – Blake Allen Sep 22 '16 at 02:09
  • See [this community wiki](http://stackoverflow.com/a/111111/1848578) for info on closures. – qxz Sep 22 '16 at 02:56
  • Wow, thanks so much for the detailed answer! The concept of defining those variables outside of the `next` function, and then **doing** stuff with them inside of it will help me in many future projects. I'm beginning to more fully understand inheritance and object-oriented programming. – Blake Allen Sep 22 '16 at 03:04
0

Every call next function will to register event for #next、#answer_box and '#answer,Are you sure this is what you want?just because of this will be a problem,Your problem is not all