having a problem, I have a javascript content switcher on a page, but I can't seem to get one thing working - how to make a clicked button stay active after it's clicked?
Here's a code:
JS
<script type="text/javascript">
function switch1(div) {
var option=['one','two','three'];
for(var i=0; i<option.length; i++) {
if (document.getElementById(option[i])) {
obj=document.getElementById(option[i]);
obj.style.display=(option[i]==div)? "block" : "none";
}
}
}
window.onload=function () {switch1('one');}
</script>
CSS
#switchables li a {
color: #262626;
text-decoration: none;
display: inline-block;
padding-top: 14px;
padding-right: 34px;
padding-bottom: 10px;
padding-left: 33px;
background-image: url(img/catButBcgr.jpg);
border-right-width: 1px;
border-left-width: 1px;
border-right-style: solid;
border-left-style: none;
border-right-color: #E1E1E1;
border-left-color: #FFF;
}
#switchables li a:hover {
background-image: url(img/catButBcgrH.jpg);
}
#switchables li a:active {
background-image: url(img/catButBcgrA.jpg);
}
HTML
<ul id="switchables">
<li><a class="active" href="javascript:void[0];" onclick="switch1('one');">OVERVIEW</a></li>
<li><a class="active" href="javascript:void[0];" onclick="switch1('two');">CATEGORY</a></li>
<li><a class="active" href="javascript:void[0];" onclick="switch1('three');">CATEGORY</a></li>
</ul>
You need to make an "Active" class and add it to the button when clicked.
#switchables a:active, #switchables a.active {
background-image: url(img/catButBcgrA.jpg);
}
It's easy using jQuery:
$(document).ready(function() {
myInit()
})
function myInit() {
$('#switchables a').click(function() {
$('#switchables a').removeClass('active')
$(this).addClass('active')
})
}
This is a nice opportunity to learn. Diodeus' answer is completely right, but his jQuery code does horrible things on the background, see the comments:
$(document).ready(function() {
myInit()
})
function myInit() {
// on the following line, jQuery creates an array of objects (a tags)
// (costly operation!) and adds click listener to each of them
$('#switchables a').click(function() {
// on the following line, jQuery creates the crazy God object again
// and throws it off after this command
// for each a tag and tries to remove class active from it
// in only one case it actually does something - mere class removal
// btw removeClass is ridiculous function if you dig into jQuery 1.10 source
$('#switchables a').removeClass('active')
// this = the source of click event, not jQuery object
$(this).addClass('active')
})
}
This is just a very short code, now imagine you write whole web this style. It will be observably slower, consuming much more resources.
If you insist on jQuery, try to write reusable code a little:
function myInit() {
// jQuery object is created only once
var $anchors = $('#switchables a');
$anchors.click(function() {
// ...and reused here
$anchors.removeClass('active')
$(this).addClass('active')
});
}
But you'd do much better job using native javascript
var items = document.querySelectorAll("#switchables a");
var prev = items[0];
[].forEach.call(items,function(item) {
item.addEventListener("click",function() {
// no need to loop every a tag here
prev.classList.remove("active");
item.classList.add("active");
// remember previous active a tag
prev = item;
});
});
document.querySelectorAll is a live collection which is something that can't be achieved by any javascript library, it is implemented in underlying and more effective code of the browser.
Advice Don't use jQuery until you know Javascript well. Without that knowledge, you will be able to implement just basic animations, copy&paste some plugins and nothing more. And when you know Javascript on some level, you will probably see very little reason to use jQuery anymore.
In the code above, jQuery can be easily removed:
1: $(document).ready(handler) -> document.addEventListener("readystatechange",handler);
2: $('#switchables a') -> document.querySelectorAll("#switchables a");
3: $(nodeList).click(handler) ->
[].forEach.call(nodeList,function(node) {
// you can reuse node here, unlike the jQuery
node.addEventListener("click",handler);
});
4: $(node).removeClass(className) -> node.classList.remove(className)
5: $(node).addClass(className) -> node.classList.add(className)
It is a few chars longer. But it is more reusable, readable, effective and it is not God object or Cargo cult programming.
The native codes above are javascript standards and are supported in any decent browser. Three years ago, when Diodeus provided his answer, IE8 was an issue here. But it is dead now (under 2% worldwide according to gs.statcounter). Help it die completely by not supporting it.
Related
Good day.
I don't know the right terminology about my question but what I want to ask is how to ask is this:
//functionA
$(document).on('click', '.classA1, .classA2, .classA3', function(event) {
//i want to call the functionB when functionA is used.
//if possible, when I use the onclick on classB2
}
//functionB
$(document).on('click', '.classB1, .classB2', function(event) {}
note, I am new to JavaScript and was suddenly given a task by my boss. I cant really ask them about this since they are also new to the project/JavaScript since we just received the project from previous developer.
$('.classA1, .classA2, .classA3').on('click', ()=> {
console.log('function A called');
$('.classB1, .classB2').trigger('click');
});
$('.classB1, .classB2').on('click', ()=> {
console.log('function B called');
});
a {
display: inline-block;
background: teal;
padding: .5rem;
border-radius: 5px;
color: white;
font: 16px Arial, sans-serif;
cursor: pointer;
}
.b {
background: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a class="classA1">class A1</a>
<a class="classA2">class A2</a>
<a class="classA3">class A3</a>
<a class="classB1 b">class B1</a>
<a class="classB2 b">class B2</a>
If I would be thinking simply about it, I would declare two methods first and then use them as callbacks in the listeners.
function functionA(event) {
// implement your logic here
// and call functionB as well
functionB(event);
}
function functionB(event) {
// implement your B logic here
}
$(document).on('click', '.classA1, .classA2, .classA3', functionA);
$(document).on('click', '.classB1, .classB2', functionB);
This is actually not much else to be done as you can't delegate an event in such way as you wish it.
Imagine following scenario. Pink rectangle would be e.g. a span within a div (black rectangle) If you would add a click listener to the "div", then the click event would fire when you click the "div" and even if you click the "span". The click event propagated.
Otherwise you might want to add multiple click listeners to the same object. Then depending on your desire you can either interrupt the propagation (blocking the other listeners) by e.g. invoking the event.stopPropagation() method.
I would like the community to add more explanations if I missed something critical.
I have a site with a large outline, and I'm trying to let our users filter it down so they can see just the stuff they want. Each line of the outline has a set of classes that say what category it's in, and I'm hide/showing them via jQuery when the users select a particular category.
Here's the current location so you can see it in action:
https://courses.edx.org/courses/course-v1:HarvardX+CHEM160+1T2017/76695c0ad7604bb897570ecb906db6e3/
And here's the javascript and css for this page:
$(document).ready(function() {
console.log('working');
// Keeping track of all the currently visible items.
var currentlyShown = [];
var index;
var showAllButton = $('#showAll');
// If any of the object's classes match any of the selected options, show it.
function showRightClasses() {
console.log('showing: ' + currentlyShown);
if (currentlyShown.length == 0) {
showAllButton.click();
}
$('.hiddenpage').each(function(i) {
if (_.intersection(this.className.split(' '), currentlyShown).length > 0) {
$(this).show('slow');
} else {
$(this).hide('slow');
}
});
}
if (showAllButton.prop('checked')) {
currentlyShown.push('hiddenpage');
showRightClasses();
}
showAllButton.change(function() {
if (!this.checked) {
index = currentlyShown.indexOf('hiddenpage');
if (index !== -1) {
currentlyShown.splice(index, 1);
}
} else {
currentlyShown.push('hiddenpage');
}
showRightClasses();
});
$('.pageselector').change(function() {
subject = $(this).attr('name');
if (!this.checked) {
index = currentlyShown.indexOf(subject);
if (index !== -1) {
currentlyShown.splice(index, 1);
}
} else {
currentlyShown.push(subject);
}
if (showAllButton.prop('checked')) {
showAllButton.click();
}
showRightClasses();
});
});
.hiddenpage {
display: none;
}
.checkboxes {
float: right;
padding: 8px;
border: 4px outset #aaa;
border-radius: 8px;
background-color: #eee;
}
.checkboxes label {
display: inline;
}
.nav-section {
font-size: 120%;
font-weight: bold;
margin-top: 1em;
}
.nav-sub {
font-weight: bold;
margin-left: 1em;
}
.nav-unit {
font-weight: normal;
margin-left: 2em;
}
This works, but on Safari it's dreadfully slow, and it's not particularly fast on Firefox either. Is there a more efficient way to hide/show the rows in this outline without losing the animation? Am I accidentally doing something foolish like having every row run code that hides every other row?
I should note that I have no ability to control the rest of the environment. I can't change the version of jQuery that the site uses, or remove Underscore, for example. I can only control the code you see above, and the HTML for the list.
First of all, if you care about speed, ditch the 'slow' param in .show('slow') and .hide('slow'). This triggers a very performance-heavy jQuery animation.
With all the frames you're loosing right now, this will not work nice anyway. If you need animation there, maybe you could try something with opacity instead, since (css-based) opacity animation is very cheap.
EDIT: just checked this on the site you linked and it works nice and snappy with just .show() and .hide(). The 'slow' param is definitely your bottleneck, so either just remove it or look for a different way to animate, if you absolutely need to.
I am trying to customize the standard dots that come with slick.js.
I have a class "transparent-circle" that I want to use as dots and when the dot is active I want to use the class "active"
This what my classes look like:
.transparent-circle {
border: 2px solid #fff;
height:12px;
width:12px;
-webkit-border-radius:75px;
-moz-border-radius:75px;
}
.active{
background-color: rgba(126, 222, 186, 1);
border: 2px solid #7EDEBA !important;
}
Here's what I've tried to customize the dots. I've been trying to do it with jquery in my document.ready function
$('.slick-dots li button').remove();
$('.slick-dots li').addClass('transparent-circle');
So I want to remove the standard buttons and add the css class to the list items but nothing seems to be happening, unfortunately
You have to run your functions after Slick initialized.
So this is an example , using on init
Add this before your setup :
$('.your-element').on('init', function(event, slick){
var $items = slick.$dots.find('li');
$items.addClass('transparent-circle');
$items.find('button').remove();
});
// Setup
$('.your-element').slick({
// ....
});
In external script file
$(document).ready(function(){
$(".your-slider").slick({
dots: true,
customPaging: function(slider, i) {
return '<div class="custom-slick-dots" id=' + i + "></div>";
}
});
});
Apply your styles to .custom-slick-dots
Then for the active state, apply your styles to .slick-active .custom-slick-dots
You can customise the div as you wish.
P.S. Sorry if this is not a tailored answer...it's more of a general one for anyone who needs it. 😬
try:
$('#yourID').slick({
...,
customPaging: function(slider, i) {
return ''; // Remove button, customize content of "li"
}
});
$('#yourID .slick-dots li').addClass('transparent-circle'); // Add class to "li"
There are a bunch of div elements on the page.
I have a nested div inside of them.
I want to be able to add a class to the clicked element, and .show() the child div.
$('.container').on('click', function(){
$(this).toggleClass('red').children('.insideItem').slideToggle();
});
I can click on it, it drops down.
Click again, it goes away.
So, now I need some method to removeClass() and slideUp() all of the other ones in the event of a click anywhere except the open div. Naturally, I tried something like this:
$('html').on('click', function(){
$('.container').removeClass('red').children('div').slideUp();
});
Well, that just stops the effect from staying in the first place. I've read around on event.Propagation() but I've read that should be avoided if possible.
I'm trying to avoid using any more prebuilt plugins like accordion, as this should be a pretty straightforward thing to accomplish and I'd like to know a simple way to make it work.
Would anyone be able to show a quick example on this fiddle how to resolve this?
Show only one active div, and collapse all others if clicked off
https://jsfiddle.net/4x1Lsryp/
One way to go about it is to update your code with the following:
1) prevent the click on a square from bubbling up to the parent elements
2) make sure to reset the status of all the squares when a new click is made anywhere.
$('.container').on('click', function(){
$this = $(this);
$('.container').not($this).removeClass('red').children('div').slideUp();
$this.toggleClass('red').children('div').slideToggle();
return false;
});
See the updated JSfiddle here: https://jsfiddle.net/pdL0y0xz/
You need to combine your two approaches:
for (var i = 0; i < 10; i++) {
$('#wrap').append("<div class='container'>" + i + "<div class='insideDiv'>Inside Stuff</div></div>");
}
$('.container').on('click', function() {
var hadClassRed = $(this).hasClass('red');
$('.container').removeClass('red').children('div').slideUp();
if (!hadClassRed) {
$(this).toggleClass('red').children('div').slideToggle();
}
});
.container {
width: 200px;
height: 200px;
float: left;
background: gray;
margin: 1em;
}
.insideDiv {
display: none;
}
.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap"></div>
<script>
$(document).ready(function(){
$("tr :odd").attr("class" : "dark"),
$("tr :even").attr("class" : "light")
});
</script>
This is the code I am using to give classes to rows in a table.
For some reason, It keeps throwing Uncaught SyntaxError: missing ) after argument list
It is a really good practice to end every sentence with a semicolon.
The problem is that you use attr function wrong.
It takes two plain values (key and value) or a JS object as a single argument.
Key-value:
$("tr :odd").attr("class", "dark");
$("tr :even").attr("class", "light");
Object:
$("tr :odd").attr({"class": "dark"}); // Usually for multiple values
$("tr :even").attr({"class": "light"}); // Usually for multiple values
Moreover, changing class through attr is a really bad practice.
Use jQuery addClass and removeClass functions:
$("tr:odd").addClass("dark");
$("tr:even").addClass("light");
And, finally, are you sure you really need this?
You have CSS like:
.dark
{
background-color: #333333;
}
.light
{
background-color: #CCCCCC;
}
You can do it this way:
.tr:nth-chlid(odd)
{
background-color: #333333;
}
.tr:nth-chlid(even)
{
background-color: #CCCCCC;
}
It is great to avoid using scripts whenever it is possible.
You should do it like this (using an object literal):
$(selector).attr({"class": "dark"})
or
$(selector).attr("class", "dark")