Set background color of selected radio button - javascript

I am following the excellent example I found here: CSS - How to Style a Selected Radio Buttons Label? trying to style a group of radio-buttons which I create dynamically using javascript. While I manage to create the buttons, I can't find a solution on how to change the background of the label of the radio button that is currently selected. In my example the color only changes during hovering but flips back to normal besides being selected.
My code on JSFiddle: https://jsfiddle.net/dsarh65p/2/
For reference:
HTML
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="btn-group" data-toggle="buttons">
<span id=car></span>
</div>
</body>
</html>
JS
var array = ["Saab", "Volvo", "BMW"];
var item = document.createElement('div');
item.className = 'radio-toolbar';
for (var i = 0; i < array.length; i++) {
var input = document.createElement('input');
var input_label = document.createElement('label');
input.type = 'radio';
input.name = 'radio-btn';
input.id = 'radio' + i;
input.value = "true";
input_label.innerHTML = array[i];
input_label.setAttribute("class", "btn btn-primary");
input_label.appendChild(input);
item.appendChild(input_label);
document.getElementById("car").appendChild(item);
}
CSS
.radio-toolbar input[type="radio"] {
display: none;
}
.radio-toolbar label {
display: inline-block;
background-color: #ddd;
padding: 4px 11px;
font-family: Arial;
font-size: 16px;
cursor: pointer;
}
.radio-toolbar input[type="radio"]:checked {
background-color: #bbb;
}

var array = ["Saab", "Volvo", "BMW"];
var item = document.createElement('div');
item.className = 'radio-toolbar';
for (var i = 0; i < array.length; i++) {
var input = document.createElement('input');
var input_label = document.createElement('label');
input.type = 'radio';
input.name = 'radio-btn';
input.id = 'radio' + i;
input.value = "true";
input_label.innerHTML = array[i];
input_label.addEventListener('click', function(element) {
document.querySelectorAll('.radio-toolbar label').forEach((labelEl) => {
labelEl.selected = false;
labelEl.style.backgroundColor = '#ddd';
});
element.selected = true;
element.style.backgroundColor = 'red';
}.bind(this, input_label));
input_label.setAttribute("class", "btn btn-primary");
input_label.appendChild(input);
item.appendChild(input_label);
document.getElementById("car").appendChild(item);
}
.radio-toolbar input[type="radio"] {
display: none;
}
.radio-toolbar label {
display: inline-block;
background-color: #ddd;
padding: 4px 11px;
font-family: Arial;
font-size: 16px;
cursor: pointer;
}
.radio-toolbar input[type="radio"]:checked {
background-color: #bbb;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<body>
<div class="btn-group" data-toggle="buttons">
<span id=car></span>
</div>
</body>
Link: https://jsfiddle.net/dsarh65p/24/
EDIT:
Updated fiddle with single listener and class names:
https://jsfiddle.net/dsarh65p/26/

I have updated your fiddle here:
https://jsfiddle.net/urbandrone/y49df8wv/1/
Also, I added comments everywhere I changed your code. Basically, what you want to do is not wrap <input> elements inside a <label>, but rather next to it and connect both of them via the id attribute of the <input> and the for attribute of the <label>. This way, you can change the background color of the label with CSS only, which is almost always nicer than having to use JavaScript.
HTML
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<div class="btn-group" data-toggle="buttons">
<span id=car></span>
</div>
</body>
</html>
CSS
.radio-toolbar input[type="radio"] {
display: none;
}
.radio-toolbar label {
display: inline-block;
background-color: #ddd;
padding: 4px 11px;
font-family: Arial;
font-size: 16px;
cursor: pointer;
}
.radio-toolbar .radio { /* style the wrapper */
position: relative; /* allows to "hide" the radio with absolute positioning (won't occupy space) */
display: inline-block; /* show wrappers in horizontal line */
}
.radio-toolbar input[type="radio"] { /* hide the <input> */
position: absolute;
z-index: -1;
}
.radio-toolbar input[type="radio"]:checked + label { /* target the <label> */
background-color: #000; /* changed to more obvious color */
}
JS
var array = ["Saab", "Volvo", "BMW"];
var item = document.createElement('div');
item.className = 'radio-toolbar';
for (var i = 0; i < array.length; i++) {
var wrapper = document.createElement('div'); // <-- create a wrapper element
var input = document.createElement('input');
var input_label = document.createElement('label');
input.type = 'radio';
input.name = 'radio-btn';
input.id = 'radio' + i;
input.checked = i === 0;
input.value = array[i]; // <-- <input>s should have different values
input_label.htmlFor = 'radio' + i; // <-- connect label to <radio> via for-attribute
input_label.innerHTML = array[i];
input_label.className = "btn btn-primary";
input_label.appendChild(input);
wrapper.className = 'radio'; // <-- add a class to the wrapper
wrapper.appendChild(input); // <-- add the <input>
wrapper.appendChild(input_label); // <-- add the <label>
item.appendChild(wrapper); // <-- add wrapper to toolbar
document.getElementById("car").appendChild(item);
}

Related

Element is appended but not shown in nextElementSibling [updated]

I have this program that can make closables dynamically. When the user clicks on a created closable an input box and a button are displayed in the content of the closable. The user can then input text into the textbox and then press the button. Then the users text will be displayed in the selected closable content.
Everything works, fine except for when I try to append the users input to the selected closable. I'm trying to append the users input with this function, but it doesn't work:
var taskCounter = 0;
function addTask() {
var text = document.getElementById("taskInput").value;
console.log(text);
var newTask = $("<input type='checkbox'><label>"+ text + "</label><br>");
newTask.id = 'temp' + taskCounter;
console.log(newTask.id);
taskCounter++
var newContent = document.createTextNode(text);
$(currentContent).append(newTask); //where is it being append to??
console.log("added") //it say it added but where?
}
Why isn't the users input being displayed in the selected closable? And if I'm not doing this correctly already, how do you append a dynamically created element to an elements nextElementSibling?
Here is my full code:
var currentClosable;
var currentContent;
function selectedColl(){
document.getElementById("inputTaskDiv").style.display = "block";
currentClosable = event.target;
currentContent = currentClosable.nextElementSibling;
console.log(currentContent);
var inputTaskDiv = document.getElementById("inputTaskDiv");
currentContent.append(inputTaskDiv);
}
var taskCounter = 0;
function addTask() {
var text = document.getElementById("taskInput").value;
// create a new div element and give it a unique id
var newTask = $("<input type='checkbox'><label>"+ text + "</label><br>");
newTask.id = 'temp' + taskCounter;
taskCounter++
// and give it some content
var newContent = document.createTextNode(text);
$(currentContent).append(newTask); //where is it being append to????
}
var elementCounter = 0;
var elementCounterContent = 0;
var text;
function addElement() {
text = document.getElementById("input").value;
// create a new div element and give it a unique id
var newDiv = $("<button class='collapsible' onclick='selectedColl()'></button>").text(text);
var newContentOfDiv = $("<div class='content'></div>");
newDiv.id = 'temp' + elementCounter;
newContentOfDiv.id = 'content' + elementCounterContent;
newDiv.classList = "div";
elementCounter++
elementCounterContent++
// and give it some content
var newContent = document.createTextNode(text);
// add the newly created element and its content into the DOM
document.getElementById("input").value = " ";
$("body").append(newDiv, newContentOfDiv);
newDiv.click(function() {
this.classList.toggle("active");
content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
} else {
content.style.maxHeight = content.scrollHeight + "px";
}
});
}
.collapsible {
background-color: #777;
color: white;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
}
.active, .collapsible:hover {
background-color: #555;
}
.collapsible:after {
content: '\002B';
color: white;
font-weight: bold;
float: right;
margin-left: 5px;
}
.active:after {
content: "\2212";
}
.content {
padding: 0 18px;
max-height: 0;
overflow: hidden;
transition: max-height 0.2s ease-out;
background-color: #f1f1f1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<input id="input" type="text"><button onclick="addElement()">Add</button>
<div id="inputTaskDiv" style="display:none">
<input id="taskInput" type="text"><button onclick="addTask()">Add Task</button>
</div>

TodoList Webpage, better event listener than mouseovert/out? why is my pseudo element ::first-letter not working?

Hello and thanks for stopping by.
I have one main problem with my app.
I think the mouseout and mouseover event listeners are firing like crazy when I put my cursor over the trashcan icon and I don't know why. It gets all glitchy and can't click on it correctly.
Any advice?
https://codepen.io/Dali213/pen/ExjLMdG?editors=0110
const ul = document.querySelector("ul");
//initialisation
const arr = ["learn how to use GitHub.", "learn how to use GitHub.", "learn how to use GitHub."];
for (let i = 0; i < arr.length; i++) {
addToDo(arr[i]);
}
function addToDo(text) {
const li = document.createElement("li");
const p = document.createElement("p");
p.textContent = text;
li.append(p);
li.addEventListener("click", lineThrough);
li.addEventListener("mouseover", addTrashCan);
li.addEventListener("mouseout", removeTrashCan);
ul.append(li);
}
//add rubish icon+delete function
function del() {
const li = this.closest("li");
li.removeEventListener("click", lineThrough);
li.removeEventListener("mouseover", addTrashCan);
li.removeEventListener("mouseout", removeTrashCan);
li.remove();
}
function addTrashCan() {
const trashCan = document.createElement("i");
trashCan.classList.add("far", "fa-trash-alt", "trash-can");
trashCan.addEventListener("click", del);
this.prepend(trashCan);
}
function removeTrashCan() {
const trashCan = this.querySelector("i");
trashCan.removeEventListener("click", del);
trashCan.remove();
}
Second question, at first my pseudo element ::first-letter was working correctly now it isn't.
When I look at the styles applied with the developper tool, it still seems applied though... Why?
Any advice on my code is more than welcome.
Thank you for your time.
You could prepend the trash can in the beginning itself and show/hide based on mouseout or mouseover events instead of creating the element each time:
.hidden {
display: none !important;
}
function addTrashCan() {
this.querySelector('i').classList.remove('hidden')
}
function removeTrashCan() {
this.querySelector('i').classList.add('hidden')
}
function addToDo(text) {
const li = document.createElement("li");
const p = document.createElement("p");
const trashCan = document.createElement("i");
trashCan.classList.add("far", "fa-trash-alt", "trash-can", "hidden");
trashCan.addEventListener("click", del);
li.prepend(trashCan);
p.textContent = text;
li.append(p);
li.addEventListener("click", lineThrough);
li.addEventListener("mouseover", addTrashCan);
li.addEventListener("mouseout", removeTrashCan);
ul.append(li);
}
const ul = document.querySelector("ul");
const input = document.querySelector("input");
//initialisation
const arr = ["learn how to use GitHub.", "learn how to use GitHub.", "learn how to use GitHub."];
for (let i = 0; i < arr.length; i++) {
addToDo(arr[i]);
}
function addToDo(text) {
const li = document.createElement("li");
const p = document.createElement("p");
const trashCan = document.createElement("i");
trashCan.classList.add("far", "fa-trash-alt", "trash-can", 'hidden');
trashCan.addEventListener("click", del);
li.prepend(trashCan);
p.textContent = text;
li.append(p);
li.addEventListener("click", lineThrough);
li.addEventListener("mouseover", addTrashCan);
li.addEventListener("mouseout", removeTrashCan);
ul.append(li);
}
//hide the input
function hideInput() {
input.classList.toggle("hidden");
}
//add task to the list
function enter() {
if (event.keyCode === 13) addToDo(this.value);
}
//line-through on click
function lineThrough() {
this.querySelector("p").classList.toggle("line-through");
}
//add rubish icon+delete function
function del() {
const li = this.closest("li");
li.removeEventListener("click", lineThrough);
li.removeEventListener("mouseover", addTrashCan);
li.removeEventListener("mouseout", removeTrashCan);
li.remove();
}
function addTrashCan() {
/*const trashCan = document.createElement("i");
trashCan.classList.add("far", "fa-trash-alt", "trash-can");
trashCan.addEventListener("click", del);
this.prepend(trashCan);*/
console.log('in');
this.querySelector('i').classList.remove('hidden')
}
function removeTrashCan() {
/*const trashCan = this.querySelector("i");
trashCan.removeEventListener("click", del);
trashCan.remove();*/
console.log('out');
this.querySelector('i').classList.add('hidden')
}
//listeners
document.querySelector(".display").onclick = hideInput;
input.onkeyup = enter;
* {
padding: 0px;
margin: 0px;
}
body {
background: linear-gradient(90deg, #18b7e4, #e8e9be);
}
.container {
background-color: aliceblue;
min-width: 270px;
max-width: 270px;
margin: 80px auto 0px;
}
.head {
padding: 5px 10px;
display: flex;
justify-content: space-between;
background-color: #2072b5;
color: #ffffff;
}
.display,
i {
cursor: pointer;
}
input {
border: 2px solid #2072b5;
width: 246px;
padding: 5px 10px;
}
.hidden {
display: none !important;
}
ul {
list-style: none;
}
p {
display: inline;
padding: 2px 5px;
}
p::first-letter {
text-transform: capitalize;
}
li:nth-of-type(odd) {
background-color: #f7f5f7;
}
li:nth-of-type(even) {
background-color: #ffffff;
}
.line-through {
text-decoration: line-through;
opacity: 0.7;
}
.trash-can {
background-color: red;
color: #ffffff;
padding: 2px 5px;
}
li {
display: flex;
}
<!DOCTYPE html>
<html>
<head>
<title>to-do list</title>
<link rel="stylesheet" href="main.css" />
<script src="https://kit.fontawesome.com/fe178342de.js" crossorigin="anonymous"></script>
</head>
<body>
<div class="container">
<div class="head">
<h1>TO-DO LIST</h1>
<h1 class="display">+</h1>
</div>
<input type="text" placeholder="Add New Todo" />
<ul></ul>
</div>
<script src="main.js"></script>
</body>
</html>
Edit:
To fix the ::first-letter pseudo element, issue you could add the following css:
li {
display: flex;
}

Create text element inline with input checkbox list elements using javascript

I am trying to dynamically add a checklist to my page that will look something like this, where [ ] represents a checkbox
[ ] something
[ ] something
[ ] something
The following code snippet shows what I have so far. As seen, the "somethings" are below the checkboxes, I would like for them to be on the same line.
list = ["something1", "something2", "something3"];
document.addEventListener('DOMContentLoaded', function () {
for (var i = 0; i < list.length; i++) {
var container = document.getElementById("checklist");
var li = document.createElement("li");
var input = document.createElement("input");
var text = document.createTextNode(list[i]);
container.appendChild(li).appendChild(input)
container.appendChild(text)
input.type = "checkbox"
li.style.listStyle = "none"
}
})
#container {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
top: 100px;
}
#directions{
color: green;
}
<body>
<div id="container">
<div id="directions">
Check off list items!
</div>
<div id="checklist"></div>
</div>
</body>
Fix your javascript:
//container.appendChild(text);
li.appendChild(text);
list = ["something1", "something2", "something3"];
document.addEventListener('DOMContentLoaded', function () {
for (var i = 0; i < list.length; i++) {
var container = document.getElementById("checklist");
var li = document.createElement("li");
var input = document.createElement("input");
var text = document.createTextNode(list[i]);
container.appendChild(li).appendChild(input);
li.appendChild(text);
input.type = "checkbox";
li.style.listStyle = "none";
}
})
#container {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
top: 100px;
}
#directions{
color: green;
}
<body>
<div id="container">
<div id="directions">
Check off list items!
</div>
<div id="checklist"></div>
</div>
</body>
I would recommend you using div and label elements instead of li elements here.
You might also move list from being an array of strings to be an array of objects where each object has an identifier and a label string.
Let me know if you have any questions.
list = ["something1", "something2", "something3"];
document.addEventListener('DOMContentLoaded', function () {
for (var i = 0; i < list.length; i++) {
var container = document.getElementById("checklist");
var formGroup = document.createElement("div");
var input = document.createElement("input");
var label = document.createElement("label");
formGroup.appendChild(input);
formGroup.appendChild(label);
container.appendChild(formGroup);
input.type = "checkbox"
input.id = list[i];
label.setAttribute("for", list[i]);
label.innerText = list[i];
}
})
#container {
display: flex;
flex-direction: column;
align-items: center;
position: relative;
top: 100px;
}
#directions{
color: green;
}
<body>
<div id="container">
<div id="directions">
Check off list items!
</div>
<div id="checklist"></div>
</div>
</body>
If the question is just how to get the checkbox and text on the same line, set your lis to display: inline or display: inline-block. That said, you probably shouldn't be using list items in the first place, especially when the parent isn't a list.

Return element class post form submission

I'm trying to create customizable checkboxes using buttons. I'm able to differentiate which button class has been selected, but I've been unable to track the button class post form submission. Ideally, instead of reseting the buttons to a default value when the page is loaded or submitted, I can keep whatever input was initially provided. I've tried using the isset() php function, but I don't think it's a valid solution in this circumstance. Are there any alternatives? Find my code below:
<form id="my-form" method="post">
<html>
<body >
<style>
.button {
color: white;
padding: 10px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
margin: 4px 2px;
cursor: pointer;
}
.button1 {
border-radius: 100%;
background-color: green;
border: none;
}
.button2 {
border-radius: 100%;
background-color: red;
border: none;
}
</style>
<div id="test1"></div>
<div id="test2"></div>
<!-- invalid code?
<?php
echo isset($_POST["t1test"]);
echo isset($_POST["t2test"]);
echo $_POST["t1test"];
echo $_POST["t2test"];
?>
-->
<script type="text/javascript">
function makeButton(div, val) {
var element = document.getElementById(val);
var button = document.createElement("button");
var span = document.createElement("span");
// change to account for submitted settings
if (element == null) {
button.setAttribute("class", "button button1"); }
else {
var cL1 = element.classList.contains("button1");
var cL2 = element.classList.contains("button2");
element.parentNode.removeChild(element);
if (cL2 == true) { button.setAttribute("class", "button button1"); }
if (cL1 == true) { button.setAttribute("class", "button button2"); }
}
button.setAttribute("type", "button");
button.setAttribute("id", val);
button.setAttribute("name", val);
var testDiv = document.getElementById(div);
testDiv.appendChild(button);
button.addEventListener ("click", function() { makeButton(div, val); })
}
window.onload = function() {
makeButton("test1", "t1test");
makeButton("test2", "t2test"); }
</script>
</body>
</html>
<button id="submit">Submit</button>
</form>
How about removing the form tags and adding a "click" event listener to the submit button? The code shown below inserted appended to the end of the file:
<script>
document.getElementById("submit").addEventListener("click", function(){
var elements = ["t1test", "t2test"];
for(var i = 0; i < elements.length; i++) {
var element = document.getElementById(elements[i]);
console.log(element.classList.contains("button1"));
console.log(element.classList.contains("button2"));
}
});
</script>
This way the page will not be reloaded when the button is pressed thus retaining button selection.

Why can't I set a css attribute to my array. Coding for Hangman Javascript

Why can't character.setAttribute() work. If you delete the line, the
format of what I am trying to accomplish is there, but the CSS for the letters don't make it invisible. If I do put the setAttribute() in, the code doesn't work.
<!Doctype html>
<html lang="en">
<head>
<style>
.hidden {
visibility: hidden;
}
ul {
display: inline;
list-style-type: none;
}
.boxes {
font-size:1.6em;
text-align:center;
width: 10px;
border-bottom: 3px solid black;
margin: 5px;
padding: 10px;
display: inline;
}
</style>
</head>
<body>
<script>
var possibleWord = ["cow", "better", "harder", "justify", "condemn",
"control", "hello", "understand", "life", "insight","date", "righteous"];
var hangmanWord = possibleWord[Math.floor(Math.random() *
possibleWord.length)];
var underlineHelp;
var space;
var guess;
var guesses = [];
var placement;
var underscores;
var character = [];
window.onload = function () {
placement = document.getElementById('hold');
underlineHelp = document.createElement('ul');
placement.appendChild(underlineHelp);
for (i = 0; i < hangmanWord.length; i++) {
underscores = document.createElement('li');
underscores.setAttribute('class', 'boxes');
guesses.push(underscores);
underlineHelp.appendChild(underscores);
character = document.createElement('li');
character = document.createTextNode(hangmanWord[i]);
character.setAttribute('class', 'hidden');//The issue is here, if you take
//this line out then the format will be correct, except I am trying to hide
//the letters with the css attribute "hidden."The dashes are represented by
//the bottom-border of "boxes."
underscores.appendChild(character);
}
</script>
<div id = "hold"></div>
</html>
A TextNode doesn't have attributes.
character = document.createElement('li');
character = document.createTextNode(hangmanWord[i]);
I am guessing you want to do:
character = document.createElement('span');
character.appendChild(document.createTextNode(hangmanWord[i]));
character.classList.add('hidden');
underscores.appendChild(character);
Working example:
var possibleWord = ["cow", "better", "harder", "justify", "condemn",
"control", "hello", "understand", "life", "insight", "date", "righteous"
];
var hangmanWord = possibleWord[Math.floor(Math.random() *
possibleWord.length)];
var underlineHelp;
var space;
var guess;
var guesses = [];
var placement;
var underscores;
var character = [];
window.onload = function() {
placement = document.getElementById('hold');
underlineHelp = document.createElement('ul');
placement.appendChild(underlineHelp);
for (i = 0; i < hangmanWord.length; i++) {
underscores = document.createElement('li');
underscores.setAttribute('class', 'boxes');
guesses.push(underscores);
underlineHelp.appendChild(underscores);
character = document.createElement('span');
character.appendChild(document.createTextNode(hangmanWord[i]));
character.classList.add('hidden');
underscores.appendChild(character);
}
}
.hidden {
visibility: hidden;
}
ul {
display: inline;
list-style-type: none;
}
.boxes {
font-size: 1.6em;
text-align: center;
width: 10px;
border-bottom: 3px solid black;
margin: 5px;
padding: 10px;
display: inline;
}
<div id="hold"></div>

Categories