I have multiple items in a row that I want to easily change the style of the border based on my selection.
Here is the HTML of just the row and some of the items in it:
<div class="items">
<ul>
<li class="item-hold">
<span class="item icon64x64">
<img class="item-img icon64x64" src="css/img/3001.png" alt="Abyssal Scepter" id="as">
</span>
</li>
<li class="item-hold">
<span class="item icon64x64">
<img class="item-img icon64x64" src="css/img/3020.png" alt="Sorcerer's Shoes" id="ss">
</span>
</li>
<li class="item-hold">
<span class="item icon64x64">
<img class="item-img icon64x64" src="css/img/3025.png" alt="Iceborn Gauntlet" id="ig">
</span>
</li>
</ul>
</div>
I have tried to do if !(obj).style..... However that won't work and I cannot find any solutions anywhere.
I Know how to do this with states and cases. However, I didn't want my JS to be a few 100 lines long.
So here is my js
var as = document.getElementById('as');
var ss = document.getElementById('ss');
var ig = document.getElementById('ig');
as.addEventListener('click', function() {
ItemDisc('as');
});
ss.addEventListener('click', function() {
ItemDisc('ss');
});
ig.addEventListener('click', function() {
ItemDisc('ig');
});
function ItemDisc(obj) {
var change = document.getElementById(obj);
var changeback = document.getElementById(!obj);
change.style.border = "5px solid blue";
for(!obj) {
changeback.style.border = "5px solid blue";
}
}
You can also use this as your JS:
var imgs = document.getElementsByClassName('item-img');
for(i=0; i<imgs.length; i++) {
imgs[i].addEventListener('click', function(){
for (i=0; i<imgs.length; i++)
imgs[i].style.border='1px solid blue';
this.style.border = '1px solid red';
});
}
This is a basic demo that could be improved upon.
The main idea is to loop through all the items and "reset" them to their default state. Then apply the selection style to the selected element.
<div class="items">
<ul>
<li>
<img src="https://placehold.it/50x50&text=01">
</li>
<li>
<img src="https://placehold.it/50x50&text=02">
</li>
<li>
<img src="https://placehold.it/50x50&text=03">
</li>
</ul>
</div>
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
li {
display: inline-block;
margin: 0 1rem;
}
.highlight {
border: 2px solid red;
}
// Get all items.
var items = document.querySelectorAll( '.items li' );
// Adding/removing selection style via a CSS class.
function addHighlight() {
// Loop through all items and remove the selection class.
for ( var i = 0, len = items.length; i < len; i++ ) {
items[i].className = items[i].className.replace( 'highlight', '' );
}
// Add selection class to selected item.
this.className += ' highlight';
}
// Add click event handler to items.
function addEventListener( items, event, listener ) {
for ( var i = 0, len = items.length; i < len; i++ ) {
items[ i ].addEventListener( event, listener );
}
}
addEventListener( items, 'click', addHighlight );
Demo JSFiddle.
I dont understand what you are trying to do, so I can't recreate something in its entirety.
I can point you in the right direction though.
Your problem is on line
var changeback = document.getElementById(!obj)
!obj is being resolved to the Boolean 'false', and not the element you are selecting.
Furthermore, you are using 'for', when you should be using 'if'
For is creating loops, and 'if' is for conditions
if(!obj) {
changeback.style.border = "5px solid blue";
}
Also, the border color is exactly the same.
I think it is possible to achieve what you want by changing your ItemDisc(obj) function to this.
function ItemDisc(obj){
element = document.getElementById(obj);
if(element.classList.contains('active')){
element.className += " active";
element.style.border = "5px solid blue";
} else {
element.className = "";
// Careful, because this will remove all classes from your element.
}
}
Just wanted to say... This is without jQuery, also, you can make it easier by adding styles to your css class 'active' which included borders.
}
This is very simple to do with jQuery. I'd recommend learning jQuery because it will familiarize you with both css-selectors and JavaScript. Here's a boilerplate to get you started, please forgive any typos:
<style>
.active{border:5px solid #0000FF;}
</style>
$(".item-img").click(function(){
.each(".item-img"){
myFunction( $(this).attr("id") );
}
});
function myFunction(theID){
if( $(this).attr("id") == theID ){
$(this).addClass("active");
}else{
$(this).removeClass("active");
}
}
You will want to load jQuery in your html. Also, you'll need to wrap the js above in:
$(document).ready(function(){/*above code goes here*/});
Related
I can select any item in the list by clicking on it and apply border. Then When I click on right arrow button to select next item from where I already picked item by clicking on it is not working. It selects next item but only once. I want that to apply for every item by clicking on right arrow one by one. same thing in reverse order for leftarrow. Can someone help me with pure javascript. below is my script working only for once clicked.
<ul id="gallery">
<li><img src="images/one.jpg" /></li>
<li><img src="images/two.jpg" /></li>
<li><img src="images/three.jpg" /></li>
<li><img src="images/four.jpg" /></li>
</ul>
<div id="leftArw"></div>
<div id="rightArw"></div>
var list = document.getElementById("gallery").getElementsByTagName("LI");
var items, currentDiv, leftArw, rightArw;
leftArw = document.getElementById("leftArw"),
rightArw = document.getElementById("rightArw");
rightArw.addEventListener("click", right, false);
for (items = 0; items < list.length; items++) {
list[items].style.border = "none";
//list[items].addEventListener("click", currentItem, false);
list[items].onclick = function () {
currentDiv = this;
this.style.border = "5px solid red";
}
}
function right() {
currentDiv.nextElementSibling.style.border = "5px solid red";
}
// click handler to set the current "selected" element
document.querySelector("#gallery").addEventListener("click", function(e) {
// list items are the only valid "click" source to work with
if (e.target.nodeName !== "LI") {
return;
}
var currentlySelectedElement = e.currentTarget // the <ul> element
.querySelector(".selected");
if (currentlySelectedElement !== null) {
currentlySelectedElement.className = "";
}
e.target // the <li> element
.className = "selected";
}, false);
// click handler for the "arrow" button
var right = (function() { // Closure to only query the DOM for the <li> elements once
var items = document.querySelectorAll("#gallery li");
function getSelectedItem() {
var l = items.length,
i = 0;
for (; i < l; i++) {
if (items[i].className === "selected") {
return items[i];
}
}
return null;
}
// actual click handler to select the next element
return function() {
var selectedItem = getSelectedItem(),
nextItem;
if (selectedItem !== null) {
nextItem = selectedItem.nextElementSibling || items[0];
selectedItem.className = "";
nextItem.className = "selected";
}
};
}());
document.querySelector("#rightArw").addEventListener("click", right, false);
.selected {
outline: solid 1px red
}
#rightArw {
width: 50px;
height: 50px;
background-color: yellow
}
<ul id="gallery">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<div id="rightArw"></div>
Edit
You've mentioned in the comments, that the script won't work if you add <img /> in the <li /> elements.
<li><img src="images/one.jpg" /></li>
That's because the "click" event isn't longer triggered from the <li /> but from the <img /> element. That is, the "selected" state is now set on <img /> because of e.target.
When you now click on the "arrow" the handler looks for an <li /> with the class selected (selectedItem = getSelectedItem()) which he cannot find and therefor won't go to the next <li /> element (if (selectedItem !== null)).
To get this script back to work you will have to adjust the e.target part.
In this case you will have to walk one step up (.parentNode) in the DOM:
document.querySelector("#gallery").addEventListener("click", function(e) {
// images are the only valid "click" source to work with
if (e.target.nodeName !== "IMG") {
return;
}
var currentlySelectedElement = e.currentTarget // the <ul> element
.querySelector(".selected");
if (currentlySelectedElement !== null) {
currentlySelectedElement.className = "";
}
e.target // the <img />
.parentNode // the <li> element
.className = "selected";
}, false);
var right = (function() {
var items = document.querySelectorAll("#gallery li");
function getSelectedItem() {
var l = items.length,
i = 0;
for (; i < l; i++) {
if (items[i].className === "selected") {
return items[i];
}
}
return null;
}
return function() {
var selectedItem = getSelectedItem(),
nextItem;
if (selectedItem !== null) {
nextItem = selectedItem.nextElementSibling || items[0];
selectedItem.className = "";
nextItem.className = "selected";
}
};
}());
document.querySelector("#rightArw").addEventListener("click", right, false);
.selected {
outline: solid 1px red
}
#rightArw {
width: 50px;
height: 50px;
background-color: yellow
}
<ul id="gallery">
<li><img src="images/one.jpg" /></li>
<li><img src="images/one.jpg" /></li>
<li><img src="images/one.jpg" /></li>
<li><img src="images/one.jpg" /></li>
</ul>
<div id="rightArw"></div>
Edit 2
I've added yet another check in the <ul /> click handler (right at the top) to prevent the handler to run on clicks which are not triggered by a <li /> (in the first example) or an <img /> in the second example.
Note: I can't use jQuery, only vanilla javascript
I'm not really fluent in pure JS. And this time I can't use any external resources (like jquery).
What I need:
If div1 class is active, hide text2
If div2 class is active, hide text1
I made it somehow to work, but my JS doesn't trigger when the class changes dynamic with another javascript code.
Code that triggers the active class
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
}
Code that should trigger hide/show when the class changes
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
What did I do wrong?
Codepen demo
Place your conditions inside click handler.
Add inline visibility style for inactive element
function activeClass(elem) {
var a = document.getElementsByClassName('item')
for (i = 0; i < a.length; i++) {
a[i].classList.remove('active')
}
elem.classList.add('active');
if (document.querySelector(".text2").classList.contains("active")) {
document.getElementsByClassName('text1s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text2s')[0].style.visibility = 'visible';
}
if (document.querySelector(".text1").classList.contains("active")) {
document.getElementsByClassName('text2s')[0].style.visibility = 'hidden';
document.getElementsByClassName('text1s')[0].style.visibility = 'visible';
}
}
body {
margin: 3em;
}
.item {
cursor: pointer;
}
a {
padding: 10px;
}
.active {
color: red;
border: 1px solid red;
}
<a class="item text1" onclick="activeClass(this)">show text</a>
<a class="item text2 active" onclick="activeClass(this)">hide text</a>
<br>
<br>
<h1 class="text1s" style='visibility:hidden;'>TEXT 1</h1>
<h1 class="text2s">TEXT 2</h1>
Updated Codepen
I am trying to work out to select a delete icon in my own web application. delectIcon
HTML
<main>
<div class="container">
<div class="tabs">
<p><span class="active">Newest</span></p><a href=""><p>
<span>Oldest</span></p></a><p><span>Add</span></p>
</div>
<div class="content">
<ul>
<li>
<span class="itemLeft">Answer emails</span>
<span class="itemMiddle">12-31-2016</span>
<span class="itemRight">1</span>
<b class="deleteIcon"> X </b>
</li>
<li>
<span class="itemLeft">Prep for Monday's class</span>
<span class="itemMiddle">12-31-2016</span>
<span class="itemRight">5</span>
<b class="deleteIcon"> X </b>
</li>
</ul>
</div>
</div>
</main>
JavaScript
$(".deleteIcon").on("click", function () {
alert("Oh, clicked!");
return false;
});
I failed to do so by writing it myself. So I used Chrome Web Developer Tool to find the CSS path. I tried to use the XPath($"[/html/body/main/div/div[2]/ul/li[ 1 ]/b]") and CSS Path ($"(pathbody > main > div > div.content > ul > li:nth-child(1) > b)"). Neither of them worked.
I tried to mark it with an ID and made only one "li" exists. The CSS selector worked all right. But when I clicked the deleteIcon$"(#deleteIcon)", nothing happened.
#deleteIcon{
float:right;
font-weight: bold;
padding: 0 3px 0 3px;
border-radius: 5px;
background: #ccc;
cursor: pointer;
margin-left: 5px;
font-size: 1.3em;
text-align: center;
}
I also tried to select my title. I found the following worked out.
$(".container h1").on("click", function () {
alert("Oh, no!");
return false;
});
I do not what to do now. Can anyone help me out here?
Thank you! I would be really appreciate if you can answer my question.
Adding more details:
I did actually add the deleteIcon into the HTML by JavaScript. I do not know whether this can have an effect on my selector.
Actual HTML
<main>
<div class="container">
<div class="tabs">
<p><span class="active">Newest</span></p><a href=""><p>
<span>Oldest</span></p></a><p><span>Add</span></p>
</div>
<div class="content">
</div>
</div>
</main>
JavaScript (The important part listed below)
function Item(name,dueDate,type){
this.name=name;//1
this.dueDate=dueDate;//input2
this.type=type;//3
};
$(".tabs a span").toArray().forEach(function (element) {
var $element = $(element);
// create a click handler for this element
$element.on("click", function () {
var $content,
$input,
$button,
i;
if ($element.parent().parent().is(":nth-child(1)")) {
// newest first, so we have to go through
// the array backwards
$content = $("<ul>");
for (i = Task.length-1; i >= 1; i--) {
// $buttondelete = $("<buttonDelete>").text("X");
var txt1 = Task[i].toStringName();
var txt2 = Task[i].toStringDate();
var txt3 = Task[i].toStringType();
//alert(txt3);
$content.append('<li> <span class="itemLeft">'+txt1+'</span> <span class="itemMiddle">'+txt2+'</span> <span class="itemRight">'+txt3+'</span><b class="deleteIcon"> X </b>');
}
}
$("main .content").append($content);
return false;
});
});
If you are creating the items inside ul dynamically you should bind the click event like this :
$(".content").on("click", ".deleteIcon", function()
{
alert("clicked") ;
return false;
}
) ;
The class selector starts with a . (just like the example you say you have that works).
Try
$(".deleteIcon").on("click", function () {
alert("Oh, clicked!");
return false;
});
Have a problem and can't get to solve it. Tried to use QuerySelectorAll and comma separating with GetElementsByClassName, but that didn't work, so I am wondering how to solve this problem.
I have this HTML:
<div class="area">Test title
<div class="some content" style="display: none">blablbala
<input></input>
</div>
<div class="two">This should be clickable too</div>
</div>
<div class="area">
Test title
<div class="some content">
blablbala
<input></input>
</div>
<div class="two">This should be clickable too</div>
</div>
JS:
function areaCollapse() {
var next = this.querySelector(".content");
if (this.classList.contains("open")) {
next.style.display = "none";
this.classList.remove("open");
} else {
next.style.display = "block";
this.classList.add("open");
}
}
var classname = document.getElementsByClassName("area");
for (var i = 0; i < classname.length; i++) {
classname[i].addEventListener('click', areaCollapse, true);
}
http://jsfiddle.net/1BJK903/nb1ao39k/6/
CSS:
.two {
position: absolute;
top: 0;
}
So now, the div with classname "area" is clickable. I positioned the div with class "two" absolute and now the whole div is clickable, except where this other div is. If you click on the div with classname "two", it doesn't work (it does not collapse or open the contents). How can I make this work, without changing the structure?
One way is using a global handler, where you can handle more than one item by checking its id or class or some other property or attribute.
Below snippet finds the "area" div and pass it as a param to the areaCollapse function. It also check so it is only the two or the area div (colored lime/yellow) that was clicked before calling the areaCollapse.
Also the original code didn't have the "open" class already added to it (the second div group), which mean one need to click twice, so I change the areaCollapse function to check for the display property instead.
function areaCollapse(elem) {
var next = elem.querySelector(".content");
if (next.style.display != "none") {
next.style.display = "none";
} else {
next.style.display = "block";
}
}
window.addEventListener('click', function(e) {
//temp alert to check which element were clicked
//alert(e.target.className);
if (hasClass(e.target,"area")) {
areaCollapse(e.target);
} else {
//delete next line if all children are clickable
if (hasClass(e.target,"two")) {
var el = e.target;
while ((el = el.parentElement) && !hasClass(el,"area"));
if (targetInParent(e.target,el)) {
areaCollapse(el);
}
//delete next line if all children are clickable
}
}
});
function hasClass(elm,cln) {
return (" " + elm.className + " " ).indexOf( " "+cln+" " ) > -1;
}
function targetInParent(trg,pnt) {
return (trg === pnt) ? false : pnt.contains(trg);
}
.area {
background-color: lime;
}
.two {
background-color: yellow;
}
.area:hover, .two:hover {
background-color: green;
}
.some {
background-color: white;
}
.some:hover {
background-color: white;
}
<div class="area">Test title clickable 1
<div class="some content" style="display: none">blablbala NOT clickable 1
</div>
<div class="two">This should be clickable too 1</div>
</div>
<div class="area">Test title clickable 2
<div class="some content">blablbala NOT clickable 2
</div>
<div class="two">This should be clickable too 2</div>
</div>
<div class="other">This should NOT be clickable</div>
You need to find your two elements while you're binding classname, and bind that as well.
var classname = document.getElementsByClassName("area");
for(var i=0; i < classname.length; i++){
classname[i].addEventListener('click', areaCollapse, true);
var twoEl = classname[i].getElementsByClassName("two")[0];
twoEl.addEventListener('click', function(e) { console.log('two clicked'); });
}
If you want to use jQuery:
$('.two').click(function(){
//action here
});
I have item group list
<div id="MainMenu">
<div class="list-group panel">
Menu 1
<div class="collapse" id="why">
Menu 1 a
Menu 1 b
Menu 1 c
Menu 1 d
Menu 1 e
Menu 1 f
</div>
Menu 2
<div class="collapse" id="joinus">
Menu 2 a
Menu 2 b
Menu 2 c
Menu 2 d
Menu 2 e
</div>
</div>
</div>
I want to change background of active list item, I Know how to change background, but I am unable to get which list is active, or inactive by JavaScript, tried lots of solution given on others but didn't woJrk.
JsFiddle
UPDATE:
Don't know why bootstrap isn't doing it, but here's some jQuery on a fiddle for you. The alert is displaying the href that is active.
Is that what you're after?
Update - 09/01/2022
Edited the old fiddle, here's the new one http://jsfiddle.net/dh7t3cbp/1/
$('.list-group').on('click', '> a', function(e) {
var $this = $(this);
$('.list-group').find('.active').removeClass('active');
$this.addClass('active');
alert($this.attr('href') + ' is active');
});
$('.list-group .collapse').on('click', '> a', function(e) {
var $this = $(this),
$parent = $this.parent('.collapse');
$parent.find('.active').removeClass('active');
$this.addClass('active');
alert($this.attr('href') + ' is active');
});
.list-group panel.active, .list-group panel.active a.active {
background-color: #030;
border-color: #aed248;
}
Add the following css in your code as :
.list-group-item[aria-expanded="true"]{
background-color: black !important;
border-color: #aed248;
}
Demo
What i does it assign and id to every link in list that is also the page name, and made a js function that is called on body load of the page. the function get the current file name from url and determines which page is this, then by js i made that link class active. this solve my problem. however i share this solution for others to improvement.
function get_current_page() {
var pathArray = window.location.pathname.split("/");
var current_page = pathArray[pathArray.length - 1];
current_page_array = current_page.split(".");
current_page = current_page_array[0];
if (
current_page == "students" ||
current_page == "my-profile" ||
current_page == "faqs" ||
current_page == "forecast-career"
) {
document.getElementById("joinuslist").className += " active";
document.getElementById("joinus").className += " in";
if (current_page == "students") {
document.getElementById("students").className += " active";
} else if (current_page == "faqs") {
document.getElementById("faqs").className += " active";
} else if (current_page == "forecast-career") {
document.getElementById("forecast-career").className += " active";
} else if (current_page == "my-profile") {
document.getElementById("my-profile").className += " active";
} else {
}
} else if (
current_page == "values" ||
current_page == "ambassadors" ||
current_page == "documentary"
) {
if (current_page == "values") {
document.getElementById("values").className += " active";
} else if (current_page == "ambassadors") {
document.getElementById("ambassadors").className += " active";
} else if (current_page == "documentary") {
document.getElementById("documentary").className += " active";
} else {
}
}
}
.list-group-item.active:hover {
background-color: #aed248 !important;
border-color: #aed248 !important;
}
.list-group-item.active,
.list-group-item.active:hover {
background-color: #007715 !important;
border-color: #aed248 !important;
}
#joinus .list-group-item.active,
.list-group-item.active:hover {
background-color: #adce1b !important;
border-color: #adce1b !important;
}
#whyptcl .list-group-item.active,
.list-group-item.active:hover {
background-color: #adce1b !important;
border-color: #adce1b !important;
}
.panel {
margin-bottom: 20px;
background-color: transparent !important;
border: 0px solid transparent;
border-radius: 5px;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05);
}
<body onload="get_current_page()">
<div id="MainMenu">
<div class="list-group panel">
<a
id="whylist"
href="#why"
class="list-group-item"
data-toggle="collapse"
data-parent="#MainMenu"
>Menu 1</a
>
<div class="collapse" id="why">
<a
id="values"
href="values.html"
onclick="activate(this)"
class="list-group-item"
data-toggle="collapse"
data-parent="#SubMenu1"
>Menu 1 a</a
>
<a
id="ambassadors"
href="ambassadors.html"
onclick="activate(this)"
class="list-group-item"
>Menu 1 b</a
>
<a
id="documentary"
href="documentary.html"
onclick="activate(this)"
class="list-group-item"
>Menu 1 c</a
>
</div>
<a
id="joinuslist"
href="#joinus"
class="list-group-item"
data-toggle="collapse"
data-parent="#MainMenu"
>Menu 2</a
>
<div class="collapse" id="joinus">
<a
id="my-profile"
href="my-profile.html"
onclick="activate(this)"
class="list-group-item"
>Menu 2 a</a
>
<a
id="students"
href="students.html"
onclick="activate(this)"
class="list-group-item"
>Menu 2 b</a
>
<a
id="forecast-career"
href="forecast-career.html"
onclick="activate(this)"
class="list-group-item"
>Menu 2 c</a
>
<a
id="faqs"
href="faqs.html"
onclick="activate(this)"
class="list-group-item"
>Menu 2 e</a
>
</div>
</div>
</div>
</body>
The solution is simple but maybe not obvious.
You can pass this (the clicked element) to an onclick event handler and then set the active class on the selected menu.
var activate = function(el) {
var current = document.querySelector('.active');
if (current) {
current.classList.remove('active');
}
el.classList.add('active');
}
I created this Fiddle to answer your question
http://jsfiddle.net/Ltp9qLox/9/
The script can be greatly improved, this is just an example. I'm not aware of any non-JS way to achieve the same result.
You can also store the old activated element so you don't have to use query selector every time, in this way the script would be
var current;
var activate = function(el) {
if (current) {
current.classList.remove('active');
}
current = el;
el.classList.add('active');
}
Bu then you have to initialize currentwith the value of the starting element.
Adding Persistency
Of course any change to the style of an element can't survive after a refresh without implementing some kind of persistency that is something completely different than the simple implementation. Keep in mind that there are hundreds of different ways to achieve this, one of which is NOT refreshing at all the page.
Anyway if you prefer the quick and dirt way then using localStorage is probably the best solution. This is a simple implementation
var currentHref = localStorage.getItem("currentSelected");
var current = currentHref ? document.querySelector('[href="'+currentHref+'"]') : null;
function activate(el) {
if (current && current !== el) {
current.classList.remove('active');
}
current = el;
current.classList.add('active');
localStorage.setItem("currentSelected", current.getAttribute('href'));
}
Basically you save something that you can use to recognize the element that was selected, in this case i used the href attribute value because in our case that is unique, but you could also assign id or other attributes to the elements and use that.
Then on load i read the localStorage to retrieve the saved href and if found i get the element inside the page using a simple querySelector.
Just remember that copy-pasting this kind of solution doesnt help you building better websites, you should read articles on the internet and implement what solution is best for your own use case.
Just to change the active item background color, (I've changed to grey from default - blue) add this to your css:
.list-group-item.active {
background-color: grey;
border-color: grey; }
You can add these Bootstrap classes;
.list-group-item-dark
.list-group-item-success
.list-group-item-warning
.list-group-item-primary
.list-group-item-danger
.list-group-item-secondary
.list-group-item-info