Adding only a single instance of a class - javascript

I'm trying to add a class to an element using jQuery. If the user clicks on an element it adds a class, which I can do, but I want only 1 instance of that class to be active so if the user clicks on something else that class is then removed from the previous element and added to the current one.
https://jsfiddle.net/gsuxjce2/3/
<div class="row">
<div class="col">
<div class="box">
</div>
</div>
<div class="col">
<div class="box">
</div>
</div>
<div class="col">
<div class="box">
</div>
</div>
<div class="col">
<div class="box">
</div>
</div>
</div>
.col {
width: 25%;
float: left;
}
.box {
width: 50px;
height: 50px;
background-color: red;
cursor: pointer;
}
.added {
background-color: blue;
}
$('.box').click(function() {
$(this).toggleClass('added');
if ( $(this).hasClass('added'); ) {
$(this).removeClass('added');
} else {
$(this).toggleClass('added');
}
});

Remove the .added class from all .box elements first, then just add it to the one clicked on with this:
$('.box').click(function() {
$('.box').removeClass('added');
$(this).addClass('added');
});
$('.box').click(function() {
$('.box').removeClass('added');
$(this).addClass('added');
});
.col {
width: 25%;
float: left;
}
.box {
width: 50px;
height: 50px;
background-color: red;
cursor: pointer;
}
.added {
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="row">
<div class="col">
<div class="box">
</div>
</div>
<div class="col">
<div class="box">
</div>
</div>
<div class="col">
<div class="box">
</div>
</div>
<div class="col">
<div class="box">
</div>
</div>
</div>

$('.added').removeClass('added');
inside your click event before everything.

Just add this to the start of you click event:
jQuery(".added").each(function(i,el){
jQuery(el).removeClass("added")
});
This removes all instances of the class, so that when you add one new, then that will be unique.

Related

Hide other divs when clicking another div with the same class or clicking somewhere else

I want to make a list of divs, like that:
<div class="a">
<div class="b"></div>
<div class="c"></div>
</div>
<div class="a">
<div class="b"></div>
<div class="c"></div>
</div>
<div class="a">
<div class="b"></div>
<div class="c"></div>
</div>
When you click on a div.b, div.c (only from the same div.a parent) should have a .vis class added. When you click on another div.b it adds the class to its sibling (div.c) and removes the class from the last clicked div.c. When don't click div.b, but somewhere else, the .vis class is removed from every div.c.
window.onclick = function(window) {
if(window.target.className === 'b'){
$(".b").each(function() {
$(".b").on("click", function(){
$(this).siblings(".c").addClass("vis");
})
})
} else {
$(".c").removeClass("vis");
}
}
The code above doesn't work as it should. I have to click 2 times to add the class (First it executes the function to check the target class and the second click adds the class).
When I click on another div.b the .vis class from the click before isn't removed (so I have a few divs with .vis class, but I should have only 1 at a time).
How can I make this work?
Try this
window.onclick = function(e) {
if(e.target.className === 'b'){
// removing vis class from all c divs
$('.a .c').removeClass('vis');
// Add vis class to the sibling div
$(e.target).siblings().addClass('vis');
}
else {
//When clicking outside of b remove vis class from all c div
$('.a > .c').removeClass('vis');
}
}
body {
background: #20262E;
padding: 20px;
font-family: Helvetica;
}
#banner-message {
background: #fff;
border-radius: 4px;
padding: 20px;
font-size: 25px;
text-align: center;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
}
.vis {
background-color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="banner-message">
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
</div>
https://jsfiddle.net/86ku05hp/
You need something like this:
$('.a .b').click(function() {
$(".c").removeClass("vis");
$(this).next().addClass("vis")
})
When .b is clicked, it will remove class vis from all .c, and add it to the .c in connection to the clicked .b
Demo
$('.a .b').click(function() {
$(".c").removeClass("vis");
$(this).next().addClass("vis")
})
$(document).click(function(e) {
if (!$(e.target).hasClass("b") && !$(e.target).parent().hasClass("b")) {
$(".c").removeClass("vis");
}
});
.vis {
color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
let b = document.querySelectorAll(".b");
let c = document.querySelectorAll(".c");
b.forEach(elem => {
elem.addEventListener("click", () => {
c.forEach(el => el.classList.remove("vis"));
elem.nextElementSibling.classList.add("vis");
});
});
body {
font-family: sans-serif;
}
.b {
font-size: 40px;
background: red;
text-align: center;
cursor: pointer;
}
.c {
font-size: 40px;
background: green;
text-align: center;
cursor: pointer;
display: none;
}
.vis {
display: block;
}
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>
<div class="a">
<div class="b">b</div>
<div class="c">c</div>
</div>

How do I toggle visibility of an entire dynamic row (flex wrap)?

Current Behavior
I have the following basic structure:
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content">Content</div>
</div>
<!-- ... dozens of .boxes ... -->
</section>
#containers is .display: flex; flex-wrap: wrap, so the number of boxes on any one row is dynamic. This is an important feature that must be maintained.
Here's a minimal working example:
$(document).ready(function() {
$(".collapsible").click(function() {
$( this ).next().slideToggle();
});
});
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
.collapsible:hover {
background: #aaf;
}
.content {
margin: 0.5em;
margin-left: 16px;
display: none; /* Initially collapsed */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box3">
<div class="collapsible"><h2>Box 3</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box4">
<div class="collapsible"><h2>Box 4</h2></div>
<div class="content">Content</div>
</div>
<div class="box" id="box5">
<div class="collapsible"><h2>Box 5</h2></div>
<div class="content">Content</div>
</div>
</section>
</body>
I can easily use .slideToggle() to toggle visibility of a sibling (.content) underneath one of the clickable .collapsible divs:
$(".collapsible").click(function() {
$( this ).next().slideToggle();
});
Desired Behavior and Remarks
What I'd like is, on click of any .collapsible div in a row, the entire row will be toggled. That is, every .content div on the same horizontal row as displayed in the current viewport.
This must handle rows with dynamic number of columns, including viewport resizing. I'm flexible on the precise behavior, though.
Is this possible? And how much will it hurt?🙂 Changes to the document structure (such as adding some sort of row container) are OK, and I don't mind using some JS/jQuery code of course. The main thing I can't do is hard code the number of columns, as I need my site to remain responsive on vertical phones and fullscreen desktop browsers.
Maybe the jQuery slideToggle() function is not the best method.
Since a row will be the same height , you may look at a method to set size from 0 to another value. anybox resized will stretch other boxes on the same row.
here an example of the idea, setting a max-height from 0 to 200px and a transition.
it toggles a class.
$(document).ready(function() {
$(".collapsible").click(function() {
this.classList.toggle('slide');// plain javascript to toggle a class
});
});
*{box-sizing:border-box}
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
p{margin-top:0;}
.collapsible:hover {
background: #aaf;
}
.content {
margin:0 0.5em;
margin-left: 16px;
max-height:0; /* Initially collapsed */
transition:0.5s
}
.slide + .content{max-height:400px;/* which one got the class*/ color:darkred}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible"><h2>Box 1</h2></div>
<div class="content"><p>Content</p></div>
</div>
<div class="box" id="box2">
<div class="collapsible"><h2>Box 2</h2></div>
<div class="content"><p>Content</p><p>Content</p></div>
</div>
<div class="box" id="box3">
<div class="collapsible"><h2>Box 3</h2></div>
<div class="content"><p>Content</p></div>
</div>
<div class="box" id="box4">
<div class="collapsible"><h2>Box 4</h2></div>
<div class="content"><p>Content</p><p>Content</p><p>Content</p></div>
</div>
<div class="box" id="box5">
<div class="collapsible"><h2>Box 5</h2></div>
<div class="content"><p>Content</p></div>
</div>
</section>
</body>
What you are missing here , is to set the height of the row to the height of the taller box, unless they will all be the same height.
For this, you can look for every box at the same top offset that the one clicked, and look for the tallest innercontent of the .contents and use this height .
Here comes the idea looking where each are standing and resets a max-height rule, you can inspire from too:
// defaut : supposed to be with no class 'slide' set on html elements
$(document).ready(function () {
let boxes = document.querySelectorAll(".collapsible");
let contents = document.querySelectorAll(".content");
$(".collapsible").click(function (event) {
let arrayContent = [];//reset
let hide=false;
for (i = 0; i < contents.length; i++) {
contents[i].style.maxHeight = "min-content";
let index = i;
let heightC = contents[i].offsetTop;
let boxOffset = contents[i].parentNode.offsetTop + 1;
// a few infos .add/remove what is needed
arrayContent.push({
index,
heightC,
boxOffset
});
contents[i].setAttribute("style", "");// resets inline style
}
let rowOffset = this.offsetTop;
if(this.classList.contains('slide')) {
hide=true;
}
let classState = this.classList;
arrayContent.forEach(function (obj) {
if (obj.boxOffset == rowOffset) {
if(hide == true) boxes[obj.index].classList.add('slide');/* reset needed if window resized => rows reorganized ? */
boxes[obj.index].classList.toggle("slide");
} else {
boxes[obj.index].classList.remove("slide");
}
});
});
});
* {
box-sizing: border-box
}
#containers {
display: flex;
flex-wrap: wrap;
gap: 1em;
}
.box {
min-width: 15em;
background: #888;
border: #555 1px solid;
overflow: hidden;
border-radius: 0.5em;
}
.collapsible {
background: #ccc;
cursor: pointer;
}
.collapsible h2 {
margin: 0;
margin-left: 16px;
font-size: 2rem;
}
p {
margin-top: 0;
}
.collapsible:hover {
background: #aaf;
}
.content {
margin: 0 0.5em;
margin-left: 16px;
max-height: 0;
/* Initially collapsed */
transition: max-height 0.5s!important
}
.slide~.content {
max-height: 400px;
/* which one got the class*/
color: darkred;
}
.collapsible:before {
content: attr(class)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<body>
<p id="status"></p>
<section id="containers">
<div class="box" id="box1">
<div class="collapsible">
<h2>Box 1</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
<div class="box" id="box2">
<div class="collapsible">
<h2>Box 2</h2>
</div>
<div class="content">
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="box" id="box3">
<div class="collapsible">
<h2>Box 3</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
<div class="box" id="box4">
<div class="collapsible">
<h2>Box 4</h2>
</div>
<div class="content">
<p>Content</p>
<p>Content</p>
<p>Content</p>
</div>
</div>
<div class="box" id="box5">
<div class="collapsible">
<h2>Box 5</h2>
</div>
<div class="content">
<p>Content</p>
</div>
</div>
</section>
</body>

when i hide the previous panel the next panel is moved leftward to the previous one's place and i want it to be there as it was

when i click the Button1 the Panel1 is hidden and same is the functionality of all buttons. But when i hide the Panel1 the Panel2 is moved to Panel1's place and i want to be at place where it was. kindly help me
<head>
<title>JQuery Event Listener</title>
<script src = "jquery-3.0.0.js"></script>
<style>
header {
background-color: gray;
text-align: center;
}
main {
padding-left: 39%;
position: relative;
}
.panel {
display: inline-block;
}
.panel-Heading {
background-color: blue;
width: 60px;
padding: 5px;
border: 1px groove;
}
.panel-Body {
width: 60px;
padding: 5px;
border: 1px solid;
}
</style>
</head>
<body>
<header>
<br>
<h1>Let's Have Fun!</h1>
<button id = "btn1" data-panel="1">Button1</button>
<button id = "btn2" data-panel="2">Button2</button>
<button id = "btn3" data-panel="3">Button3</button>
<button id = "btn4" data-panel="4">Button4</button>
<br><br>
</header>
<br><br>
<main>
<div id="panel1" class="panel">
<div class = "panel-Heading">Panel1</div>
<div class = "panel-Body">Content</div>
</div>
<div id="panel2" class="panel">
<div class = "panel-Heading">Panel2</div>
<div class = "panel-Body">Content</div>
</div>
<div id="panel3" class="panel">
<div class = "panel-Heading">Panel3</div>
<div class = "panel-Body">Content</div>
</div>
<div id="panel4" class="panel">
<div class = "panel-Heading">Panel4</div>
<div class = "panel-Body">Content</div>
</div>
</main>
<script>
$(function(){
$("#btn1").on('click', function() {
$("#panel1").fadeToggle();
});
$("#btn2").on('click', function() {
$("#panel2").fadeToggle();
});
$("#btn3").on('click', function() {
$("#panel3").fadeToggle();
});
$("#btn4").on('click', function() {
$("#panel4").fadeToggle();
});
});
</script>
</body>
Add width: 60px; to your .panel class:
.panel {
display: inline-block;
width: 60px;
}
... then nest the divs you'd like to hide inside of them:
<div class="panel">
<div id="panel1">
<div class = "panel-Heading">Panel1</div>
<div class = "panel-Body">Content</div>
</div>
</div>
<div class="panel">
<div id="panel2">
<div class = "panel-Heading">Panel2</div>
<div class = "panel-Body">Content</div>
</div>
</div>
<div class="panel">
<div id="panel3">
<div class = "panel-Heading">Panel3</div>
<div class = "panel-Body">Content</div>
</div>
</div>
<div class="panel">
<div id="panel4">
<div class = "panel-Heading">Panel4</div>
<div class = "panel-Body">Content</div>
</div>
</div>
This will cause the nested div to disappear when the buttons are clicked, while the outer div remains in place to hold the space.
Also, since your JavaScript is below the elements it will be affecting, you don't need to wait for document ready. You're also writing more click handlers than you need to. You can probably swap all of your JavaScript out for the following:
$(".panel").on('click', function() {
$(this).children().first().fadeToggle();
});
Try this
$(function(){
$("#btn1").on('click', function() {
$("#panel1").fadeToggle();
});
$("#btn2").on('click', function() {
$("#panel2").fadeToggle();
});
$("#btn3").on('click', function() {
$("#panel3").fadeToggle();
});
$("#btn4").on('click', function() {
$("#panel4").fadeToggle();
});
});
.main {
width : 100%;
}
.main .panel-container{
display: inline-block;
width : 24% !important;
}
header {
background-color: gray;
text-align: center;
}
main {
padding-left: 39%;
position: relative;
}
.panel {
display: inline-block;
}
.panel-Heading {
background-color: blue;
width: 60px;
padding: 5px;
border: 1px groove;
}
.panel-Body {
width: 60px;
padding: 5px;
border: 1px solid;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<head>
<title>JQuery Event Listener</title>
<script src = "jquery-3.0.0.js"></script>
<style>
</style>
</head>
<body>
<header>
<br>
<h1>Let's Have Fun!</h1>
<button id = "btn1" data-panel="1">Button1</button>
<button id = "btn2" data-panel="2">Button2</button>
<button id = "btn3" data-panel="3">Button3</button>
<button id = "btn4" data-panel="4">Button4</button>
<br><br>
</header>
<br><br>
<div class="main">
<div class="panel-container">
<div id="panel1" class="panel">
<div class = "panel-Heading">Panel1</div>
<div class = "panel-Body">Content</div>
</div>
</div>
<div class="panel-container">
<div id="panel2" class="panel">
<div class = "panel-Heading">Panel2</div>
<div class = "panel-Body">Content</div>
</div>
</div>
<div class="panel-container">
<div id="panel3" class="panel">
<div class = "panel-Heading">Panel3</div>
<div class = "panel-Body">Content</div>
</div>
</div>
<div class="panel-container">
<div id="panel4" class="panel">
<div class = "panel-Heading">Panel4</div>
<div class = "panel-Body">Content</div>
</div>
</div>
</div>
</body>

Aligning boxes(divs) of equal size in html symmetrically according to their number

I want to make an HTML page that contains a box at the top and a certain number of boxes being dynamically generated using jquery, the number of boxes at the bottom of top box can be 4 at max.
I want to align these boxes dynamically and symmetrically in the html page. I am using angularjs's ng-repeat to generate boxes. I want the sizes of the boxes to remain same but arrange them symmetrically on the html page.
currently i am using angular js to dynamically create boxes and align them using col-md class of bootstrap. but this makes the size of boxes to change when the number of boxes change.
html code
<div id="header-wrapper" class="container vscrolling_container">
<div id="header" class="container vscrolling_container">
<div id="logo">
<h1 class="page-head-line" id="visionh"><a>Vision</a></h1>
<p id="visionp"><a rel="nofollow">{{visiontext}}</a></p>
</div>
</div>
</div>
<div class="row" id="missionstart">
<div ng-class="missioncount[missions.length]" ng-repeat="mission in missions" style="opacity: 0.9">
<div class="dashboard-div-wrapper" ng-class="bkclr[$index]">
<h1 id="{{mission.id}}" style="color: #000">{{mission.missionInfo}}</h1>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%"></div>
</div>
<ul>
<li id="{{missioncontent.id}}" ng-repeat="missioncontent in mission.missionContent">
<p style="text-align: left">{{missioncontent.info}}</p>
</li>
</ul>
</div>
</div>
</div>
java script code
'use strict';
var mission_vision_mod = angular.module('myApp.mission_vision', ['ngRoute']);
mission_vision_mod.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/mission_vision', {
templateUrl: 'partials/mission_vision/mission_vision.html',
controller: 'mission_visionCtrl'
});
}]);
mission_vision_mod.controller('mission_visionCtrl', ['$scope','$http', function($scope, $http) {
$scope.visiontext = "Here is the content of vision";
$scope.bkclr = ['bk-clr-one','bk-clr-two','bk-clr-three','bk-clr-four'];
$scope.progressbar = ['progress-bar-warning','progress-bar-danger','progress-bar-success','progress-bar-primary'];
$scope.missioncount = ['col-md-0','col-md-12','col-md-6','col-md-4','col-md-3','col-md-2.5','col-md-2'];
$http.get('m_id.json').success(function(data){
$scope.missions = data;
$scope.len = data.length;
});
}]);
I have created a quick jsfiddle
HTML Content:
<div class="container">
<div class="header"></div>
<div class="content">
<div class="contentBox"></div>
<div class="contentBox"></div>
</div>
</div>
<br/><br/><br/>
<div class="container">
<div class="header"></div>
<div class="content">
<div class="contentBox"></div>
<div class="contentBox"></div>
<div class="contentBox"></div>
<div class="contentBox"></div>
</div>
</div>
Related CSS:
.container div {
height: 100px;
}
.header {
border: 1px solid black;
width: 75%;
margin: 5px auto;
}
.content {
text-align: center;
}
.contentBox {
border: 1px solid black;
width: 20%;
display: inline-block;
box-sizing: border-box;
}
Caution: I have used plain CSS for this demo.
Hope this helps you.
flexbox can do this
.wrap {
width: 80%;
margin: auto;
border: 1px solid black;
margin-bottom: 25px;
}
.top,
.item {
width: 100px;
height: 50px;
background: red;
}
.top {
display: inline-block;
}
.flex {
display: flex;
justify-content: space-around;
}
<div class="wrap">
<div class="flex">
<div class="top"></div>
</div>
<div class="flex">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</div>
JSfiddle Demo

Div doesnt have any height

I am constructing a div on the fly using Jquery, and appending it to the body or any element.
after appending, when i try to get get the height it gives 0. In Chrome i checked all its height property its 0. what could be the problem.
This is my code to append :
var template = '<div class="capMainSection">
<div class="CAP"> </div>
<div class="scrolldiv repeatSection" style="display:none;"">
<div class="header sectionheader"> </div>
<div class="content">
<div class="leftColumn">
<div class="show" id="capInfo">
<div class="label1">CA Contacts:</div>
<div class="label2"><p>CA Lead:<span class="LeadName"></span><span class="LeadEmail"></span></p></div>
<div class="lable3"><p>Lead:<span class="vLeadName"></span><span class="vLeadEmail"></span></p></div>
</div>
<div class="hidden" id="facInfo">
<div class="label1"><span class="facid"></span><span class="facName"></span></div>
<div class="label2"><span class="city"></span><span class="state"></span><span
class="country"></span></div>
</div> </div>
<div class="rightColumn">
<div class="rightGroup">
<div class="groupproto">
<p><span class="protocolname show"></span>
<span class="date_class show"></span></p>
</div>
<div class="statusClass hidden"></div>
<div class="approvedFinding show"></div>
<div class="closedFinding show"></div>
<div class="verifiedFinding show"></div>
<div class="lasActivity show"></div>
</div>
<div class="linkButton">
<input type="button" class="lplinkbutton" value=">">
</div>
</div>
</div>
</div>
</div>';
i am cloning the div first then appending
templateNode = $('.repeatSection').clone(true);
//change the display none to show
$(templateNode).find('.content').attr('id',capRow);
$('.capMainSection').append($(templateNode));
css
.content {
clear: both;
font-size: 13px;
}
.leftColumn {
float: left;
width: 40%;
padding: 10px 0 10px 10px;
}
.rightColumn {
float: right;
width: 50%;
padding: 0;
}
Try this:
.capMainSection {overflow: hidden;}
Or, you can do this:
.capMainSection:after {
content: " ";
display: block;
clear: both;
}

Categories