When the element's first clicked on its color should turn red. That part works. When the element's clicked on a second time it's should turn black, it's initial default color, and so on and so forth. That's the part that doesn't work. Once the element turns red it stays in that "state".
function toggleClass() {
var monday = document.getElementById("monday");
monday.classList.add("redColor");
monday.classList.remove("redColor");
this.classList.toggle("redColor");
}
monday.addEventListener("click", toggleClass)
.greenColor {
color: green;
}
.redColor {
color: red;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Practise App</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="monday" class="">Monday</div>
<script src="index.js" type="text/javascript"></script>
</body>
</html>
You just need the toggle, it will toggle the class for you - you don't need the add or remove: monday.classList.toggle("redColor");
for example:
function toggleClass() {
var monday = document.getElementById("monday");
monday.classList.toggle("redColor");
}
function toggleClass() {
var monday = document.getElementById("monday");
monday.classList.toggle("redColor");
}
monday.addEventListener("click", toggleClass)
.greenColor {
color: green;
}
.redColor {
color: red;
}
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>Practise App</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="monday" class="">Monday</div>
<script src="index.js" type="text/javascript"></script>
</body>
</html>
You don't need this two instructions:
monday.classList.add("redColor");
monday.classList.remove("redColor");
Just the toggle is enough. Also if you already captured the div in the variable monday, you don't need the reference to this:
function toggleClass() {
var monday = document.getElementById("monday");
monday.classList.toggle("redColor");
}
monday.addEventListener("click", toggleClass)
this should do the trick.
Here's a pen to illustrate: https://codepen.io/ePresas/pen/BaQjVwG
DOMTokenList.toggle()
The toggle() method of the DOMTokenList interface removes a given token from the list and returns false. If token doesn't exist it's added and the function returns true.
You do not need to use add() and remove(), simply toggle() should do the trick.
Also, as this keyword refers to the currently clicked element, I think you do not need to get the element by id here:
function toggleClass() {
this.classList.toggle("redColor");
}
monday.addEventListener("click", toggleClass)
.redColor {
color: red;
}
.greenColor {
color: green;
}
<div id="monday" class="">Monday</div>
Related
Can someone please explain to me why this doesn't work. I am aiming to loop through a javscript file to change the background colour of my html document on click. When I am to do this it doesn't loop through but then goes straight to yellow (the last of the loop)
const colors = ["blue", "green", "yellow"];
const btn = document.getElementById("btn");
function myFunction(){
for (let i=0; i<colors.length; i++){
document.body.style.backgroundColor = colors[i]
}
}
it automatically goes to i = 2 and creates a yellow background color
here is html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Colour Flipper</title>
<link rel="stylesheet" href="colourflipper.css">
</head>
<body>
<div class="top">
<ul>Colour Flipper</ul>
<ul>Simple Hex</ul>
</div>
<div class="main">
<button id="btn" onclick="myFunction()">
<h1>Background Colour</h1>
</button>
</div>
<script src="colourflipper.js"></script>
</body>
</html>
The problem you're having is that the entire myFunction code is being run on every click. Because your counter is defined in the function, it is reset every click, and the loop is running every time, and cycling through all of the colours, on every click. You're only seeing yellow because it is running too quickly for you to see the individual colours, and the loop is ending on yellow, as it is the last element in the colors array.
If you want to cycle colours on click, you need to store the state of the color outside of the function loop, because your event function should only needs to have code that will run every time a click happens.
Here is how I imagine you wanted it to work:
const colors = ["blue", "green", "yellow"];
const btn = document.getElementById("btn");
let colorIndex = -1;
function myFunction(){
colorIndex += 1;
if (colorIndex > colors.length-1) colorIndex = 0;
document.body.style.backgroundColor = colors[colorIndex]
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Colour Flipper</title>
<link rel="stylesheet" href="colourflipper.css">
</head>
<body>
<div class="top">
<ul>Colour Flipper</ul>
<ul>Simple Hex</ul>
</div>
<div class="main">
<button id="btn" onclick="myFunction()">
<h1>Background Colour</h1>
</button>
</div>
<script src="colourflipper.js"></script>
</body>
</html>
A slightly alternative approach to SubXaero's answer is to use a closure to maintain a local variable rather than creating a global one.
Note: I've used classes here instead of setting the background style directly.
const colors = ["blue", "green", "yellow"];
const btn = document.getElementById("btn");
const color = document.getElementById("color");
// Pass in `colors` to the handler which returns a new
// function that does all the work
btn.addEventListener('click', handleClick(colors), false);
// This function accepts colors as an argument
// initialises the array index, and then
// returns the function that will be used as the listener
function handleClick(colors) {
let index = 0;
return function() {
if (index < colors.length) {
color.classList.add(colors[index]);
++index;
}
}
}
.blue { background-color: blue; }
.green { background-color: green; }
.yellow { background-color: yellow; }
<div id="color">Colour</div>
<button id="btn">Background Colour</button>
I want to get the 'p' element with red color attribute. To do this i wrote the code below but i get a null result. What am i doing wrong?
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./test.css">
<script src="./test.js" defer></script>
<title>test</title>
</head>
<body>
<p id="p1">red</p>
<p id="p2">green</p>
<p id="p3">blue</p>
</body>
</html>
test.js
test.js
"use strict"
let element = document.querySelector("p[color='red']");
console.log(element); // logs null
test.css
#p1 {
color: red;
}
#p2 {
color: green;
}
#p3 {
color: blue;
}
You're trying to select an element based not on its HTML attributes, but on the CSS rules that are applied to it. This can't be done with a plain querySelector.
For the general case, iterate over all possibly matching elements and call getComputedStyle on each to find the one that matches:
const p = [...document.querySelectorAll('p')]
.find(p => window.getComputedStyle(p).color === 'rgb(255, 0, 0)');
console.log(p);
#p1 {
color: red;
}
#p2 {
color: green;
}
#p3 {
color: blue;
}
<p id="p1">red</p>
<p id="p2">green</p>
<p id="p3">blue</p>
Note that for color, you need to use rgb syntax.
Trying to change color using a variable, console works but color not changing when I click on the square.
Color is the variable I want to use.
I have tried an actual string value and that does not work.
<!DOCTYPE html>
<html>
<head>
<link href="main.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<h1>Test Your Reactions!</h1>
<p>Click on the shapes as fast as you can</p>
<div id="shapes">
</div>
<script>
function myFunction() {
var colour = '#'+((Math.random() * (1<<24)|0).toString(16).slice(-6));
document.getElementById("shapes").style.backgroundColour = colour;
console.log(colour);
}
</script>
</body>
</html>
its backgroundColor not Colour .. you have an extra u
You need to replace backgroundColour by backgroundColor without u :
document.getElementById("shapes").style.backgroundColour = colour;
______________________________________________________^
Must be :
document.getElementById("shapes").style.backgroundColor = colour;
NOTE 1: You need to trigger the function to see the effect and you must also give your target div shapes a width/height so you can see it.
NOTE 2: You must listen on DOMContentLoaded event to make sure all the elements are loaded to the DOM before calling your script.
Working sample:
<!DOCTYPE html>
<html>
<head>
<link href="main.css" rel="stylesheet" type="text/css" />
<style>
#shapes {
width: 100px;
height: 100px;
border: 1px solid #000;
}
</style>
</head>
<body>
<h1>Test Your Reactions!</h1>
<p>Click on the shapes as fast as you can</p>
<div id="shapes">
</div>
<script>
document.addEventListener("DOMContentLoaded", function(event) {
var shapes = document.getElementById("shapes");
shapes.addEventListener('click', myFunction, false);
});
function myFunction() {
shapes.style.backgroundColor = "#" + (Math.random() * (1 << 24) | 0).toString(16).slice(-6);
}
</script>
</body>
</html>
Try this
const shapes = document.getElementById("shapes"); // You declare once, then you can reuse
function myFunction() {
var colour = '#'+((Math.random() *(1<<24)|0).toString(16).slice(-6));
shapes.style.backgroundColor = colour;
console.log(colour);
}
shapes.addEventListener('click', myFunction); // I guess you want to click somewhere
<h1>Test Your Reactions!</h1>
<p>Click on the shapes as fast as you can</p>
<div id="shapes">Shapes</div>
Below code gives the expected result. please take it.
<!DOCTYPE html>
<html>
<head>
<link href="main.css" rel="stylesheet" type="text/css"/>
<style>
#shapes {
width: 300px;
height: 300px;
background-color: coral;
color: white;
}
</style>
</head>
<body>
<h1>Test Your Reactions!</h1>
<p>Click on the shapes as fast as you can</p>
<div id="shapes" onClick="myFunction();">
test
</div>
<script>
function myFunction() {
var colour = '#'+((Math.random() * (1<<24)|0).toString(16).slice(-6));
document.getElementById("shapes").style.backgroundColor = colour;
console.log(colour);
}
</script>
</body>
</html>
I'm trying to build a quick thingy where the web page changes color every time you click a button. I've written JS which will change the bg color to red if the current bg is #FFFFFF. After it didn't work with the default, I tried explicitly setting the bg color through CSS and HTML script tag to #FFFFFF. Neither worked. Oddly, the JS runs if I change the == operator to !==.
$(document).ready(function() {
$("button").click(function() {
if ($("body").attr("background-color") == "#FFFFFF") {
$("body").css("background-color", "red");
} else if ($("body").attr("background-color") == "red") {
};
});
});
body {
background-color: #FFFFFF;
}
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<title></title>
</head>
<body style="background-color:#FFFFFF;">
<button>hi</button>
<div class="test">text</div>
</body>
</html>
You can't use attr to retrieve a style property, you have to css instead :
$("body").css("background-color")
more informations here : https://api.jquery.com/css/
You are checking for a background-color attribute on the body. Body doesn't have a background-color attribute. It has a style attribute - which in turn has a background-color attribute.
Option 1: Change your if statement to check for the style:
if ($("body").attr("style") == "background-color: #FFFFFF;")
This will only work if you don't add additional styles. You are better off using Option 2 below.
Option 2: Set the color via a css class, then check whether the body has that class.
CSS:
.white { background-color: #FFFFFF; }
.red { background-color: red; }
JQUERY:
if ($("body").hasClass("white")) {
$("body").removeClass("white").addClass("red");
}
It is not attribute, it is style that you checking. Attributes are inside tags, styles are inside css. Use $("body").css("background-color")
try this:
$("body").css("background-color", "#FFFFFF");
I'm practicing basic JS skills by setting up little exercises for myself. In this one, I have a list of <a>s inside a div. The aim of the exercise is to wrap each <a> in a div. I'm using replaceChild in this instance.
Oddly (to me at least) the script works for the first three links, but after that throws an error:
Uncaught TypeError: Cannot read property 'parentNode' of undefined
I can't tell why the script partly works. Can anyone see what I'm doing wrong here? Here's the code I'm using:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.getElementsByTagName("a");
for (var i=0, ii=links.length; i<ii; i++)
{
var container = document.createElement("div");
links[i].parentNode.replaceChild(container, links[i]);
container.appendChild(links[i]);
}
</script>
</body>
</html>
and here's an online version: http://codepen.io/anon/pen/Lpuky
I've tried the few debugging techniques that I know of and read about this error message, but haven't worked out what's wrong here. Seems funny to me that it works for 3 of the 6 links.
The collection links is NodeList and is live.
Since you are replacing them, they are disappearing from the collection and our index into them is no longer pointing to anything.
You're modifying the nodelist as you iterate over it. Use the Array slice method to make a copy of the list:
var linksCopy = Array.prototype.slice.call(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
Regarding your own follow-up answer: if your objective was simply to find the easiest way to wrap the <a>s in <div>s, rather than to practice with createElement, replaceChild or appendChild or any of the other methods, this would be it:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Demo</title>
<style>
div div {
padding: 10px;
background: #e7e7e7;
margin: 5px;
}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.querySelectorAll("a");
for (var i=0; i<links.length; i++) {
links[i].outerHTML = '<div>'+links[i].outerHTML+'</div>';
}
</script>
</body>
</html>
.
Live demo here: http://jsbin.com/jasoho/1/edit?html,output. Another advantage of the outerHTML method is that it doesn't change the nodeList. So you can also use getElementsByTagName in stead of querySelectorAll.
As a follow up to this, I often hear that querySelectorAll() is different in that it returns a static Nodelist rather than an array, so I thought that might come in handy here, and indeed it does:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.querySelectorAll("a");
for (var i=0, ii=links.length; i<ii; i++)
{
var container = document.createElement("div");
links[i].parentNode.replaceChild(container, links[i]);
container.appendChild(links[i]);
}
</script>
</body>
</html>
Also, an alternative to Array.prototype.slice.call(links) is [].slice.call(links):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.getElementsByTagName("a");
var linksCopy = [].slice.call(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
</script>
</body>
</html>
And another option again is to use [].forEach.call():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
[].forEach.call(document.querySelectorAll('a'), function(el) {
var container = document.createElement("div");
el.parentNode.replaceChild(container, el);
container.appendChild(el);
});
</script>
</body>
</html>
Yet another option, using Array.from():
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style media="all">
div div {padding: 10px; background: #e7e7e7; margin: 5px;}
</style>
</head>
<body>
<div>
link
link
link
link
link
link
</div>
<script>
var links = document.getElementsByTagName("a");
var linksCopy = Array.from(links);
for (var i=0; i<linksCopy.length; i++)
{
var container = document.createElement("div");
linksCopy[i].parentNode.replaceChild(container, linksCopy[i]);
container.appendChild(linksCopy[i]);
}
</script>
</body>
</html>