I'm a little unsure why my code doesn't seem to be working when my html and JS code are within the same file. When the html and JS are separate, seems to be working fine. Can someone point out the error in my ways....I'm a newbie!!
HTML:
<div class="main">
<div class="light"></div>
<button onclick="chngCol()" id="burn">Burn!</button>
</div>
JavaScript:
chngCol() {
if(document.getElementByClass('light').style.background == "#00ffff")
{
document.getElementByClass('light').style.background = "#ffff00";
}
else if(document.getElementByClass('light').style.background == "ffff00")
{
document.getElementByClass('light').style.background = "#ff00ff";
}
else if(document.getElementByClass('light').style.background == "#ff00ff")
{
document.getElementByClass('light').style.background = "#00ffff";
}
}
CSS:
.light{
width: 50px;
height: 50px;
background-color:#00ffff;
}
All code is in the same document with the appropriate tags and however the error i'm getting in Chrome Console on the first { after calling chngCol.
There are a multitude of issues.
chngCol() { is not valid JS. Either function chngCol() { OR const chngCol = () =>
You need document.getElementsByClassName("light")[0] OR better, document.querySelector(".light")
You cannot read the background color of the element if it is not set in script first.
I think you meant to do this:
let cnt = 0;
const colors = ["#00ffff", "#ffff00", "#ff00ff"];
const chngCol = () => {
cnt++;
if (cnt >= colors.length) cnt = 0; // wrap
document.querySelector('.light').style.background = colors[cnt]; // use the array
}
document.getElementById("burn").addEventListener("click", chngCol);
.light {
width: 50px;
height: 50px;
background-color: #00ffff;
}
#burn {
width: 150px;
font-weight: 700;
}
<div class="main">
<div class="light"></div>
<button id="burn">Burn!</button>
</div>
The document.getElementByClass selector is an array selector. In order to select your element you should select the first element of the array.
Try this instead:
document.getElementsByClassName('light')[0].style.background
Related
I want to make a basic inbox function. It contains 3 messages.
So I want to make that when the user click onto the DELETE button, set the msg1's display to none, and decrease the messages value.
Here is the example code:
var x = 2;
function deleteMsg1() {
var msg1 = document.getElementsByClassName("cont");
if (confirm("Are you sure to want to delete this message?")) {
msg1[0].style.display = "none";
x = x-1;
} else {
}
}
function deleteMsg2() {
var msg2 = document.getElementsByClassName("cont2");
if (confirm("Are you sure to want to delete this message?")) {
msg2[0].style.display = "none";
x = x-1;
} else {
}
}
document.getElementById("msgcount").innerHTML = x;
.cont, .cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span>messages</h1>
<button onclick="deleteMsg1()">Delete</button>
<div class="cont">
Some text...
</div>
<br><br>
<button onclick="deleteMsg2()">Delete</button>
<div class="cont2">
Some text...
</div>
I know this isn’t the best idea, but I guess it’s bad.
I think I should do this with one function() and try something event listener but I don't really know how to do that.
Any idea or help?
You should wrap each message's HTML in a parent element so that you can then treat each set of elements that comprise a message as a single unit and delete it all at once.
To be able to do this with a single function, you can use this to reference the element that triggered the callback function in the first place and .closest() to access the single parent wrapper.
Notes:
Do not use inline HTML event attributes, like onclick.
Separate your HTML and your JavaScript and use .addEventListener()
to bind elements to event callbacks. Even MDN recommends not using
them.
Do not use .getElementsByClassName() as it is a 25+ year old
API that has significant performance implications. Instead, use the
modern .querySelectorAll() method.
Do not use .innerHTML if you can avoid it as it has security and
performance implications. Since the text you are wanting to update
doesn't have any HTML in it anyway, .innerHTML is not warranted.
Instead, use .textContent.
// Do your event binding in JavaScript, not HTML
document.querySelectorAll("button").forEach(function(element){
element.addEventListener("click", function(){
if (confirm("Are you sure to want to delete this message?")) {
// All you need to do is delete the nearest complete
// ancestor message construct, which can be done with
// the .closest() method
this.closest(".message").remove();
updateMessageCount();
}
});
});
function updateMessageCount(){
// Set the count equal to the length of the
// collection returned by searching for all the
// messages
document.getElementById("msgcount").textContent =
document.querySelectorAll(".message").length;
}
updateMessageCount();
.cont, .cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span> messages</h1>
<!-- By wrapping each message, you can treat all its HTML
as one single unit. -->
<div class="message">
<button>Delete</button>
<div class="cont">
Some text...
</div>
</div>
<br><br>
<div class="message">
<button>Delete</button>
<div class="cont">
Some text...
</div>
</div>
Explained
Here's a simple enough solution, you need to update the HTML manually every time you want to update the value of x. That's why I created an updateX function, it'll just take the value & update the DOM, it's quite that simple.
const updateX = (x) => {
document.getElementById("msgcount").innerHTML = x;
};
let x = 2;
const del = (className) => {
const msg = document.getElementsByClassName(className);
if (confirm("Are you sure to want to delete this message?")) {
msg[0].style.display = "none";
x--;
} else {
console.log("===");
}
updateX(x);
};
updateX(x);
.cont,
.cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span>messages</h1>
<button onclick="del('cont')">Delete</button>
<div class="cont">
Some text...
</div>
<br/><br/>
<button onclick="del('cont2')">Delete</button>
<div class="cont2">
Some text...
</div>
My advice to you: Never declare events js inside html structure tags! As here:
<button onclick="deleteMsg1()">Delete</button>
This is a very bad practice. This has many disadvantages. And this can lead to bad consequences.
I made a solution for you with the forEach() method, without using javascript in html.
The Delete button is also removed.
let msg = document.querySelectorAll(".cont");
let btn_del = document.querySelectorAll('.btn_del');
let x = 2;
btn_del.forEach(function (btn_del_current, index) {
btn_del_current.addEventListener('click', function () {
if (confirm("Are you sure to want to delete this message?")) {
this.style.display = "none";
msg[index].style.display = "none";
x = x - 1;
document.getElementById("msgcount").innerHTML = x;
} else {}
});
});
.cont, .cont2 {
background-color: red;
padding: 5px;
width: 100px;
margin: 25px 0;
}
.show {
display: block;
}
<h1>There are <span id="msgcount"></span>messages</h1>
<button class="btn_del">Delete</button>
<div class="cont">
Some text...
</div>
<br><br>
<button class="btn_del">Delete</button>
<div class="cont">
Some text...
</div>
applying a class to an element only when clicked
You could make 2 different click functions. One for trap and one for the rest.
For that you need to know which ones are the other ( safe ones ). See otherDivsIds in the below code. You find the other id's using the filter function in the idArray and then loop through them ( with forEach or something else ) and add event listeners to each of them.
I would also suggest to ' swap ' the naming of the variables trapBox and trapId. Vice versa would be better
See code below
var idArray = ['one','two','three','four'];
var trapBox = idArray[Math.floor(Math.random() * idArray.length)];
var trapId= document.getElementById(trapBox);
trapId.addEventListener('click', boomClickFunction, false);
var otherDivsIds = idArray.filter(id => id !== trapBox);
otherDivsIds.forEach(id => {
safeBox = document.getElementById(id);
safeBox.addEventListener('click', safeClickFunction, false)
})
var timeoutId = window.setTimeout(ticker, 5000);
function ticker() {
document.getElementById('timesUp').innerHTML = "Time's up!";
document.body.style.backgroundColor = "black";
}
function boomClickFunction() {
this.classList.add('boom')
}
function safeClickFunction() {
this.classList.add('safe')
}
div {
width: 20px;
height: 20px;
background-color: green;
margin: 20px;
float: left;
}
.boom {
background-color: red;
}
.safe {
background-color: lightblue;
}
#timesUp {
color: white;
}
<div id='one'>
</div>
<div id='two'>
</div>
<div id='three'>
</div>
<div id='four'>
</div>
<span id="timesUp">
</span>
You can add a class to an element by using classList.add('classToBeAdded').
In your case, you could put it in your clickFunction:
trapId.classList.add('boom');
How to add event delegation to dynamically created divs, to change property of the target div? I've tried several suggestions that I found for event delegation but none of them work. I think I'm making some mistakes but I don't know how to fix.
I am trying to develop a file thumbnail list interface with HTML and JavaScript. I made a method that draws thumbnails dynamically from an Array. And now I want to add some functions to manipulate the thumbnails, ex. changing border color of the item(div) when it is clicked.
First I tried loop-method to add event listeners to the divs, but it didn't work well. And now I learned that event delegation is better way to add event listeners to dynamically created elements. But the problem is that though I'v tried codes but they didn't work at all.
I think I am making some mistakes or mis-using methods but I don't know what is the problem.
JavaScript
function drawThumbnails(area, list){
var j
var createdList = []
for (j=0; j<list.length; j++){
var thmb = document.getElementById("fileThumb");
var name = document.getElementById("itemName");
var date = document.getElementById("itemDate");
var thmbimg = document.getElementById("fileThumbImage");
var thmbicon = document.getElementById("file_icon_thumb");
name.innerHTML=list[j][0];
date.innerHTML=list[j][1];
if (list[j][2] == "folder"){
thmbimg.src = "thmb_folder.png";
thmbicon.style.display = "none";
}
else {
if (list[j][2] == "img"){
thmbimg.src=getthmbimgsample();
}
else{
thmbimg.src = getThmbimg(list[j][2]);
}
thmbicon.style.display = "block";
thmbicon.src = getThmbicon(list[j][2]);
}
var cln = thmb.cloneNode(true);
cln.style.display = "block";
document.getElementById(area).append(cln);
createdList.push(cln);
}
thmbLists.push(createdList);
}
drawThumbnails("folderArea", folders);
drawThumbnails("fileArea", files);
document.getElementById("folderArea").addEventListener('click',function(e){
if(e.target && e.target.className == "fileThumb"){
e.target.style.borderColor = "#408CFF";
}
});
HTML
<body>
<div class = "contentArea" id="contentArea">
<div class = "thumbArea" id="folderArea">
<div class = "fileThumb" id="fileThumb">
<img src="icon_thumb_folder.png" class="fileThumb_normal" id="fileThumbImage">
<div class="fileName">
<img src="icon_thumb_file.png" style="width: 20px;" id="file_icon_thumb">
<div class="fileNameLine" id = "itemName">File/FolderName</div>
<div class="fileNameDate" id="itemDate">Date</div>
</div>
</div>
</div>
<div class = "contentAreaSectionHeader">
<input type="checkbox" id="chTest2" name="chTest2">
<label for="chTest2"><span>Files</span></label>
</div>
<div class = "thumbArea" id="fileArea">
</div>
</body>
CSS
.fileThumb{
width: 213px;
height: 183px;
border-radius: 2px;
border-style: solid;
border-width: 1px;
border-color: #EEEEEE;
text-align: center;
position: relative;
float:left;
margin: 18px;
display: none;
overflow: hidden;
}
how to change color of elements one by one using javascript(jquery) and then reset the result again one by one
.cub {
background: aqua;
width: 200px;
height: 200px;
display: inline-block;
}
You can add class and remove class using jQuery. First assign another class to these divs so no other divs will be affected.
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
var counter = 0;
var divs = $('.box'), div = null;
setInterval(function(){
div = $(divs[counter]);
if(div.hasClass('cub')){
div.removeClass('cub');
} else {
div.addClass('cub');
}
counter = (counter + 1) % 4;
}, 500);
Please try this code if it works. I was not able to check it but it should work.
<div class="cub"></div>
<div class="cub"></div>
<div class="cub"></div>
<div class="cub"></div>
.cub{ background-color: white; }
.cub.highlighted{ background-color: aqua; }
<script>
var highlighting = true;
$(document).ready(function(){
var highlightingInterval = setInterval(function(){
if( $(".cub.highlighted").length == 0 )
highlighting = true;
else if( $(".cub.highlighted").length == 4 )
highlighting = false;
if( highlighting )
{
$(".cub").not(".highlighted").eq(0).addClass("highlighted");
}
else
{
var targetIndex = $(".cub.highlighted").length - 1; $(".cub.highlighted").eq(targetIndex).removeClass("highlighted");
}
}, 2000 );//setInterval
});//document ready
</script>
So, what I'm hoping to do is change the text inside a set of <p> tags every half-second. The set of tags in question is in this block of code in my body:
<div class="outerdiv" id="col2">
<p id="matrixText"></p>
</div>
Right below the above code I have the JavaScript that should call a function every half-second:
<script type="text/javascript">
setInterval("changeMatrixText()", 500);
</script>
I have the function changeMatrixText defined inside my head:
function changeMatrixText()
{
var newtext = "";
for (var i = 0; i < 1000; i++)
newtext += Math.floor((Math.random()*10)+1) % 2 ? "0" : "1";
document.getElementById("matrixText").value = newtext;
}
As you see, that's supposed to set the text to a random string of 0's and 1's. But it's not working. Any idea why?
Just in case you need to see my entire code .....
<html>
<head>
<title>Simple encrypt/decrypt</title>
<style type="text/css">
body
{
background-color: #A9F5F2;
width: 900px;
padding: 0px;
}
.outerdiv
{
margin: 5px;
border: 2px solid #FF8000;
background-color: #FFFFFF;
}
.outerdiv > p
{
margin: 5px;
word-wrap:break-word
}
.outerdiv > h1
{
margin: 5px;
}
#col1
{
width: 500x;
height: 800px;
float: left;
}
#col2
{
width: 295px;
height: 1500px;
float: right;
font-family: Courier New;
overflow: hidden;
}
#title1div
{
font-family: Arial;
width: 100%;
}
#insctdiv
{
font-family: Arial;
width: 100%;
}
#iptdiv
{
height: 400px;
width: 100%;
}
#buttonsdiv
{
text-align: center;
width: 100%;
}
#inputText
{
width: 100%;
height: 100%;
resize: none;
}
</style>
<script type="text/javascript">
function encrypt()
{
var text = document.getElementById("inputText").value;
newstring = "";
/* Make newstring a string of the bit representations of
the ASCII values of its thisCharacters in order.
*/
for (var i = 0, j = text.length; i < j; i++)
{
bits = text.charCodeAt(i).toString(2);
newstring += new Array(8-bits.length+1).join('0') + bits;
}
/* Compress newstring by taking each substring of 3, 4, ..., 9
consecutive 1's or 0's and it by the number of such consecutive
thisCharacters followed by the thisCharacter.
EXAMPLES:
"10101000010111" --> "10101401031"
"001100011111111111111" --> "0011319151"
*/
newstring = newstring.replace(/([01])\1{2,8}/g, function($0, $1) { return ($0.length + $1);});
document.getElementById("inputText").value = newstring;
}
function decrypt()
{
var text = document.getElementById("inputText").value;
text = text.trim();
text.replace(/([2-9])([01])/g,
function (all, replacementCount, bit) {
return Array(+replacementCount + 1).join(bit);
}).split(/(.{8})/g).reduce(function (str, byte) {
return str + String.fromCharCode(parseInt(byte, 2));
}, "");
document.getElementById("inputText").value = text;
}
function changeMatrixText()
{
var newtext = "";
for (var i = 0; i < 1000; i++)
newtext += Math.floor((Math.random()*10)+1) % 2 ? "0" : "1";
document.getElementById("matrixText").value = newtext;
}
</script>
</head>
<body>
<div id="col1">
<div class="outerdiv" id="title1div">
<h1>Reversible text encryption algorithm</h1>
</div>
<div class="outerdiv" id="insctdiv">
<p>Type in or paste text below, then click <b>Encrypt</b> or <b>Decrypt</b></p>
</div>
<div class="outerdiv" id="iptdiv">
<textarea id="inputText" scrolling="yes"></textarea>
</div>
<div class="outerdiv" id="buttonsdiv">
<button onclick="encrypt()"><b>Encrypt</b></button>
<button onclick="decrypt()"><b>Decrypt</b></button>
</div>
</div>
<div class="outerdiv" id="col2">
<p id="matrixText"></p>
</div>
<script type="text/javascript">
setInterval("changeMatrixText()", 500);
</script>
</body>
</html>
In essence, I'm trying to make the right column of my page keep printing inside a new string of 0's and 1's every half-second, kinda like on the computer screen on the movie The Matrix, if you catch my drift.
According to MDN, the elements with a value attribute include <button>, <option>, <input>, <li>, <meter>, <progress>, and <param>. You'll need to set the innerHTML instead.
document.getElementById("matrixText").value = newtext;
to
document.getElementById("matrixText").innerHTML = newtext;
and
setInterval("changeMatrixText()", 500);
to
setInterval(changeMatrixText, 500);
Working Demo
document.getElementById("matrixText").value = newtext;
.value is used for form fields instead use
document.getElementById("matrixText").innerHTML = newtext;
in your changeMatrixText function
Here's an example of how you can do this:
http://jsfiddle.net/35W4Z/
The main difference is that a <p> element doesn't have a .value attribute. Instead, use the innerHTML attribute (as shown in the JSFiddle example)
Hope this helps!
Well for fun, I stuck this in a fiddle: http://jsfiddle.net/jdmA5/1/
So two things, mostly:
1) You can't set the "value" of a div element. You have to set the .innerHTML:
document.getElementById("matrixText").innerHTML = newtext;
2) This could be due to the fact I built this out in fiddle, but setInterval is notorious for not running like you expect unless you give each iteration its own memory space. I did this by wrapping the call to changeMatrix in a anonymous function:
setInterval(function() {changeMatrixText();}, 500);
Check out the jsfiddle link to see it in action.
Have you tried changing the setInterval method to accept the first argument as the function itself (the name, minus the parentheses), rather than a string...
As you are not passing any parameters explicitly, you can invoke the function as follows:
setInterval(changeMatrixText, 500);
Should you have needed to supply some parameters, then the following would work:
setInterval(function() {
changeMatrixText(myParam1, myParam2); // etc, etc
}, 500);