Ok, so i have an unordered list and it has two items. Now in my javascript i am trying to add event listener to these items so that a CSS class can be applied to them once clicked. here is the code. can anyone fill the missing part in here.Thanks
html part:-
<body>
<h3>Simple Add/Remove Task</h3>
<h4>To do List</h4>
<ul>
<div>
<li class="todos">Wake up</li>
<li class="todos">Study</li>
</div>
<div>
<button>Delete</button><br>
<button>Delete</button>
</div>
</ul>
<script type="text/javascript" src="./script.js"></script>
</body>
Js part:-
var listItems = document.getElementsByClassName("todos");
for (var i = 0; i<listItems.length; i++){
listItems[i].addEventListener("click", function(){
})
}
Just add or toggle the desired class with classList.add() or classList.toggle().
Also (FYI):
Headings should not be used because of the way they style the text
within them. As with everything else in HTML, they are semantic. You
shouldn't have an h4 unless you want a new sub-section to an h3,
which you wouldn't have unless it was a sub-section of an h2 an so
on. You can (and should) do your formatting with CSS, not HTML.
It is also invalid to put a div directly inside of a ul. Only
li, script, or template elements can be children of a ul or
ol.
Don't use .getElementsByClassName(). Use .querySelectorAll() instead.
var listItems = document.querySelectorAll(".todos");
for (var i = 0; i<listItems.length; i++){
listItems[i].addEventListener("click", function(){
this.classList.toggle("active"); // each click toggles the use of the class
});
// While looping over the bullets, search for the button within each
// and set up a click handler for when the delete button gets clicked
// .closest() will look for the nearest ancestor that matches the selector.
listItems[i].querySelector("button").addEventListener("click", function(){
this.closest(".todos").remove();
});
}
h1 { font-size: 1.2em; }
h2 { font-size: 1em; }
.active { background-color:yellow; }
<h1>Simple Add/Remove Task</h1>
<h2>To do List</h2>
<ul>
<li class="todos">Wake up <button>Delete</button></li>
<li class="todos">Study <button>Delete</button></li>
</ul>
use this line in js to change the class:
listItems[i].className = 'cssClass';
and then make some 'cssClass' css. Unless you want to make the css created in js, in which case you would do this beforehand:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.cssClass { color: green; }';
Use for...of to iterate over the elements.
Use the event.currentTarget to get the selected element.
Use classList.add to add a class to an element
var listItems = document.getElementsByClassName("todos");
for (let listItem of listItems) {
listItem.addEventListener("click", event => {
event.currentTarget.classList.add('selected')
})
}
.selected {
background: green;
}
<body>
<h3>Simple Add/Remove Task</h3>
<h4>To do List</h4>
<ul>
<li class="todos">Wake up</li>
<li class="todos">Study</li>
</ul>
</body>
Related
I'm relatively new to JavaScript, so I'm not sure if I'm doing things conventionally here, of if there's a better way of doing what I'm trying to do.
I have a JavaScript function that takes about 3,600 sentences from a JSON document and inserts them automatically into my HTML code. A unique id is generated for each once in the HTML.
I want to create an onclick event for each sentence so that when it's clicked more information appears underneath about the sentence. This means I have to declare thousands of variables, one for each sentence and one for each information div associated with that sentence:
var sent1 = document.getElementById('s1');
var sent1info = document.getElementById('s1info');
var sent2 = document.getElementById('s2');
var sent2info = document.getElementById('s2info');
var sent3 = document.getElementById('s3');
var sent3info = document.getElementById('s3info');
...
This is way too much to do manually. Is there a way to automate the process of declaring these variables, or is there a better way to do what I'm doing?
For context, my intention with each variable is to feed it into this function:
sent1.onclick = function(){
if(sent1info.className == 'open'){
sent1info.className = 'close';
} else{
sent1info.className = 'close';
}
};
From here the CSS will reduce the info box to a hight of 0 when the className is 'close' and expand it when the className is 'open'. But, again, this will require me writing out this function thousands of times.
Is there a way to do this automatically also? Or am I going about this all wrong?
Edit to show HTML:
<!DOCTYPE html>
<html>
<head>...</head>
<body>
<div id="everything">
<header id="theheader" class="clearfix">...</header>
<div id="thebody" class="box clearfix">
<aside id="page" class="side">...</aside>
<div class="items">
<article id="content" class="article">
<img id="sentpic" src="sentpic.jpg">
<h1>Sentences</h1>
<div id="sentences">
*** This is where the JS inserts sentences and information ***
<ul id='sent1' class='sentcontent'><li class='number'>1.</li><li class='thesent'>...</li></ul>
<div id='sent1info' class='infobox'>
<ul class='sentinfo'><li class='information'>Info:</li><li class='infotext'><em>...</em></li></ul>
<ul class='sentinfo'><li class='information'>Line:</li><li class='line'>...</li></ul>
</div>
<ul id='sent2' class='sentcontent'><li class='number'>2.</li><li class='thesent'>...</li></ul>"
<div id='sent2info' class='infobox'>
<ul class='sentinfo'><li class='information'>Info:</li><li class='infotext'><em>...</em></li></ul>
<ul class='sentinfo'><li class='information'>Line:</li><li class='line'>...</li></ul>
</div>
*** it goes on like this for each sent inserted ***
</div>
</article>
</div>
</div>
<div class="associates clearfix">...</div>
<footer class="foot">...</footer>
</div>
<script type="text/javascript" src="index.js"></script>
</body>
</html>
Using HTML <details> element:
const json = [
{thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
{thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];
const template_sentence = (ob, i) => `
<details class="sentence">
<summary>${i+1} ${ob.thesent}</summary>
<h3>${ob.info}</h3>
<div>${ob.line}</div>
</details>`;
document.querySelector("#sentences").innerHTML = json.map(template_sentence).join('');
<div id="sentences"></div>
Otherwise, by using your current non-semantic markup:
Targeting by ID (in your specific case) is not needed. There's other methods like the + Next Adjacent sibling selector in CSS.
And here's a JS example - should be self-explanatory, but feel free to ask.
Use JS to toggle a class (.active in this example) to the clickable UL element
Use CSS and the Next adjacent sibling selector + to make the info DIV display: block
/* Just a sample... you'll know how to modify this with the right properties I hope */
const json = [
{thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
{thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];
// The toggle function:
const toggleInfobox = ev => ev.currentTarget.classList.toggle("active");
// A single sentcontent template
const template_sentence = (ob, i) =>
`<ul class='sentcontent'>
<li class='number'>${i+1}</li>
<li class='thesent'>${ob.thesent}</li>
</ul>
<div class='infobox'>
<ul class='sentinfo'>
<li class='information'>Info:</li>
<li class='infotext'><em>${ob.info}</em></li>
</ul>
<ul class='sentinfo'>
<li class='information'>Line:</li>
<li class='line'>${ob.line}</li>
</ul>
</div>`;
// Get target element
const el_sentences = document.querySelector("#sentences");
// Loop JSON data and create HTML
el_sentences.innerHTML = json.map(template_sentence).join('');
// Assign listeners
const el_sentcontent = el_sentences.querySelectorAll(".sentcontent");
el_sentcontent.forEach(el => el.addEventListener('click', toggleInfobox));
/* BTW, why do you use <ul> ? That's not a semantic list! */
.sentcontent { padding: 0; cursor: pointer;}
.sentcontent li { display: inline-block; }
/* Arrows are cool, right? */
.sentcontent:before { content: "\25BC"; }
.sentcontent.active:before { content: "\25B2"; }
/* Hide adjacent .infobox initially,
/* and show adjacent .infobox on JS click */
.sentcontent + .infobox { display: none; }
.sentcontent.active + .infobox { display: block; }
<div id="sentences"></div>
In this Stack overflow answer you can find out more about toggling an element on some button click.
This question is more of an architectural issue than a need for creating dynamic variables. Consider this example:
ids are removed (existing class names used)
This pattern scales for n sentence instances
In handleClick, we toggle the open class on the clicked element, which lets us leverage the adjacent sibling selector via CSS
No need for a close class, since the absence of the open class represents the closed state.
let outerUL = document.querySelectorAll('.sentcontent')
function handleClick() {
this.classList.toggle('open');
}
outerUL.forEach(ul => {
ul.addEventListener('click', handleClick);
})
.sentcontent {
cursor: pointer;
}
.sentcontent.open + .infobox {
display: block;
}
.infobox {
background-color: #eee;
display: none;
padding: .25em .5em;
}
<ul class='sentcontent'>
<li class='number'>1.</li>
<li class='thesent'>Sent</li>
</ul>
<div class='infobox'>
<ul class='sentinfo'>
<li class='information'>Info</li>
<li class='infotext'><em>Info text</em></li>
</ul>
<ul class='sentinfo'>
<li class='information'>Line info</li>
<li class='line'>Line</li>
</ul>
</div>
<ul class='sentcontent'>
<li class='number'>2.</li>
<li class='thesent'>Sent</li>
</ul>
<div class='infobox'>
<ul class='sentinfo'>
<li class='information'>Info</li>
<li class='infotext'><em>Info text</em></li>
</ul>
<ul class='sentinfo'>
<li class='information'>Line info</li>
<li class='line'>Line</li>
</ul>
</div>
https://jsfiddle.net/d91va7tq/2/
When you have a very large json data then its good idee to keep in mind too not render the whole data at once, it will effect the webbrowser performance. Instead render when needed. And that is when the user click for more information.
I did some example below, make sure too read the comment
const json = [
{thesent:"Lol", info:"This is some info 1", line:"Whatever 1..."},
{thesent:"Lorem", info:"Some info 2", line:"Something here 2..."},
];
const container = document.querySelector(".container");
json.forEach((item)=> {
let x= item;
let el = document.createElement("li");
el.innerHTML = x.thesent;
container.appendChild(el);
el.addEventListener("click",()=> {
var infoContainer= el.querySelector(".info");
// dont create all html element at once, instead create them
//when the user click on it. this is better when you have a very large data.
if (!infoContainer){ // not created, then create
infoContainer = document.createElement("div");
infoContainer.className="info";
var info = document.createElement("div");
var line = document.createElement("div");
info.innerHTML = x.info;
line.innerHTML = x.line;
infoContainer.appendChild(info);
infoContainer.appendChild(line);
el.appendChild(infoContainer);
} else if (infoContainer.style.display == "none") // created and hidden, then display it
infoContainer.style.display = "block";
else infoContainer.style.display= "none"; // already displayed then hide it
});
})
.container li >div.info >div:first-child{
font-size: 12px;
}
.container li >div.info >div:last-child{
font-size: 10px;
}
<ul class="container">
</ul>
i'm fairly new to javascript programming and i want to learn it more. I want to remove a class name from every node of a nodeList when i click on any node from the same nodeList.
I wrote this code:
d = document.querySelectorAll(".chat-line__message");
d.forEach(removeHighlight);
function removeHighlight(item){
item.addEventListener("click", function(){
item.forEach(function(element){
element.classList.remove("highlight");
});
//for-loop instead of forEach doesn't work either.
})
}
What am i doing wrong? Thank you.
To remove the .highlight class from every node in the nodeList, iterate over them in the click event handler and remove the .highlight class from there:
var elements = document.querySelectorAll(".chat-line__message");
elements.forEach(function(item) {
item.addEventListener("click", function() {
elements.forEach(function(element) {
element.classList.remove("highlight");
});
})
});
ul {
list-style-type: none;
padding: 0;
}
li:hover {
background: cornflowerblue;
}
.chat-line__message {
font-size: 20px;
font-weight: bold;
}
.chat-line__message.highlight {
background: orange;
}
<ul>
<li class="chat-line__message highlight">A</li>
<li class="chat-line__message">B</li>
<li class="chat-line__message highlight">C</li>
<li class="chat-line__message">D</li>
<li class="chat-line__message highlight">E</li>
</ul>
item is a single element...the one you assign the click listener too.
You want to loop over the collection to remove the class from all the elements in the collection
function removeHighlight(item){
item.addEventListener("click", function(){
d.forEach(function(element){
// ^^ iterate collection
element.classList.remove("highlight");
});
});
}
if I understand your doubt than you were almost there:
<button onclick="myFunction()">Try it</button>
<div class="myDIV">
This is a DIV element.
</div>
<div class="myDIV">
This is a DIV element.
</div>
<script>
function myFunction()
{
d = document.querySelectorAll(".myDIV");
d.forEach(removeHighlight);
}
function removeHighlight(item) {
item.classList.toggle("highlight");
}
</script>
Have fun in javascript coding!
Maybe I'm way off, but here we go.
print '<li '.$class.'><a id="flodet" href="index.php?artikelid='.$rad["id"].'">'.$rad["header"].'</a> </li>';
This line print links to articles from a database. The class flodet just style the link. What I want to do is to create another div inside the class flodet. I have tried to do this with these couple of lines of javascript.
function myFunc() {
var bild = document.createElement("div");
document.getElementById('flodet').appendChild(bild);
}
Am I way off or am I on the right track?
Here is a snippet to play around with.
Few suggestions:
'<li '.$class.'> - this seems to be wrong ; use the attribute class
You could select the li using ul > li if needed and can avoid setting class to each li; You could even decorate the parent ul with a class and select the li's using ul.myList li where myList is the class of ul
function myFunc() {
/* To add a 'div' inside the list item anchor */
/*
var bild = document.createElement("div");
bild.innerHTML = "My new DIV";
document.getElementById('flodet').appendChild(bild);
*/
/* To add a 'div' inside each list item */
var listItems = document.querySelectorAll("ul > li");
for (var i = 0; i < listItems.length; i++) {
var bild = document.createElement("div");
bild.innerHTML = "My Div" + i;
/* Add an attribute, say 'class' */
bild.setAttribute("class", "divClass");
listItems[i].appendChild(bild);
}
}
window.onload = myFunc;
/* To select the list items */
ul > li {
color: #DDD;
}
.divClass {
border: 1px solid #F2F2F2;
}
<ul>
<li>
<a id="flodet" href="">Link 1</a>
</li>
<li>
<a id="flodet2" href="">Link 2</a>
</li>
<li>
<a id="flodet3" href="">Link 3</a>
</li>
</ul>
You are most likely on the right track, but let me suggest one thing about your tiny code-piece:
I you are using styles to brush up the link, you are better of to set the class-attribute on the link rather than the id. ID's should be unique - That might not be the case, if there are more elements of this type generated by your code.
document.getElementById('flodet').insertAdjacentHTML("beforeend", "<div class='inline'> World!</div>");
.inline {
display: inline-block;
}
<div id="flodet">Hello </div>
looks okay, add it inside a document.ready or something simular and you should be good to go.
I would suggest one change though,
Instead of
var bild = document.createElement("div");
document.getElementById('flodet').appendChild(bild);
i would just do
document.getElementById('flodet').insertAdjacentHTML("beforeend", "<div>Hello World!</div>");
So when someone hover a <li> I need that my Div get his class changed.
How can I do This?
Is this possibile using only css or do I need to put some JS inside?
Edit 1: each li will have a especific id, and the div would recive the id as a class.
I think you should to use JQuery:
$(document).ready(function(){
$("li").mouseover(function(event){
$("#capa").addClass("class");
});
});
To assign a class to the parenting <div> element based on the ID of a hovered child <li>, first check for the hover and get the ID name, then assign it to the parenting <div>.
The following is a code that you will be able to use for several divs on a page, and it will reset the class names on leaving the <li> hover, by using the out handler of the jQuery method:
$(".changeme ul li").hover(function(){
$(this).parents("div").addClass($(this).attr("id"));
}, function(){
$(this).parents("div").removeClass($(this).attr("id"));
});
.changeme{
background-color:#eee;
}
.changeme.firstli{
background-color:#ffd;
}
.changeme.secondli{
background-color:#fdd;
}
.changeme.thirdli{
background-color:#dfd;
}
.changeme.fourthli{
background-color:#ddf;
}
.changeme.fifthli{
background-color:#ddd;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="unaffected">
<p> some other parenting div, not affected</p>
<div class="changeme">
<p>some text, nothing changes</p>
<ul>
<li id="firstli">we are changing our parentting div!</li>
<li id="secondli">we are changing our parentting div!</li>
<li id="thirdli">we are changing our parentting div!</li>
</ul>
<p>some text, nothing changes</p>
<ul>
<li id="fourthli">we are changing our parentting div!</li>
<li id="fifthli">we are changing our parentting div!</li>
</ul>
<p>some text, nothing changes</p>
</div>
</div>
https://jsfiddle.net/svArtist/adq5dr68/
Go to your div style class definitions and add "li:hover" near the name;
.yourDiv { font-size:14pt; }
then turn to this
.yourDiv li:hover { font-size:14pt; }
You could just use the :hover property, that way you wouldn't have to change the div's class, which you can only do with javascript.
CSS hover attributes can be used to specify how an element should appear on hover, but not how some other element should appear when the first is hovered over. Achieving behavior of that complexity requires a touch of JavaScript.
(function() {
var div = document.getElementById("parent"); // save a reference to the target div
var lis = div.querySelectorAll("li"); // get your <li> tags
for (var i = 0, len = lis.length; i < len; i++) {
lis[i].onmouseover = updateDivClass; // attach the event listener to each tag
}
div.onmouseout = function() { // remove class when no longer hovering over div
this.className = "";
};
function updateDivClass() { // apply class to div when hovering over <li> tag
div.className = this.id;
}
})();
.Class1 {
background-color: #df7000;
font-family: Calibri;
color: black;
}
.Class2 {
background-color: purple;
color: white;
font-family: Segoe UI;
}
.Class3 {
background-color: black;
color: lightgreen;
font-family: courier;
}
<div id="parent">
Hover over a class below to apply the class to the entire div.
<ul>
<li id="Class1">Black Calibri with Orange Background</li>
<li id="Class2">White Segoe UI with Purple Background</li>
<li id="Class3">Light Green Courier with Black Background</li>
</ul>
</div>
I have trouble in writing a script to change the appearance of the clicked tab in a webpage navigation list. In other words, I want to make the clicked tab appear as the selected (in code). I tried to do that by changing its id to selected_link and restoring the id of the previously selected tab.
EDIT: Following jamespaned's suggestion, I replaced element IDs with classes.
My tabs appear like in this picture:
So, when I click to "bio", I want it to appear as "home" and "home" to appear as the other tabs.
As I'm a newbie in JavaScript coding, I didn't managed to accomplish that. Here is what I've done:
The HTML code for the (inline) navigation list:
<nav>
<ul id="navlist">
<li class="selected"> home </li>
<li class=""> bio </li>
<li class=""> publications </li>
<li class=""> software </li>
<li class=""> contact </li>
</ul>
</nav>
its respective CSS:
nav ul {
list-style:none;
padding:0;
margin:0;
}
nav li {
background-color:black;
display:inline;
border:solid;
border-width:1px 1px 0 1px;
margin:0 5px 0 0;
}
nav li a {
color:white;
padding:0 10px;
}
.selected {
background-color:white;
padding-bottom: 1px;
}
.selected_link{
color:blue;
}
and the JavaScript which I've designed to accomplish this task, but it didn't worked:
function changeSelected(clickedId)
{
var ulist = document.getElementById("navlist");
var elems = ulist.getElementsByTagName("class");
for (var i = 0; i < elems.length - 1; i++)
{
var sel = elems[i].getAttribute("class");
if (sel == selected)
{
var selli = elems[i];
break;
}
}
selli.setAttribute("class", "");
selli.lastElementChild.setAttribute("class", "");
var clicked = document.getElementById(clickedId);
clicked.setAttribute("class", "selected_link");
clicked.parentNode.setAttribute("class", "selected");
}
How could I do that using only plain JavaScript?
This Javascript will do what you want:
function changeSelected(clickedId)
{
var selli = document.getElementById("selected");
var sela = document.getElementById("selected_link");
sela.setAttribute("id", "");
selli.setAttribute("id", "");
var clicked = document.getElementById(clickedId);
clicked.setAttribute("id", "selected_link");
clicked.parentNode.setAttribute("id", "selected");
}
That said, here are some ideas that might help your Javascript education:
You are using Javascript to set your IDs, but the Javascript won't work on the next page after you've clicked on one of the links. You'll probably need to do some backend (PHP/Ruby, etc) coding to get your styles to change.
IDs are normally used to refer to a unique element on the page that doesn't change, such as a #header or #sidebar_banner. You might want to use a class instead, such as ".selected_link".
You don't need both #selected_link and #selected. You could do ".selected" and ".selected a" to change the CSS so you only need to change one element.
Hope that helps!