Search code examples
javascriptjquerycssshow-hidedynamic-html

How does one select the first element of a given class using jquery?


This is a debug question. I have googled the hell out of this, checked out jQuery's documentation on the first() selector, and read tons of stack overflow posts, but none of the tweaks I've made based on that research have worked.

GOAL: In the snippet below, I am trying to remove the class of 'hidden' from the first of a series of divs that were added to the dom using jquery at the top of the document.ready() event.

    $(document).on('click','#begin',function(){
        $('#intro').addClass('hidden');
        $('#form').removeClass('hidden');
        $('.question').first().css({'visibility':'hidden'});
    });

PROBLEM: For some reason, when I use the first() selector, all of the questions stay hidden. When I don't use it, as expected, all of the questions get revealed. These divs were added dynamically, using jQuery with the classes 'question' and 'hidden.'

The snippet above occurs in line 50 of the example code I am attaching. The declaration of those classes occurs at line 30.

/**
 * Created by davidgoldberg on 10/16/14.
 */

function Question(topic,question,choices,correctAnswer){
    this.topic = topic;
    this.question = question;
    this.choices = choices;
    this.correctAnswer = correctAnswer;
    this.userAnswer = null;
}

var allQuestions;
allQuestions = [
    new Question("Addition", "What is 8 + 8?", [16, 18, 64, 28], 16),
    new Question("Subtraction", "What is 23-8?", [16, 15, 14, 17], 15),
    new Question("Multiplication", "What is 8 * 8?", [16, 18, 64, 36], 64),
    new Question("Division", "What is 48/16", [3, "3/2", 4, "8/3"], 3),
    new Question("Imaginary Numbers", "What is \u221A(-1)^8?", ["i", "-i", 1, -1], 1)
];


function qToHTML(question) {
    var header = "<h2>" + question.topic + "</h2>";
    var qText = "<p>" + question.question + "</p>";
    var options = "";
    for (var i = 0; i < question.choices.length; i++) {
        options += "<input type='radio' name='" + question.topic + "' value ='" + question.choices[i] + "'>" + question.choices[i] + "<br>";
    }
    var wrapper = "<div class='question'></div>";

    var HTMLstring;
    HTMLstring = header + qText + options;
    $("form").append(HTMLstring).wrap(wrapper);
}



$(document).ready(function(){

    //set up page
    for(var i = 0; i < allQuestions.length; i++){
        qToHTML(allQuestions[i]);
    }
    $('form').append('<input type="submit" value="submit">');
    
    // setup intro
    $(document).on('click','#begin',function(){
        $('#intro').addClass('hidden');
        $('#form').removeClass('hidden');
        $('.question').first().css({'visibility':'hidden'});
    });
    
    // in-form navigation
    $('#next').on('click',function(){

    });

    //collect and check user answers
    $('form').on('submit', function(event) {

        var numCorrect = 0;

        event.preventDefault();

        for(var i = 0; i < allQuestions.length; i++) {

            // collect answers
            var currentQ = allQuestions[i];
            currentQ.userAnswer = $("input[name='" + currentQ.topic + "']:checked").val();

            // check answers
            if (currentQ.correctAnswer == currentQ.userAnswer) {
                numCorrect++;
            }
        }

        // show score
        var score = numCorrect + "/" + allQuestions.length;
        $('#results').find('p').text("You got " + score + " of the questions right");
        $('#results').removeClass('hidden');

        // resets buttons    
        $('input[type="radio"]').each(function(){
            $(this).prop('checked', false);
        });
    });
});
.hidden {
    display: none;
}
<!DOCTYPE html>
<html>
    <head>
        <title>Dynamic Quiz</title>
        <link rel="stylesheet" type="text/css" href="styles.css">
    </head>
    <body>
        <h1>Dynamic Quiz</h1>
        
        <div id='intro'>
            <h3>Get ready for the dynamic quiz</h3>
            <p>You will be asked a questions from a range of different math subjects.  Selecting an answer will bring you to the next page.  The 'next' and 'back' buttons do just what you expect.  When you are finished, click the 'submit' button at the bottom of the page, and you will be directed to your score.  When you are ready, click the 'begin' button below.</p>
            <input type="button" id="begin" value="begin">
        </div>

        <div id='form' class='hidden'>
            <form>
                    
                  <!-- <div class="question hidden">
                        <h2></h2>
                        <p></p>
                        <input type="radio" name="" value="">
                        <input type="radio" name="" value="">
                        <input type="radio" name="" value="">
                        <input type="radio" name="" value="">
                       
                        <input type="submit" value="submit">
                    </div> -->
                
            </form>
            <span id="nav-buttons">
                <button id="previous">previous</button>
                <button id="next">next</button>
            </span>

        </div>
        <div id="results" class="hidden">
            <h2>Results:</h2>
            <p></p>
        </div>

        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
        <script src="script.js"></script>
    </body>
</html>


Solution

  • One selects the first element in the class just as I did in the snippet above. The problem wasn't class selection mechanics--it was a bug in the javascript function that generates the questions.

    There was a bug that was preventing me from selecting the the first element in the class. In the function that follows this paragraph, the .wrap(wrapper) call wraps the "form" element in divs with class="question"--not the individual questions as I had intended.

    function qToHTML(question) {
        var header = "<h2>" + question.topic + "</h2>";
        var qText = "<p>" + question.question + "</p>";
        var options = "";
        for (var i = 0; i < question.choices.length; i++) {
            options += "<input type='radio' name='" + question.topic + "' value ='" + question.choices[i] + "'>" + question.choices[i] + "<br>";
        }
        var wrapper = "<div class='question'></div>";
    
        var HTMLstring;
        HTMLstring = header + qText + options;
        $("form").append(HTMLstring).wrap(wrapper);
    }
    

    Here is the revised function:

    function qToHTML(question) {

    var header = "<h2>" + question.topic + "</h2>";
    var qText = "<p>" + question.question + "</p>";
    var options = "";
    for (var i = 0; i < question.choices.length; i++) {
        options += "<input type='radio' name='" + question.topic + "' value ='" + question.choices[i] + "'>" + question.choices[i] + "<br>";
    }
    
    var HTMLstring;
    HTMLstring = header + qText + options;
    HTMLstring = "<div class='question hidden'>" + HTMLstring + "</div>";
    $("form").prepend(HTMLstring);
    

    }