1

What I am doing is making an mini game where users can drag and drop "magnets" (actually images) of words to create active writing sentences. In order to evaluate if the sentence is correct I made a data attribute "data-spot" in the drop area divs and I made a data attribute "data-word" on the images. If the word contained in "data-word" matches the the word contained in "data-spot" then it is a match. This evaluation occurs on button click "check my work". Right now I've made a function that should check if the magnets are matching for sentence one and if they are all match it should add 1 to the score.

My problem is that I'm getting "wordpuzzle.js:27 Uncaught ReferenceError: $this is not defined". I have checked and my links to jquery are at the bottom of my html and my javascript file is linked below the jquery files so that's not the problem. I think the issue is the logic I use to select the attribute values under the //on submit click in my jquery but I've checked and I have not made any typos...

<!doctype html>
<html lang="en">
<head>

<title>PR Active Writing</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" href="css/wordpuzzle2.css">
<link href='https://fonts.googleapis.com/css?family=Yesteryear' rel='stylesheet' type='text/css'>

</head>
<body>
<image src="images/PR-Active-Writing-Whiteboard.png" alt="whiteboard picture" id="backgroundimage"/>
<div id="startmessage">
    <h1>Welcome to the PR Active Writing Game</h1>
    <h2>Instructions</h2>
    <div>For clear, concise and strong sentences, PR writers use the active voice.
     When you click on the ‘begin’ button you will be shown a sentence that is 
     written in passive voice, your task is to rearrange the words to change the 
     sentence to active voice. There is a word bank to choose extra or different 
     words from. Simply drag the words into their correct spot and when you are 
     satisfied with your answer click the ‘Check my work’ button.
    </div>
    <button id="startactive">BEGIN</button>
</div>
<div id="wordbank">
<h1>Word Bank:</h1>
<image src="images/magnet-broken.png" alt="broken" data-word="broken" class="magnet"/>
<image src="images/magnet-city.png" alt="city" data-word="city" class="magnet"/>
<image src="images/magnet-did.png" alt="did" data-word="did" class="magnet"/>
<image src="images/magnet-distroyed.png" alt="destroyed" data-word="destroyed" class="magnet"/> <!--typo in the word "destroyed"-->
<image src="images/magnet-fixed.png" alt="fixed" data-word="fixed" class="magnet"/>
<image src="images/magnet-for.png" alt="for" data-word="for" class="magnet"/>
<image src="images/magnet-give.png" alt="give" data-word="give" class="magnet"/>
<image src="images/magnet-half.png" alt="half" data-word="half" class="magnet"/>
<image src="images/magnet-house.png" alt="house" data-word="house" class="magnet"/>
<image src="images/magnet-instructions.png" alt="instructions" data-word="instructions" class="magnet"/>
<image src="images/magnet-Mike.png" alt="Mike" data-word="Mike" class="magnet"/>
<image src="images/magnet-of.png" alt="of" data-word="of" class="magnet"/>
<image src="images/magnet-over.png" alt="over" data-word="over" class="magnet"/>
<image src="images/magnet-professor.png" alt="professor" data-word="professor" class="magnet"/>
<image src="images/magnet-profit.png" alt="profit" data-word="profit" class="magnet"/>
<image src="images/magnet-projects.png" alt="projects" data-word="projects" class="magnet"/>
<image src="images/magnet-Sam.png" alt="Sam" data-word="Sam" class="magnet"/>
<image src="images/magnet-sells.png" alt="sells" data-word="sells" class="magnet"/>
<image src="images/magnet-students.png" alt="students" data-word="students" class="magnet"/>
<image src="images/magnet-the.png" alt="the" data-word="the" class="magnet"/>
<image src="images/magnet-the2.png" alt="the" data-word="the" class="magnet"/>
<image src="images/magnet-the3.png" alt="the" data-word="the" class="magnet"/>
<image src="images/magnet-The4.png" alt="The" data-word="The" class="magnet"/>
<image src="images/magnet-The5.png" alt="The" data-word="The" class="magnet"/>
<image src="images/magnet-their.png" alt="their" data-word="their" class="magnet"/>
<image src="images/magnet-thesis.png" alt="thesis" data-word="thesis" class="magnet"/>
<image src="images/magnet-watch.png" alt="watch" data-word="watch" class="magnet"/>
<image src="images/magnet-well.png" alt="well" data-word="well" class="magnet"/>
<image src="images/magnet-wildfire.png" alt="wildfire" data-word="wildfire" class="magnet"/>
<image src="images/magnet-will.png" alt="will" data-word="will" class="magnet"/>
<image src="images/magnet-you.png" alt="you" data-word="you" class="magnet"/>
<image src="images/magnet-your.png" alt="your" data-word="your" class="magnet"/>

</div>
<div id="sentences">
<h1>Sentences:</h1>
<p>The thesis projects were done well by the students.</p>
<div id="senone"><div class="mdroppable" data-spot="The"> </div> <div class="mdroppable" data-spot="students"> </div> <div class="mdroppable" data-spot="did"> </div> <div class="mdroppable" data-spot="their"> </div> <div class="mdroppable" data-spot="thesis"> </div> <div class="mdroppable" data-spot="projects"> </div> <div class="mdroppable" data-spot="well"> </div></div>
<p>More than half of the city was destroyed by the wildfire.</p>
<div id="sentwo"><div class="mdroppable" data-spot="The"> </div> <div class="mdroppable" data-spot="wildfire"> </div> <div class="mdroppable" data-spot="destroyed"> </div> <div class="mdroppable" data-spot="over"> </div> <div class="mdroppable" data-spot="half"> </div> <div class="mdroppable" data-spot="of"> </div> <div class="mdroppable" data-spot="the"></div><div class="mdroppable" data-spot="city"></div></div>
<p id="senthree">Instructions will be given to you by your professor.</p>
<p id="senfour">The broken watch was fixed by Mike.</p>
<p id="senfive">The house was sold for a profit by Sam.</p>
<button id="checkmywork">CHECK MY WORK</button>
</div>

  <div id="successmessage">
    <p id="success1">Excellent job! You got 4-5 answers correct! Here are the correct sentences.</p>
    <p id="success2">Not bad! You got 2-3 answers correct! Here are the correct sentences.</p>
    <p id="success3">You might want to brush up on your active writing before considering Public relations. You got 0-1 answers correct. Here are the correct sentences.</p>
  </div>

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.9/jquery-ui.min.js"></script>
<script type="text/javascript" src="js/wordpuzzle.js"></script>
</body>
</html>

this is my jquery:

$(document).ready(function(){
var pruserScore = 0;
$("#successmessage").hide();
$("#sentences").hide();

$("#startactive").click(function(){
$("#startmessage").hide();
$("#sentences").show();
}) 


//makes the magnets draggable
$( dragmagnet );
function dragmagnet() {
$(".magnet").draggable({
snap: ".mdroppable",        
cursor: 'move'
});
}

//makes underline areas droppable
$(".mdroppable").droppable();

//on submit click 
$("#checkmywork").click(function(){
$(".mdroppable").each(function(){
    if ($("#senone .mdroppable").attr('data-spot',$(this).val()) === $(".magnet").attr("data-word",$this.val())){
    pruserScore += 1; 
    console.log(pruserScore);
    }
    else{console.log("it's wrong");}
    });
})
});
G.H
  • 23
  • 3
  • 3
    `$(this)` not `$this`??? I don't see anywhere `$this` defined in your code... And just be aware than your game would be easy to hack but i guess you made it just for entertaining purpose. EDIT: i see anyway your check condition is wrong, comparing `attr()` setter, which return jq matched set, not attribute value – A. Wolff Jul 19 '16 at 15:11

2 Answers2

0

It appears that you forgot to wrap this in parens. This will correct the error:

if ($("#senone .mdroppable").attr('data-spot',$(this).val()) === $(".magnet").attr("data-word",$this.val())){
                                                   // need to change this ------------------------^

But more importantly, .attr(key, value) is a setter invocation, not a getter as you may be looking for. You probably don't need the $(this).val() at all.

Will
  • 2,163
  • 1
  • 22
  • 22
  • 1
    That is only a minor error in a much larger spectrum of issues with this code. – mhodges Jul 19 '16 at 15:31
  • Yep I've still got so much to learn. But if you are going to comment on stuff it's more helpful to be constructive with your criticism. – G.H Jul 19 '16 at 15:45
  • @G.H Yes, I am working on making the entirety of your code work as we speak. I just got it working, I will post an answer in a minute. Be patient ;) – mhodges Jul 19 '16 at 15:46
  • Oh! My bad, I misinterpreted you. – G.H Jul 19 '16 at 15:48
0

Okay, so as I mentioned in comments, there were several issues with this code ranging from logic to syntactic.

1) The first, and most obvious is the error that your javascript was throwing and that was that you did not wrap $this in parentheses. The correct syntax is $(this). You seem to be using it fine elsewhere, so that is just a simple typo.

2) You were using the setter function for .attr() in your comparison, which is not what you want to do. To compare two .attr() values against one another, the code should look like this:

$(".elem1").attr("data-attribute") === $(".elem2").attr("data-attribute")

3) Even if you got those things syntactically correct, your code still would not work as intended because you are never tying a single magnet value to a single data spot. For example, if you changed your code to the following:

// NOT WORKING
$(".mdroppable").each(function(){
    if ($(this).attr('data-spot') === $(".magnet").attr("data-word")){
      pruserScore += 1; 
      console.log(pruserScore);
    }
    else{
      console.log("it's wrong");
    }
});

If you think about what this is doing, it is taking the data-spot attribute of the current .mdroppable (which is what you want). HOWEVER, $(".magnet") is returning you the array of ALL magnets. Calling .attr() on an array of jQuery elements will only return you the .attr() for the FIRST ITEM in the array. So you are always comparing against the word "broken" in this case.

So, the question then begs.. well how do you get it to look at the single .magnet that is dropped on the current .mdroppable in the .each() loop?

The answer is, there are a ton of ways that you can do it. I chose to do it by storing a correct/incorrect value in an internal data attribute (this is why I chose .data() over .attr()). So, when the element is dropped onto a draggable area, that is when it does the correct/incorrect checking. It sets the data attribute, and then the check work button simply iterates through and looks at the new data attribute.

The code looks like this:

  //makes the magnets draggable
  $( dragmagnet );
  function dragmagnet() {
    $(".magnet").draggable({
      snap: ".mdroppable",        
      cursor: 'move',
    });
  }
  $("#wordbank").droppable();
  //makes underline areas droppable
  $(".mdroppable").droppable({
    out: function (event) {
      $(this).data("correct", "false");
    },
    drop: function (event, ui) {
      if ($(this).data("spot") === ui.draggable.attr('data-word')) {
        $(this).data("correct", "true");
      }
      else {
        $(this).data("correct", "false");
      }
    }
  });

  //on submit click 
  $("#checkmywork").click(function(){
    pruserScore = 0;
    $(".mdroppable").each(function(){
      if ($(this).data('correct') === "true"){
        pruserScore += 1; 
        console.log(pruserScore);
      }
      else{
        console.log("it's wrong");
      }
    });
  });

HERE IS A WORKING DEMO

Anyway, I hope this helps you better understand what is going on and why your approach was slightly off. If you have any more questions, please feel free to ask! I tried to keep this as short as possible, but it's already a novel ;)

Community
  • 1
  • 1
mhodges
  • 10,938
  • 2
  • 28
  • 46
  • thank you for explaining that attr() calls an array of jquery elements! That explains some stuff that was happening earlier. You thinking is very easy to follow and your explanation is logical. Thanks a bunch! – G.H Jul 19 '16 at 16:19
  • You're welcome! =) I also just updated the demo to reset the correct/incorrect flag when they drag the word out of the drop zone. Also, a much better (and safer) way to implement the correct/incorrect flag would be using the .data() function instead of .attr("data-*"). This will set an internal data attribute that is not visible or editable in the DOM. Changing the demo again to include that change. – mhodges Jul 19 '16 at 16:22