JQuery Show/Hide Link - javascript

So here is my dilemma. Been trucking on this Jquery extreme code here and I need help telling if a certain link is showing or not. Here is what I have.
The toggles:
<span class="icon icon84"></span>
<span class="icon icon85"></span>
(notice the only thing that is different is the icon number) These need to toggle back and forth when someone clicks the #visbilitybutton. Not sure of the best way to do this and to capture what is selected as well.
The only code I have currently makes the toggle go one way, but doesn't go back when clicked again.
$(document).ready(function () {
$('#visbilitybutton').click(function() {
$(this).replaceWith('<span class="icon icon85"></span>');
});
});

First things first, you shouldn't have multiple identical id attributes on your page. Make visibilitybutton a class.
Anyways, you can use the jQuery toggle() function to specify what to do on each consecutive click:
$(".visibilitybutton").toggle(function(){
$(this)
.attr("title","Invisible")
.find("span").toggleClass("icon84 icon85");
}, function(){
$(this)
.attr("title","Visible")
.find("span").toggleClass("icon84 icon85");
});
If you want to be more efficient, you can do it all in one fell jQuery swoop like so, with some good techniques:
var vis = ["Invisible","Visible"];
$(".visibilitybutton").click(function(){
var i = 0;
$(this)
.attr("title",vis[i])
.find("span").toggleClass("icon84 icon85");
i = (i==0)?1:0;
});
Even more so would be to make a class that hides the element when added to it and shows it when you remove it (a classname with display:none applied in the CSS works fine):
$(".visibilitybutton").click(function(){
$(this)
.toggleClass("hide")
.find("span").toggleClass("icon84 icon85");
});

You need to have unique ids; therefore, you should select the items by class. You can use toggle() to handle the consecutive clicks, and you can use toggleClass() to handle the swapping of classes.
HTML:
<span class="icon icon84"></span>
<span class="icon icon85"></span>
Javascript:
$(document).ready(function () {
$('.button').toggle(function() {
var $button = $(this);
$button.prop("title","Invisible");
$button.find('.icon85').toggleClass('icon85', 'icon84');
}, function() {
var $button = $(this);
$button.prop("title","Visible");
$button.find('.icon85').toggleClass('icon84', 'icon85');
});
});

The id attribute is supposed to be unique to each element. Change the id attribute to the class attribute for each hyperlink.
Then, in your jQuery code, get the hyperlinks by their class name:
$('.visbilitybutton').click(function() {
// code goes here
});
In your event handler, you should use test the title attribute, like so:
$('.visibilitybutton').click(function() {
$this = $(this);
if ($this.attr("title") == "Visible")
$this.attr("title", "Invisible").find("span")
.removeClass("icon85").addClass("icon84");
else
$this.attr("title", "Visible").find("span")
.removeClass("icon84").addClass("icon85");
});

Related

Hide a div if an element has been clicked twice in a row, else Show

I have several items in my navigation bar, and a div next to it, ie:
<nav>
<a id="a"></a>
<a id="b"></a>
<a id="c"></a>
</nav>
<div id="menu-col"></div>
If the same link is clicked twice in a row, I want to hide #menu-col. If not, I want #menu-col to remain visible.
I'm not a javascript guy so I tried this:
var lastClicked;
$('nav a').on('click', function(e) {
alert(e.target.id + " - " + this.lastClicked);
if (e.target.id == this.lastClicked) {
$('#menu-col').hide();
this.lastClicked = '';
}
else {
$('#menu-col').show();
this.lastClicked = e.target.id;
}
});
Then I remembered that javascript assigns references, and not values. So when I did this.lastClicked = e.target.id; I'm assigning a reference to my element's id, then on the next click I make that e.target.id == ''.
In javascript, what would be the proper way of closing a box if the same link is clicked twice, and if not making sure the box is visible.
You can achieve this using toggleClass() to set a state class on the clicked a and also using toggle() on the .menu-col to show or hide it based on that state class. Try this:
$('nav a').click(function(e) {
e.preventDefault();
var $a = $(this);
$a.toggleClass('active').siblings().removeClass('active');
$('.menu-col').toggle($a.hasClass('active'));
});
.menu-col {
display: none;
}
.active {
color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<a id="a" href="#">a</a>
<a id="b" href="#">b</a>
<a id="c" href="#">c</a>
</nav>
<div class="menu-col">menu-col</div>
As long as you keep those ids unique across you app (which you should be doing anyway) the approach you've chosen isn't wrong. Any primitive in javascript is actually stored by value. Those primitives are string, number, boolean, and symbol. For more info see here https://developer.mozilla.org/en-US/docs/Glossary/Primitive
I would suggest something like this, you should have some kind of condition in which the div shows after it has been hidden.
$('nav a').dblclick(function(event) {
event.preventDefualt();
alert($(this).attr('id'));
$('#menu-col').toggle();
});
Something like that should be exactly what you are looking for, like I said though, there should be a condition in which it shows itself again, I made it a toggle so any double click on any 'nav a' element will cause it to show/hide the div.
Just for the sake of an option. Here is another way for double clicks(clicked twice in a row).
Using ondblclick event.
Double-click me.

jQuery slideDown not working on element with dynamically assigned id

EDIT: I cleaned up the code a bit and narrowed down the problem.
So I'm working on a Wordpress site, and I'm trying to incorporate drop-downs into my menu on mobile, which means I have to use jQuery to assign classes and id's to my already existing elements. I have this code that already works on premade HTML, but fails on dynamically created id's.
Here is the code:
...
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
$(document).on('click', '.dropdown-title', function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
//THIS LINE FAILS
$(currentAttrValue).slideDown(300).addClass('d-open');
}
e.preventDefault();
});
I've registered the elements with the class dropdown-title using $(document).on(...) but I can't figure out what I need to do to register the elements with the custom ID's. I've tried putting the event callback inside the .each functions, I've tried making custom events to trigger, but none of them will get the 2nd to last line of code to trigger. There's no errors in the console, and when I console log the selector I get this:
[ul#m0.sub-menu.dropdown-content, context: document, selector: "#m0"]
0
:
ul#m0.sub-menu.dropdown-content
context
:
document
length
:
1
selector
:
"#m0"
proto
:
Object[0]
So jQuery knows the element is there, I just can't figure out how to register it...or maybe it's something I'm not thinking of, I don't know.
If you are creating your elements dynamically, you should be assigning the .on 'click' after creating those elements. Just declare the 'on click' callback code you posted after adding the ids and classes instead of when the page loads, so it gets attached to the elements with .dropdown-title class.
Check this jsFiddle: https://jsfiddle.net/6zayouxc/
EDIT: Your edited JS code works... There also might be some problem with your HTML or CSS, are you hiding your submenus? Make sure you are not making them transparent.
You're trying to call a function for a attribute, instead of the element. You probably want $(this).slideDown(300).addClass('d-active'); (also then you don't need $(this).addClass('d-active'); before)
Inside submenus.each loop add your callback listener.
As you are adding the class dropdown-title dynamically, it was not available at dom loading time, that is why event listener was not attached with those elemnts.
var menuCount = 0;
var contentCount = 0;
//find the mobile menu items
var submenus = $('[title="submenu"]');
if (submenus.length && submenus.parent('.fusion-mobile-nav-item')) {
console.log(submenus);
submenus.addClass('dropdown-title').append('<i id="dropdown-angle" class="fa fa-angle-down" aria-hidden="true"></i>');
submenus.each(function() {
$(this).attr("href", "#m" + menuCount++);
// add callback here
$(this).click( function(e) {
var currentAttrValue = $(this).attr('href');
if ($(e.target).is('.d-active') || $(e.target).parent('.dropdown-title').is('.d-active')) {
$(this).removeClass('d-active');
$(currentAttrValue).slideUp(300).removeClass('d-open');
} else {
$('.dropdown-title').removeClass('d-active');
$('.dropdown-content').slideUp(300).removeClass('d-open');
$(this).addClass('d-active');
console.log($(currentAttrValue));
$(currentAttrValue).slideDown(300).addClass('d-active');
}
e.preventDefault();
});
})
var content = submenus.parent().find('ul.sub-menu');
content.addClass('dropdown-content');
content.each(function() {
$(this).attr("id", "m" + contentCount++);
})
}
Turns out my problem is that jQuery is adding to both the mobile menu and the desktop menu, where the desktop menu is being loaded first when I search for that ID that's the one that jQuery finds. So it turns out I was completely wrong about my suspicions.

jQuery disable the previous span and the next span, on click span

I'm having trouble applying class to the previous element or the next element.
<a href="#"><span class="glyphicon glyphicon-thumbs-up up"></span>
<a href="#"><span class="glyphicon glyphicon-thumbs-down down"></span>
I want to disable the second span, when I click the first span and vice versa.
$(document).on('click','.up, .down',function (e){
e.preventDefault();
if ($(this).hasClass('up')){
var down = $(this).parent().nextAll('a.comment-vote-down');
down.removeClass('disable-link').addClass('disable-link');
}else if($(this).hasClass('down')){
var up = $(this).parent().prevAll('a.comment-vote-up');
up.removeClass('disable-link').addClass('disable-link');
}
});
example on jsfiddle
You try to find class .comment-vote-down that doesn't exist in your HTML code
https://jsfiddle.net/xnovq390/4/
try this:
$(document).on('click','.up, .down',function (e){
e.preventDefault();
if ($(this).hasClass('up')){
var down = $(".down");
down.removeClass('disable-link').addClass('disable-link');
}else if($(this).hasClass('down')){
var up = $(".up");
up.removeClass('disable-link').addClass('disable-link');
}
});
It's because you don't have an a with a class of .comment-vote-down, or comment-vote-up.
Either take that part out of your nextAll selection:
.nextAll('a');
https://jsfiddle.net/xnovq390/1/
or, add in the class to your HTML:
<a href="#" class="comment-vote-up">
https://jsfiddle.net/xnovq390/3/
If the .up element is always the previous element from the .down one, you can simply do:
$(document).on('click', '.up, .down', function(e) {
e.preventDefault();
if ($(this).hasClass('up')) $(this).next().addClass('disable-link');
else $(this).prev().addClass('disable-link');
}
$(document).on('click','.up, .down',function (e){
e.preventDefault();
if ($(this).hasClass('up')){
$(this).addClass('disable-link');
$('span.down').removeClass('disable-link');
}else if($(this).hasClass('down')){
$(this).addClass('disable-link');
$('span.up').removeClass('disable-link');
}
});
As the other answers already stated, there is no spoon element with .comment-vote-down class.
But additionally to make life easier, you could buffer the 2 elements, bind the click to them and disable the ones not clicked, reducing the code to
var btns = $('.up, .down');
btns.click(function(){
btns.not(this).addClass('disable-link');
});
fiddle
If you'd want to disable the containing a, the 'other's parent could be obtained by chaining parent() : btns.not(this).parent().addClass('disable-link'); ( or .closest('a') if there is a deeper hierarchy)

how to repeat same Javascript code over multiple html elements

Note: Changed code so that images and texts are links.
Basically, I have 3 pictures all with the same class, different ID. I have a javascript code which I want to apply to all three pictures, except, the code needs to be SLIGHTLY different depending on the picture. Here is the html:
<div class=column1of4>
<img src="images/actual.jpg" id="first">
<div id="firsttext" class="spanlink"><p>lots of text</p></div>
</div>
<div class=column1of4>
<img src="images/fake.jpg" id="second">
<div id="moretext" class="spanlink"><p>more text</p></div>
</div>
<div class=column1of4>
<img src="images/real.jpg" id="eighth">
<div id="evenmoretext" class="spanlink"><p>even more text</p></div>
</div>
Here is the Javascript for the id="firsttext":
$('#firstextt').hide();
$('#first, #firsttext').hover(function(){
//in
$('#firsttext').show();
},function(){
//out
$('#firsttext').hide();
});
So when a user hovers over #first, #firsttext will appear. Then, I want it so that when a user hovers over #second, #moretext should appear, etc.
I've done programming in Python, I created a sudo code and basically it is this.
text = [#firsttext, #moretext, #evenmoretext]
picture = [#first, #second, #eighth]
for number in range.len(text) //over here, basically find out how many elements are in text
$('text[number]').hide();
$('text[number], picture[number]').hover(function(){
//in
$('text[number]').show();
},function(){
//out
$('text[number]').hide();
});
The syntax is probably way off, but that's just the sudo code. Can anyone help me make the actual Javascript code for it?
try this
$(".column1of4").hover(function(){
$(".spanlink").hide();
$(this).find(".spanlink").show();
});
Why not
$('.spanlink').hide();
$('.column1of4').hover(
function() {
// in
$(this).children('.spanlink').show();
},
function() {
// out
$(this).children('.spanlink').hide();
}
);
It doesn't even need the ids.
You can do it :
$('.column1of4').click(function(){
$(this); // the current object
$(this).children('img'); // img in the current object
});
or a loop :
$('.column1of4').each(function(){
...
});
Dont use Id as $('#id') for multiple events, use a .class or an [attribute] do this.
If you're using jQuery, this is quite easy to accomplish:
$('.column1of4 .spanlink').hide();
$('.column1of4 img').mouseenter(function(e){
e.stopPropagation();
$(this).parent().find('.spanlink').show();
});
$('.column1of4 img').mouseleave(function(e){
e.stopPropagation();
$(this).parent().find('.spanlink').hide();
});
Depending on your markup structure, you could use DOM traversing functions like .filter(), .find(), .next() to get to your selected node.
$(".column1of4").hover(function(){
$(".spanlink").hide();
$(this).find(".spanlink, img").show();
});
So, the way you would do this, given your html would look like:
$('.column1of4').on('mouseenter mouseleave', 'img, .spanlink', function(ev) {
$(ev.delegateTarget).find('.spanlink').toggle(ev.type === 'mouseenter');
}).find('.spanlink').hide();
But building on what you have:
var text = ['#firsttext', '#moretext', '#evenmoretext'];
var picture = ['#first', '#second', '#third'];
This is a traditional loop using a closure (it's better to define the function outside of the loop, but I'm going to leave it there for this):
// You could also do var length = text.length and replace the "3"
for ( var i = 0; i < 3; ++i ) {
// create a closure so that i isn't incremented when the event happens.
(function(i) {
$(text[i]).hide();
$([text[i], picture[i]].join(',')).hover(function() {
$(text[i]).show();
}, function() {
$(text[i]).hide();
});
})(i);
}
And the following is using $.each to iterate over the group.
$.each(text, function(i) {
$(text[i]).hide();
$([text[i], picture[i]].join(', ')).hover(function() {
$(text[i]).show();
}, function() {
$(text[i]).hide();
});
});
Here's a fiddle with all three versions. Just uncomment the one you want to test and give it a go.
I moved the image inside the div and used this code, a working example:
$('.column1of4').each(function(){
$('div', $(this)).each(function(){
$(this).hover(
function(){
//in
$('img', $(this)).show();
},
function(){
//out
$('img', $(this)).hide();
});
});
});
The general idea is 1) use a selector that isn't an ID so I can iterate over several elements without worrying if future elements will be added later 2) locate the div to hide/show based on location relational to $(this) (will only work if you repeat this structure in your markup) 3) move the image tag inside the div (if you don't, then the hover gets a little spazzy because the positioned is changed when the image is shown, therefore affecting whether the cursor is inside the div or not.
EDIT
Updated fiddle for additional requirements (see comments).

jQuery Mouseover DOM

I have a number of elements (the total number of which I do not know). I want something to appear when I mouse-over any one of these elements (which is taken care of by having a mouseover bound to the shared class of these elements).
However, the thing that I want to appear on mouseover is dependent on what the cursor is over - so I need to get the DOM element under the cursor, without the luxury of being able to bind mouseover events to each element in code.
Any suggestions?
HTML:
<a id="say1" class="say" href="#" data-word="one">Say 'one'</a>
<a id="say2" class="say" href="#" data-word="two">Say 'two'</a>
<a id="say3" class="say" href="#" data-word="three">Say 'three'</a>
Javascript (with jQuery):
$(document).ready(function () {
$('.say').mouseover(function () {
alert($(this).data('word'));
});
});
Pure Javascript (without jQuery, it is not equivalent):
window.onload = function () {
var onmouseover = function (e) {
alert(e.target.getAttribute('data-word'));
};
var elems = document.getElementsByClassName('say');
for (var i = 0; i < elems.length; i += 1) {
elems[i].onmouseover = onmouseover;
}
};
Instead of calling alert function you may implement any logic.
Event delegation is your friend here.
See this post from Christian Heilmann on that topic http://www.icant.co.uk/sandbox/eventdelegation/.
HTH.
jQuery makes this easy with .each():
$('#container').bind('mouseover', function () {
$(".selector").each(function(){
// Do something $(this) = item clicked
$(this).toggleClass('.example'); // Toggle class is just an example
});
});
You can then check certain characteristics of $(this) and then do different things based on the values/characteristics.

Categories

Resources