1

The title is self-explanatory, I tried using .checked(and several other methods that also failed), but it did not work.

I want to know how, so I can count the score for a quiz.

Here is the html part for it:

<html>
    <head lang=pt>
       <meta charset="utf-8">
        <title>Formulario</title>
        <link rel="stylesheet" type="text/css" href="quiz1.css">
        <script src=quiz.js></script>
    </head>    
    <body>        
            <form class=formulario onsubmit="return mostrar_placar()"> 
                <h3 id = "pergunta">Qual é o nome do inventor da linguagem de programação Python?<br></h3>
                <input class = "escolhas" id ="0" type="button" value="Guido van Rossum" onclick="keep_highlighted('0')"><br> 
                <input class = "escolhas" id ="1" type="button" value="Dennis Ritchie" onclick="return keep_highlighted('1')"><br> 
                <input class = "escolhas" id ="2" type="button" value="James Gosling" onclick="return keep_highlighted('2')"><br>
                <input class = "escolhas" id ="3" type="button" value="Brendan Eich" onclick="return keep_highlighted('3')"><br>                
                <h3 id = "pergunta">Dentre as alternativas a seguir, qual não é um item de hardware?<br></h3>
                <input class = "escolhas" id ="4" type="button" value="Mouse" onclick="return keep_highlighted('4')"><br> 
                <input class = "escolhas" id ="5" type="button" value="Processador" onclick="return keep_highlighted('5')"><br> 
                <input class = "escolhas" id ="6" type="button" value="Chipset" onclick="return keep_highlighted('6')"><br>
                <input class = "escolhas" id ="7" type="button" value="Debian" onclick="return keep_highlighted('7')"><br><br>                    
                <input type="submit" value="confirmar">
        </form>           
    </body>
</html>

And this is the js:

var certos = ["0", "7"];


function keep_highlighted(id) {
    document.getElementById(id).style.background = "white";
    document.getElementById(id).style.color = "black";
}

function placar() {
    var placar = 0;
    for (var i = 0; i < 8; i++) {
        console.log(document.getElementById(i.toString()).checked);
        if (document.getElementById(i.toString()).checked) {
            if (document.getElementById(i.toString()).value == certos[i]) {
                placar += 1;
            }
        }
    }
    return placar;

}

function mostrar_placar() {
    alert("Seu placar é " + placar());
}

The console is only printing 8 falses no matter what I click(showing that its never checked). So it never enters in the condition that counts the score (without if (document.getElementById(i.toString()).checked) it always shows 2 on the score since it loops through all the buttons even the ones not selected). And with it always shows the score as 0....can someone help?

isherwood
  • 58,414
  • 16
  • 114
  • 157
Mateus
  • 47
  • 1
  • 3
  • 6
  • 5
    input type button is not a checkbox – George Mar 12 '18 at 19:55
  • 3
    A button element will *never* be "checked". – Pointy Mar 12 '18 at 19:55
  • Ah so how I see if it's highlighted, do I really have to change the type to =radio?. I really didn't want to do that – Mateus Mar 12 '18 at 19:57
  • it is highlighted because you are setting `.style.background = "white";` on click. Since you are doing it this way, without storing state in some object. Check if the button style is white to tell whether it is "checked". – George Mar 12 '18 at 19:58
  • Buttons never get `checked`. You should be using `input type=radio`. – Scott Marcus Mar 12 '18 at 19:59

5 Answers5

4

Buttons should not be used to signify an answer unless they are part of a group of choices. Then, you have to decide if only one item from the group should be allowed to be selected or if multiple items are allowable. This is exactly what checkboxes and radio buttons are for.

Now, you don't have to show the user checkboxes or radio buttons - you can show them something that looks like a button instead, but the "buttons" need to behave either like checkboxes or radio buttons. This can be accomplished by actually using checkboxes or radio buttons, but hiding those and, instead, showing label elements that are tied to the hidden items.

Then, in your JavaScript, you can access the actual checkboxes and radio buttons as you normally would.

Here is an example of using hidden checkboxes so that multiple "button" elements can be selected:

document.getElementById("getChecked").addEventListener("click", function(){
   // Gather up all the checked checkboxes into an Array;
   var checkedCheckboxes =
      Array.prototype.slice.call(document.querySelectorAll("input[type='checkbox']:checked"));
      
   // Set up result array
   var result = [];
   
   // Loop over them and add selected values to array
   checkedCheckboxes.forEach(function(checkbox){
     result.push(checkbox.value); 
   }); 
   
   // Clear old output and log new results
   console.clear();
   console.log(result);
});
/* Hide the checkboxes */
input[type='checkbox'] { display:none; }

/* Default styling for labels to make them look like buttons */
input[type='checkbox'] + label {
  display:inline-block;
  box-shadow:1px 1px grey;
  border-radius:3px;
  background-color:#e0e0e0;
  padding:5px;
  font-family:Arial, Helvetica, sans-serif;
  cursor:pointer;
}

/* Styling for labels when corresponding checkbox is checked */
input[type='checkbox']:checked + label {
  box-shadow:-1px -1px grey;
  background-color:#f78d32;
}
<input type="checkbox" id="chk1" name="chk1" value="choice 1">
<label for="chk1">Choice 1</label>

<input type="checkbox" id="chk2" name="chk2" value="choice 2">
<label for="chk2">Choice 2</label>

<input type="checkbox" id="chk3" name="chk3" value="choice 3">
<label for="chk3">Choice 3</label>

<p><button id="getChecked">Get the checked checkbox values</button></p>

Using radio buttons, so that only one "button" can be selected, is almost identical, except for the HTML uses input type=radio and the CSS and JavaScript selectors change to find those radio buttons. Also, since only one radio button can ever be selected (within any given group), there's no need to gather up all the checked radio buttons (from one group) into an array. There will just be one checked button.

document.getElementById("getChecked").addEventListener("click", function(){
   // Get the one radio button (within its group) that is checked:
   var checkedRadio = document.querySelector("input[type='radio'][name='rad']:checked");
   
   // Clear old output and log new results
   console.clear();
   console.log(checkedRadio.value);
});
/* Hide the checkboxes */
input[type='radio'] { display:none; }

/* Default styling for labels to make them look like buttons */
input[type='radio'] + label {
  display:inline-block;
  box-shadow:1px 1px grey;
  background-color:#e0e0e0;
  padding:5px;
  border-radius:3px;
  font-family:Arial, Helvetica, sans-serif;
  cursor:pointer;
}

/* Styling for labels when corresponding radio button is checked */
input[type='radio']:checked + label {
  box-shadow:-1px -1px grey;
  background-color:#f78d32;
}
<input type="radio" id="rad1" name="rad" value="choice 1">
<label for="rad1">Choice 1</label>

<input type="radio" id="rad2" name="rad" value="choice 2">
<label for="rad2">Choice 2</label>

<input type="radio" id="rad3" name="rad" value="choice 3">
<label for="rad3">Choice 3</label>

<p><button id="getChecked">Get the checked radio button value</button></p>
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • With type='radio', when a second button is clicked, the previously clicked one is automatically deselected. It still works that way with type='button' but the 1st highlight stays even after the second choice is highlighted, confusing the user, who has no way to unhighlight (he wouldn't know it had actually been deselected. – John Biddle Jan 17 '19 at 00:22
  • @JohnBiddle I'm not sure what you are getting at. I'm not showing `type='button'`, nor am I advocating that approach. In fact, my entire answer explains why `type='button'` should not be used for this use case. – Scott Marcus Jan 17 '19 at 01:19
  • When I ran your code snipet iand clicked on one button and then another, they both stayed highlighted. – John Biddle Jan 17 '19 at 02:47
  • @JohnBiddle That happens with the first of my code snippets and it is supposed to. That example uses checkboxes behind the scenes (not buttons) and with checkboxes, you can have more than one selected. If you click one of the selected buttons a second time, it will de-select, just as a checkbox would. – Scott Marcus Jan 17 '19 at 03:22
  • @JohnBiddle If you read my answer, you would see the just prior to that example, I wrote ***Here is an example of using hidden checkboxes so that multiple "button" elements can be selected:*** – Scott Marcus Jan 17 '19 at 03:24
  • @JohnBiddle After reading the first example, go check the second, which uses Radio Buttons and implements mutual exclusivity. – Scott Marcus Jan 17 '19 at 03:25
0

"Ah so how I see if it's highlighted..."

It appears that you want to know if the button is highlighted, which basically is to say that it's the element that is "active" or has focus. You can get this via document.activeElement.

Here's a demo that shows the active element change with clicks on the body.

document.body.onclick = function() {
  console.log(document.activeElement);
};
html, body { height: 100%; }
<button>button</button>
<input placeholder="click in here">

However, you're asking about your solution instead of fully explaining the problem. I don't know how this relates to scoring a quiz, so it could be that you need something very different.

0

An input button cannot be "checked" in itself. You have a few options for how to handle this though. You could change the elements to a form with radio buttons or checkbox buttons. However, if you want to keep the buttons you could also do something in the javascript keep_highlighted method when the button is clicked such as:

if (document.getElementById(id).classList.contains("checked")) {
    document.getElementById(id).classList.remove("checked");
} else {
    document.getElementById(id).classList.add("checked");
}

and you can get this list of "checked" buttons by using:

document.getElementsByClassName("checked");

This will toggle the "checked" class on the element, which you can get a list of elsewhere in your javascript, such as wherever your submit button directs to

EDIT: Also, you could move your button styling into these if blocks so that you could "toggle" the buttons to be highlighted or not based on them being clicked and users could also "uncheck" a selection.

Alex DeCamillo
  • 345
  • 4
  • 18
0
document.getElementById(id).setAttribute("checked","");
document.getElementById(id).removeAttribute("checked");
Arghya Sadhu
  • 41,002
  • 9
  • 78
  • 107
Denice
  • 1
  • 1
    Welcome to Stack Overflow. Code-only answers are discouraged on Stack Overflow because they don't explain how it solves the problem. Please edit your answer to explain what this code does and how it improves of the existing upvoted answers, so that it is useful to the OP as well as other users with similar issues. – FluffyKitten Aug 21 '20 at 19:28
-1

You want to set a property such as 'checked' or 'clicked' or 'highlighted' for each button. Then when you click the button, set that to true. Then to check which have been clicked, loop those buttons and check if 'clicked' is true or false.

let buttons = document.querySelectorAll('input[type="button"]');

let buttonData = Array.from(buttons).map((el, i) => {
  el.addEventListener('click', ()=>{
    const clicked = !buttonData[i].clicked;
    buttonData[i].clicked = clicked;
    if(clicked){
      el.classList.add('highlighted');
    } else {
      el.classList.remove('highlighted');
    }
  });
  return {element: el, clicked:false}
});

buttonData.forEach((btn, i) => {
  
});

document.getElementById('check-buttons').addEventListener('click', ()=>{
  buttonData.forEach((btn, i) => {
    console.log("button:", btn.element.id, "is highlighted?", btn.clicked);
  });
});
input[type="button"] {
  min-width: 100px;
  display: block;
}
.highlighted {
  background-color: white;
  outline: 2px solid rgba(230,200,100);
}
<input type="button" id="button0" value="button 0">
<input type="button" id="button1" value="button 1">
<input type="button" id="button2" value="button 2">
<input type="button" id="button3" value="button 3">
<br>
<button id="check-buttons"> which buttons are highlighted ?</button>
George
  • 2,330
  • 3
  • 15
  • 36
  • Except that buttons don't have a checked property. – Scott Marcus Jan 17 '19 at 02:20
  • that's why you create the property. element attributes are different from object properties. I edited the code so you can see it working more easily and toggle the clicked state. – George Jan 18 '19 at 08:31
  • No, that's not why you add the property. In your use case, you should be adding a `data-*` attribute to use as an indicator. Generally, you should not be adding properties to DOM objects, especially not a property named for an event because adding the property doesn't implement the event behavior. It becomes very confusing for others. Really, the solution here is to not use a button in the first place. See my answer for the correct way. – Scott Marcus Jan 18 '19 at 19:02
  • It works so I'm not sure why you down-voted it. The property is not added to the DOM object, it's got it's own object if you read the code, and you find it confusing. He wanted a button so that's how I answered. My answer is legitimate, there are more than 1 way to do things, just because you have an opinion on what 'right', doesn't mean my answer it wrong. No need for the downvote and useless comments. – George Jan 20 '19 at 11:56
  • If what you are trying to say is that the `.map()` method is causing a duplicate of the DOM node to be created and placed into the returned array and that this is why it's ok to add a property, I'm afraid you're not following what I'm saying. First, your solution creates duplicate objects, which in and of itself is a poor solution. Second, as I've said, adding a property with a name that is the name of a native event for other object types to an object without that actual event being implemented is bad design.... – Scott Marcus Jan 21 '19 at 01:53
  • ... Third, none of this is necessary if you just give the DOM nodes a `data-` attribute (something like `selected`). You could then just use that attribute value as a flag to know how it should be styled. But, as I've shown, the best solution is to not reinvent the wheel. Just use checkboxes and labels which implement all this natively. Lastly, `"It works != It's good"`. – Scott Marcus Jan 21 '19 at 01:55