Select all but this element - javascript

I have a few accordions setup and I'd like only one to be open throughout the whole page. I thought that the .not() method would achieve what I wanted however it is just immediately closing the current div.
Here is what I have if anyone can spot where I've gone wrong:
JS
$( document ).ajaxComplete(function() {
$('.accordion-toggle').click(function(){
//Expand or collapse this panel
$(this).next().stop().slideToggle('1000');
$(this).toggleClass('active').siblings().removeClass('active');
//Hide the other panels
$('.accordion-content').not(this).slideUp('1000');
});
});
HTML
<div id="location1">
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
</div>
<div id="location2">
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
<h3 class="accordion-toggle">Opening times <i class="fa fa-angle-down"></i></h3>
<div class="accordion-content">
<p>List of products available here!</p>
</div>
</div>
CSS
.accordion-content {
display: none;
padding:20px 0;
border-bottom: 1px solid #d4d5d7;
}
.accordion-content.default {display: block;}
.accordion-toggle {
cursor: pointer;
font-size:18px;
padding:10px 0;
margin:0;
border-bottom:1px solid #d4d5d7;
position:relative;
}

You were pretty close. You should change this line
$('.accordion-content').not(this).slideUp('1000');
To This:
$('.accordion-toggle').not(this).next().slideUp('1000');
Since your click function is applied to the accordion-toggle class, you have to target that class since this is an accordion-toggle class element, and you want to filter out all elements that are not this object. This will also force you to have to use the .next() method since you're looking to slide the next element in the DOM.
Edit 1:
In order to remove the active class across all of the #locationX divs, you should separate this line
$(this).toggleClass('active').siblings().removeClass('active');
Into this:
$('.active').not(this).removeClass('active');
$(this).toggleClass('active');
The way it was written previously, after the active class is toggled on the current element, it will only remove that class from all sibling elements, which won't properly affect elements in the other divs. It makes the script a bit longer, but it will remove all of the active classes before toggling the class on the current element.
Edit 2:
The simplest solution for the whole function is probably the following:
$('.accordion-toggle').click(function(){
//Expand or collapse this panel
$(this).next().stop().slideToggle('1000');
//Hide the other panels
$('.accordion-toggle').not(this).removeClass('active').next().slideUp('1000');
$(this).toggleClass('active');
});

In your case this is the toggle not the content (it would also have to be $(this) not just this, so:
$('.accordion-content').not(this).slideUp('1000');
Will match all accordion content.
You could try:
var $content = $(this).next('.accordion-content');
$('.accordion-content').not($content).slideUp('1000');
As a note, I would set var $this = $(this); at the beginning of your handler so that you are not repeatedly creating jQuery objects which is relatively expensive.

Related

Delete dynamically added item by clicking on modal

I am trying to delete dynamically added item by clicking on delete button .delete on modal box.
I have one modal and it pops-up when I click on button <i class="fa-solid fa-ellipsis">.
Code:
function showOptions(object) {
if (object.target.matches(".fa-ellipsis")) {
let optionsModal = object.target.querySelector(".optionsModal");
optionsModal.classList.toggle("hide");
}
}
function deletePost() {
// delete specific li-item from the list
}
document.querySelector("body").addEventListener("click", showOptions(event));
document.querySelector(".delete").addEventListener("click", deletePost);
<body>
<ul class="posts-list">
<li class="posts-list-item">
<div class="post">
<div class="post-option">
<i class="fa-solid fa-ellipsis"></i>
</div>
</div>
</li>
<li class="posts-list-item">
<div class="post">
<div class="post-option">
<i class="fa-solid fa-ellipsis"></i>
</div>
</div>
</li>
<!-- every li item is added dynamically -->
</ul>
<div class="optionsModal hide">
<p class="delete">Delete</p>
<p class="cancel">Cancel</p>
</div>
</body>
And I have a problem how to pass to deletePost function specific <i class="fa-solid fa-ellipsis"> when I click on them. I was trying to nest one eventListener in another but it doesn't work.
When you open the modal, add a class to the item you clicked on. Then find the item in deletePost.
The modal isn't inside object.target, so you shouldn't use object.target.querySelector() to find it, use document.querySelector().
You shouldn't toggle the hide class when clicking on a list items. That will hide the modal if you click on a different item before cancelling the modal (although if you make it truly modal, you shouldn't be able to click on something else). I just remove the class to display the modal.
function showOptions(object) {
if (object.target.matches(".fa-ellipsis")) {
let optionsModal = document.querySelector(".optionsModal");
optionsModal.classList.remove("hide");
let oldSelected = document.querySelector(".selected");
if (oldSelected) {
oldSelected.classList.remove("selected");
}
object.target.classList.add("selected");
}
}
function deletePost() {
let selected = document.querySelector(".selected");
if (selected) {
selected.closest(".posts-list-item").remove();
}
}
document.querySelector("body").addEventListener("click", showOptions);
document.querySelector(".delete").addEventListener("click", deletePost);
.selected {
background-color: red;
}
.hide {
display: none;
}
<body>
<ul class="posts-list">
<li class="posts-list-item">
<div class="post">
<div class="post-option">
<i class="fa-solid fa-ellipsis">Item 1</i>
</div>
</div>
</li>
<li class="posts-list-item">
<div class="post">
<div class="post-option">
<i class="fa-solid fa-ellipsis">Item 2</i>
</div>
</div>
</li>
<!-- every li item is added dynamically -->
</ul>
<div class="optionsModal hide">
<p class="delete">Delete</p>
<p class="cancel">Cancel</p>
</div>
</body>

Bootstrap 4 change accordion behaviour

I'm using HTML templates, which are based on Bootstrap 4.3.1 to present my students with learning content. In the current templates, all accordion panels are closed on page load and each accordion panel can be opened regardless of how many others have also been opened.
A working example can be found on this CodePen: https://codepen.io/hagelslag1001/pen/MWGeZJr
The HTML code is as follows:
<h2>Accordion: Group of 2</h2>
<p class="small">Accordion: start copy</p>
<!-- Accordion headings should be changed to respect page hierarchy -->
<div class="accordion shadow mb-5">
<div class="card">
<div class="card-header">
<h2 class="card-title">
Accordion 1 of 2
</h2>
</div>
<div class="collapse">
<div class="card-body">
<p>Insert Accordion 1 of 2 content here.</p>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h2 class="card-title">
Accordion 2 of 2
</h2>
</div>
<div class="collapse">
<div class="card-body">
<p>Insert Accordion 2 of 2 content here.</p>
</div>
</div>
</div>
</div>
<p class="small">Accordion: end copy</p>
Is it possible to change this default behaviour so that only one panel can be opened at a time? (i.e. as soon as a new panel is opened, the previously opened panel will automatically close)
The Bootstrap examples use (data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne") to accomplish this for the accordions in these templates
I can't figure out how to accomplish this, since the HTML code for the accordions in these templates look different than the Bootstrap 4 examples, which use either an a or button tag to trigger the collapsible event.
Here is a simpler answer based on your CodePen: https://codepen.io/mrtcntn/pen/MWGeZdP
According the Bootstrap 4 docs, you need id="accordion" on the top level div and you don't need to give ids like id="accordion_1" and id="accordion_2".
Therefore I removed the first portion from the JS and added id="accordion" at line 18 in the HTML.
You can do this by letting javascript check for active classes and only allowing one at the time. Here's a simplified example.
// DOM here
let nav = document.querySelector(".nav");
// Handlers here
const clickHandler = function (e) {
if (e.target.classList.contains("nav__link")) {
const link = e.target;
const siblings = link.closest(".nav").querySelectorAll(".nav__link");
link.classList.toggle("active");
// removes all actives except for the clicked one
siblings.forEach((el) => {
if (el !== link) el.classList.remove("active");
});
}
};
// Listeners here
nav.addEventListener("click", clickHandler);
body {
font-family: sans-serif;
}
.nav__link {
display: block;
width: 100%;
}
.active {
background: #0f0;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div class="nav">
<ul class="nav__links">
<li class="nav__item">
<a class="nav__link" href="#accordeon--1">Accordeon 1</a>
</li>
<li class="nav__item">
<a class="nav__link" href="#accordeon--2">Accordeon 2</a>
</li>
<li class="nav__item">
<a class="nav__link" href="#accordeon--3">Accordeon 3</a>
</li>
<li class="nav__item">
<a class="nav__link" href="#accordeon--4"
>Accordeon 4</a
>
</li>
</ul>
</div>
</div>
<script src="src/index.js"></script>
</body>
</html>

jquery Checking if parent element has a specific text within it, if so then add child element after specific pre-existing child element

I'm working on a product box that has the products price, in-stock status, etc. The product box has multiple child elements within the parent element and within each child element, theirs a sub-child element that has a span element with text. I'm not sure what jquery code or javascript code I need to specify the condition that if this product box DOES NOT CONTAIN a product status within it, then add this NEW child element with text after the child element price container
So far I tried .has .find and :contains but they all select all product boxes that has those element/Id/class conditions and applies it even though i specify that only those without this existing text should have this new element with text applied.
General format of what I'm wroking with example:
<div class="product-box-container">
<h5 class="product-title">
<a class="product-name">This Watch Name</a>
</h5>
<p class="product-id">ABCD-123</p>
<div class="price-container">
<span class="product-price">$29.99</span>
<div class="availability-status">
<span class="product-status">In Stock</span>
</div>
<div class="view-product">
<a><span>View Product</span></a>
</div>
</div>
NOTE: I'm working with multiple product boxes within one page and a lot of them have the same class/Id names. I'm focusing on those without a product status and adding to them. Only way to differentiate them is by identifying the text within the product box container element and using that to apply specific conditions to certain boxes with particular text.
END RESULT
Product box with no product status before solution:
<div class="product-box-container">
<h5 class="product-title">
<a class="product-name">This Watch Name</a>
</h5>
<p class="product-id">ABCD-123</p>
<div class="price-container">
<span class="product-price">$29.99</span>
</div>
<div class="view-product">
<a><span>View Product</span></a>
</div>
</div>
Product box WITH added new child element:
<div class="product-box-container">
<h5 class="product-title">
<a class="product-name">This Watch Name</a>
</h5>
<p class="product-id">ABCD-123</p>
<div class="price-container">
<span class="product-price">$29.99</span>
</div>
<div class="availability-status">
<span class="product-status">Custom Order</span>
</div>
<div class="view-product">
<a><span>View Product</span></a>
</div>
</div>
#1 Method tried:
/*First i have to make sure it only applies this code to a web page that has view product button/class cause only the pages that have product boxes has view product button/class*/
if ($('span:contains("View Product")').length >0) {
/*trying to find specific product boxes that do not have product-status by
using its product-id text*/
if ($('div.product-box-container').has('p:contains("ABCD-123")').length >0){
$('div.price-container').after('<div class="availability-status"><span class="product-status">Custom Order</span></div>');
}
}
#2 Method tried
/*specifying to apply only to web pages with view product*/
if ($('span:contains("View Product")').length >0) {
/*applying the NEW child element first to everything*/
$('div.price-container').after('<div class="availability-status"><span class="product-status">Custom Order</span></div>');
/*then deleting the NEW child element from any product boxes that has the In
Stock text within it*/
if ($('div.product-box-container').has('span:contains("In Stock")').length >0) {
$('div.availability-status').css('display','none');
}
}
Find all the boxes
Filter out the ones that do have an availability-status
Find the view-product nested in the remaining boxes
Insert the custom html before the view product
$('.product-box-container')
.filter(function(){
return $(this).find('.availability-status').length < 1;
})
.find('.view-product')
.before(`
<div class="availability-status">
<span class="product-status">Custom Order</span>
</div>
`);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="product-box-container">
<h5 class="product-title">
<a class="product-name">This Watch Name</a>
</h5>
<p class="product-id">ABCD-123</p>
<div class="price-container">
<span class="product-price">$29.99</span>
</div>
<div class="view-product">
<a><span>View Product</span></a>
</div>
</div>
<div class="product-box-container">
<h5 class="product-title">
<a class="product-name">This Watch Name</a>
</h5>
<p class="product-id">ABCD-123</p>
<div class="price-container">
<span class="product-price">$29.99</span>
</div>
<div class="availability-status">
<span class="product-status">In Stock</span>
</div>
<div class="view-product">
<a><span>View Product</span></a>
</div>
</div>

Manipulate css style of a class depending on other class css style

I am using navigation drawer of Framework7 plugin on my hybrid app. The drawer can be open/close using the button as well as using swipe/slide left/right.
Now when the navigation drawer was open, the class <div class="panel panel-left panel-reveal"> added another class which is active class.
So when opened: <div class="panel panel-left panel-reveal active ">
when closed: <div class="panel panel-left panel-reveal>
Based on that event, is it possible to add style to other class?
Example is this class: <div class="views"> to <div class="views" style="opacity: 0.5">
What to accomplish: When the drawer is open, the class view will add style, when drawer is close remove the view class style.
Is it possible to catch that event and accomplish what I would like to do?
Sorry for the delay, so below is the sample code to add a css class to a div only on hover event. I have done this using html and css only. (No DOM manipulation).
<!doctype html>
<html>
<head>
<style>
a.ex1:hover{color: red;}
a.ex2:hover, a.ex2:active {font-size: 150%;}
a.ex3:hover, a.ex3:active {background: red;}
a.ex4:hover, a.ex4:active {font-family: monospace;}
a.ex5:visited, a.ex5:link {text-decoration: none;}
a.ex5:hover, a.ex5:active {text-decoration: underline;}
.open-close{ display: none;}
a.ex6:hover .open-close{display: block;}
</style>
</head>
<body>
<p>
<a class = "ex1" href="#"> This link changes color </a>
</p>
<p>
<a class = "ex2" href="#"> This link changes font-size </a>
</p>
<p>
<a class = "ex3" href="#"> This link changes background-color </a>
</p>
<p>
<a class = "ex4" href="#"> This link changes font-family </a>
</p>
<p>
<a class = "ex5" href="#"> This link changes text-decoration </a>
</p>
<p>
<a class = "ex6" href="#">
<div>This link displays another div by detecting change in class</div>
<div class="open-close">
Here you can add your content to hide/show/modify elements based on the classes
</div>
</a>
</p>
</body>
</html>
NOTE - Just remember to use the appropriate CSS selector based on your HTML structure.
Hope this helps. Let me know if you have any questions. Happy to help.
Hi Yes it is Possible. Using HTML and Javascript itself. You can also achieve this using JQUERY DOM manipulation. Let me know which one would you want to know.
I have modified your HTML a little
<div class="panel-overlay"></div>
<div class="panel panel-left panel-reveal">Just to see if his appears in green on fire of a single common event</div> <!---it adds "active class" e.g. <div class="panel panel-left panel-reveal active"> -->
<div class="views"> Just to see if this appears in red on fire of a single common event<!--this should toggle change background, i mean add background color when class panel has active class then remove the bgcolor when active class remove (vise versa) -->
<div class="view view-main" data-page="home">
<div class="pages">
<div data-page="home" class="page navbar-fixed">
<div class="navbar">
<div class="navbar-inner">
<div class="left">
<button onclick="myFunction()" type="button" class="open-panel fa fa-bars button-nav"> I am button 1</button>
</div>
<div class="center" style="left: -6.5px;"></div>
<div class="right">
<button type="button" id="refresh" class="button-nav"> <i class="el el-refresh"></i> I am button 2</button>
</div>
</div>
</div>
<div class="page-content">
<div class="content-block"> content here... </div>
</div>
</div>
</div>
</div>
</div>
Just add this JavaScript function and you will be good to go.
function myFunction(){
$(".panel-reveal").addClass("active");
if($(".panel-reveal").hasClass("active")) {
$(".views").addClass("change")
}
}
CSS will be
.active{
background-color: green !important;
}
.change{
background-color: red !important;
}
I hope this helped.

Jquery toggle and add/remove

I have two buttons.
Both buttons have a rollover css color change.
One of the buttons just links to another page.. however, the other button when clicked needs to
A.) Show a hidden div
B.) toggle to the roll-over color and stay that color. (but not change the other buttons class)
I only want the button with the id of "edit" to toggle the class m-button-regular to m-button-active and not the other button. The JQuery I am using changes both buttons classes to m-button-active.
What is going wrong in this script?
<a href="#tab1" id="edit" >
<span class="m-button-small m-button-regular text-center floatleft clearfix mtm mls" id="sm-tab1">
<i class="fa fa-gear"></i>
<p>EDIT</p>
</span>
</a>
<a href="#tab1">
<span class="m-button-small m-button-regular text-center floatleft clearfix mtm mls" id="sm-tab1">
<i class="fa fa-plus"></i>
<p>ADD</p>
</span>
</a>
<div class="row editcontainer">
</div>
$('.editcontainer').hide();
$(document).ready(function(){
$('#edit').click(function(){
$(".editcontainer").toggle();
$('.m-button-regular').toggleClass("m-button-active");
});
});
You need to use .find() to refer its child span, then you can use toggle.
Get the descendants of each element in the current set of matched elements, filtered by a selector, jQuery object, or element.
Use
$(this).find('.m-button-regular').toggleClass("m-button-active");
instead of
$('.m-button-regular').toggleClass("m-button-active");
This seems to do what you want :
$('.editcontainer').hide();
$(document).ready(function() {
$('#edit').click(function() {
$(".editcontainer").toggle();
$('#edit').toggleClass("m-button-active");
});
});
.m-button-active {
color : green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<a href="#tab1" id="edit">
<span class="m-button-small m-button-regular text-center floatleft clearfix mtm mls" id="sm-tab1">
<i class="fa fa-gear"></i>
<p>EDIT</p>
</span>
</a>
<a href="#tab1">
<span class="m-button-small m-button-regular text-center floatleft clearfix mtm mls" id="sm-tab1">
<i class="fa fa-plus"></i>
<p>ADD</p>
</span>
</a>
<div class="row editcontainer" style="display: none">Edit container</div>
By the way your selector was originally selecting both buttons.
This is refering to all classes:
$('.m-button-regular').toggleClass("m-button-active");
You must refer the button
$("#edit").toggleClass("m-button-active");
You are almost right but slight change to your code and bingo
$('.editcontainer').hide();
$(document).ready(function(){
$('#edit').click(function(){
$(".editcontainer").toggle();
$('.m-button-regular',this).toggleClass("m-button-active"); //<--- add a scope, same as $(this).find
});
});

Categories

Resources