JQuery: combine click / trigger elements for more efficiently written code? - javascript

I am trying to figure out a more efficient way to write my code which works but it seems inefficient. Essentially I have a series of Id elements in a nav that trigger a click function on various ids elsewhere on the page. I tried combining my elements but that does not seem to work:
$("#red, #green, #blue").bind("click", (function () {
$("#section-red, #section-green, #section-blue").trigger("click");
alert("#section-red (Red heading) has been triggered!");
alert("#section-green (Green heading) has been triggered!");
alert("#section-blue (Blue heading) has been triggered!");
}));
... but this just seems to trigger everything.
I can do this below but for lots of ids, it will be a monster to maintain and update. Not sure if there is a better way.
$("#red").bind("click", (function () {
$("#section-red").trigger("click");
alert("#section-red (Red heading) has been triggered!");
}));
$("#green").bind("click", (function () {
$("#section-green").trigger("click");
alert("#section-green (Green heading) has been triggered!");
}));
// etc...
I have a fiddle here that I have been playing with but still no joy. Essentially a click on the top nav trigger a simulated click on an H2 heading which works but it's just the code efficiency at this point.

I would add data attributes to your nav elements like:
<ul>
<li id="red" data-trigger-id="#section-red">Section Red</li>
<li id="green" data-trigger-id="#section-green">Section Green</li>
<li id="blue" data-trigger-id="#section-blue">Section Blue</li>
</ul>
then in jQuery:
$("#red, #green, #blue").bind("click", (function () {
var triggerID = $(this).data("trigger-id");
$(triggerID).trigger("click");
}

Using event delegation you only need to register two event handlers.
$("ul").delegate("li", "click", function() {
var id = $(this).attr("id");
$("#section-"+id).trigger("click");
});
$(document).delegate("h2", "click", function() {
console.log($(this).attr("id"));
});
EDIT
You could make it more efficient by caching the element lookups
var h2 = [];
h2['red'] = $("#section-red");
h2['blue'] = $("#section-blue");
h2['green'] = $("#section-green");
Inside the ul delegate click handler
h2[id].trigger('click');
Fiddle

First, I would create a class for the ul - in this example, I called it "sections":
<ul class="sections">
<li id="red">Section Red</li>
<li id="green">Section Green</li>
<li id="blue">Section Blue</li>
</ul>
Next, bind a click even to $('.sections>li'), get the index, and apply it to the relative div.
$(".sections>li").click(function () {
var index=$(this).index();
$('.faqfield-question.accordion').eq(index).click();
});
That's all there is to it!
DEMO:
http://jsfiddle.net/6aT64/43/
Hope this helps and let me know if you have any questions!

How about doing something like this. This works for all browsers(including IE ;-) )
document.onclick = function(event){
event = event || window.event; //IE does not pass Object of event.
var target = event.target || event.srcElement;
switch(target.id){
case "header-red":
case "red-section":
redClicked();
break;
case "header-green":
case "green-section":
greenClicked();
break;
}
};

Related

Open/Close submenu when clicking the item name

I am having problems with the menu part of a wordpress site (salient theme), when i am on mobile, i open the menu with the hamburger button and have several options, some with sub menus, so the items with sub menus only open when clicking the little arrow icon to the right of the item, i am trying to get it to open also when you click on the item itself by making it so when you click the item it triggers a click on the arrow
here is the html of the menu
and here is the javascript i am doing to get it to work(only doing it for the first item with submenu here), i am new to javascript but for what i've seen i think this should work (i am using the Code Snippets
plugin for wordpress)
<?php
add_action( 'wp_footer', function () { ?>
<script>
var el = (document.querySelector('.menu-item.menu-item-type-custom.menu-
item-object-custom.menu-item-has-children.menu-item-5812 a'));
console.log(el);
var el2 =(document.querySelector('.menu-item.menu-item-type-custom.menu-
item-object-custom.menu-item-has-children.menu-item-5812 span'));
console.log(el2);
el.onclick = function()
{
$el2.click();
};
</script>
<?php } );
?>
SOLUTION:
aside from the answear by Alvaro Montoro i needed to encapsulate everything inside an eventListener with DomLoaded, here is the final code
add_action( 'wp_footer', function () { ?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var elSupervivencia = document.querySelector('#slide-out-widget-area > div >
div.inner > div > ul:nth-child(1) > li.menu-item.menu-item-type-custom.menu-
item-object-custom.menu-item-has-children.menu-item-5812 > a');
console.log(elSupervivencia);
var elSupervivenciaFlecha = document.querySelector('#slide-out-widget-area >
div > div.inner > div > ul:nth-child(1) > li.menu-item.menu-item-type-
custom.menu-item-object-custom.menu-item-has-children.menu-item-5812 .ocm-
dropdown-arrow i');
console.log(elSupervivenciaFlecha);
elSupervivenciaFlecha.onclick = function() {
console.log("Clicked on the span");
}
elSupervivencia.onclick = function(e)
{
e.preventDefault();
elSupervivenciaFlecha.click();
};
});
</script>
<?php } );
For what you seem to want, you almost have it. The only thing that seems to be missing is to prevent the default behavior when you click on the link (which could be a potential problem as pointed on the comments above, because the linked page may be innaccessible through the menu now).
With .preventDefault() you will prevent the default action for that element for that event, so you would just need to add that:
var el = (document.querySelector('.menu-item.menu-item-type-custom.menu-item-object-custom.menu-item-has-children.menu-item-5812 a'));
console.log(el);
var el2 = (document.querySelector('.menu-item.menu-item-type-custom.menu-item-object-custom.menu-item-has-children.menu-item-5812 span'));
console.log(el2);
el2.onclick = function() {
console.log("Clicked on the span");
}
el.onclick = function(e) {
e.preventDefault();
el2.click(); // removed the $
};
<ul class="menu">
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children menu-item-5812">
Supervivencia
<ul class="sub-menu">
<li>Supervivencia 1</li>
<li>Supervivencia 2</li>
<li>Supervivencia 3</li>
</ul>
<span class="ocm-drowndown-arrow" style="top: 17.5px">
<i class="fa-angle-down"></i>
</span>
</li>
</ul>
As they pointed in the comments, that may not be too usable, as the linked page is no longer accessible on the menu, you may want to add some conditions (checking for window size or a variable/class that indicates that the mobile menu is active) to perform that preventDefault().
Apart from that, you may want to consider changing the selector for el and el2, as they are not specific and could match more than one element. I know you are using querySelector so only the first element that matches the selector will be returned, which should not be a problem for el but could be problematic with el2 (because the a could be a child span that would be selected over the sibling one that is the one you want.)

Using a comparison table. Mobile responsive problem when more than one table added?

The comparison table I am using is here:
https://codepen.io/adrianjacob/pen/KdVLXY
When I duplicate the tables and the viewer goes mobile responsive; the buttons are only working for the first table.
Is there any classes or such I can add to the JavaScript and HTML so I can make each group of buttons specific to their table?
Button code:
<ul>
<li class="bg-purple">
<button>Self-Employed</button>
</li>
<li class="bg-blue">
<button>Simple Start</button>
</li>
<li class="bg-blue active">
<button>Essentials</button>
</li>
<li class="bg-blue">
<button>Plus</button>
</li>
JavaScript code:
// DIRTY Responsive pricing table JS
$( "ul" ).on( "click", "li", function() {
var pos = $(this).index()+2;
$("tr").find('td:not(:eq(0))').hide();
$('td:nth-child('+pos+')').css('display','table-cell');
$("tr").find('th:not(:eq(0))').hide();
$('li').removeClass('active');
$(this).addClass('active');
});
// Initialize the media query
var mediaQuery = window.matchMedia('(min-width: 640px)');
// Add a listen event
mediaQuery.addListener(doSomething);
// Function to do something with the media query
function doSomething(mediaQuery) {
if (mediaQuery.matches) {
$('.sep').attr('colspan',5);
} else {
$('.sep').attr('colspan',2);
}
}
// On load
doSomething(mediaQuery);
I'd really appreciate any help, thanks for your time.
The problem is that your jQuery targets are currently too generic, so when you have multiples, it only finds content from the first one and puts it in both. What your script does is update both tables.
I've forked the Codepen, added a second table, and tweaked a couple of values on our comparison table, so you should see different things in each (and each set of tabs acts separately)
https://codepen.io/CapnHammered/pen/QzBbqN
Key part you're missing is some form of parent selector - in this case, we've used an article tag to wrap our table:
$( "ul" ).on("click", "li", function() {
var pos = $(this).index()+2;
$parent = $(this).closest('article');
$parent.find("tr").find('td:not(:eq(0))').hide();
$parent.find('td:nth-child('+pos+')').css('display','table-cell');
$parent.find("tr").find('th:not(:eq(0))').hide();
$parent.find('li').removeClass('active');
$(this).addClass('active');
});
Try this:
$("ul").on("click", "li", function(e) {
var $clicked = $(e.currentTarget); // This will give you the clicked <li>
var $ul = $clicked.parent();
var $table = $ul.next(); // Only works if the table immediately follows the <ul>
var pos = $clicked.index() + 2;
$table.find("tr").find("td:not(:eq(0))").hide();
$table.find("td:nth-child(" + pos + ")").css("display", "table-cell");
$table.find("tr").find("th:not(:eq(0))").hide();
$clicked.siblings().removeClass("active");
$clicked.addClass("active");
});
Basically, when you click a <li> you should search the next table and show/hide the information only on that table. Before you were selecting all <tr> elements so it would affect all tables in the page.
EDIT: after re-reading your question this sentence left me confused:
When I duplicate the tables and the viewer goes mobile responsive; the buttons are only working for the first table.
When I try to duplicate the tables in your codepen the buttons work for both tables, not sure if I'm understanding your problem.

Changing the background color of a link after being clicked

I'd like to ask how to change the background color of each link (the rectangular shape surrounding it) to one different color after a link is clicked, and the other links still remain in its original background color.
Each link corresponds to one div placed in the same html file (that I didn't include here).
The point is to let the viewers know which link they are at. By the way, if it is okay I'm looking for the fastest code possible ^_^ (pure css, javascript or jQuery). Appreciate all suggestions!
the highlight only applied to the current link only! (the others will have the normal colors)
<div id="Navigation">
<div id="nav_link">
<ul id="MenuBar" class="MenuBarHorizontal">
<li><a class="MenuBarItemSubmenu" href="javascript:showonlyone('Index_frame');" >Home</a>
<ul>
<li><a href="javascript:showonlyone('Specification_frame');" >Specification</a></li>
<li><a href="javascript:showonlyone('Images_frame');" >Images</a></li>
<li>Video</li>
<li>Contact</li>
</ul>
</li>
<li><a href="javascript:showonlyone('Specification_frame');" >Specification</a></li>
<li><a href="javascript:showonlyone('Images_frame');" >Images</a></li>
<li>Video</li>
<li>Contact</li>
</ul>
</div>
<!--End of nav_link-->
</div>
<!-- End of Navigation-->
function showonlyone(thechosenone) {
$('.newboxes').each(function(index) {
if ($(this).attr("id") == thechosenone) {
$(this).show(1000).fadeIn(500);
}
else {
$(this).hide(1500).fadeOut(500);
}
});
}
EDITED
Guys, there is this one thing that I'm still stuck at even though I spent time on it a lot, I added some more JavaScript links the same with the above in the page with the idea that these new links will be functional just like the former. That is being clicked on ==> the highlight will appear only on these Navigation links. I tried to modify the function from jjurm like this
$(function(){
$("#MenuBar a,#colOne a").bind("click", function(){
var names=$(this).attr('name');
$("#MenuBar a").removeClass("clicked");
$("#MenuBar a[name='names']").addClass("clicked");
});
});
It didn't work and neither did the old ones that used to work
In a similar question to yours I once found out that only changes in text color are allowed some properties can be changed if you use a:visited pseudo-class (UPD: and background-color is one of them). But since your links are javascript links, the :visited selector will not work, hence you cannot do it as a pure CSS solution. You will have to use some kind of javascript. If jQuery is ok, you can try this:
$('a').on('click', function(){$(this).css("background-color","yellow");});
Perhaps you can change the "showonlyone" function? Then you could add the background changing code to it.
You can do this by simple css code:
#MenuBar a:visited {
background: yellow;
}
Edit:
As far as this doesn't work with javascript links (but I haven't tried it), there is other solution with jQuery and CSS.
jQuery code:
$(function(){
$("#MenuBar a").bind("click", function(){
$(this).addClass("clicked");
});
});
CSS:
#MenuBar a.clicked {
background: yellow;
}
Edit2:
Ok, if you want to keep highlighted only last clicked element, it's enough to add this simple line to javascript code:
$(function(){
$("#MenuBar a").bind("click", function(){
$("#MenuBar a").removeClass("clicked"); // Remove all highlights
$(this).addClass("clicked"); // Add the class only for actually clicked element
});
});
Edit3:
If you want to have more links that point to same location and to highlight all of them if one is clicked, follow this:
$(function(){
// Assume that your 'a' elements are in #MenuBar and #colOne
$("#MenuBar a, #colOne a").bind("click", function(){
// Remove all highlights
$("#MenuBar a, #colOne a").removeClass("clicked");
// Store the name attribute
var name = $(this).attr("name");
// Find all elements with given name and highlight them
$("#MenuBar a[name='"+name+"'], #colOne a[name='"+name+"']").addClass("clicked");
});
});
You can add an active class to the clicked anchor. Using live NodeList should work really fast as you also need to unselect previously selected item:
var a = document.getElementById('Navigation').getElementsByClassName('active');
$('#Navigation').on('click', 'a', function() {
if (a[0]) a[0].className = '';
this.className = 'active';
});
http://jsfiddle.net/vBUCJ/
Note: getElementsByClassName is IE9+ if you need to support older versions use jQuery:
var $a = $('#Navigation a');
$('#Navigation').on('click', 'a', function() {
$a.removeClass('active');
$(this).addClass('active');
});
http://jsfiddle.net/vBUCJ/1/
$('#MenuBar').on('click', 'a', function() {
$(this).css('background-color', '#bada55');
});
or if you need unique colors you can use the data-attribute.
$('#MenuBar').on('click', 'a', function() {
var $elem = $(this);
$elem.css('background-color', $elem.data('color'));
});
I'd recommended adding classes instead and using css to define styles.
$('#MenuBar').on('click', 'a', function() {
$(this).addClass('clicked-menu-link');
});
edit:
To remove the other clicks use:
$('#MenuBar').on('click', 'a', function() {
var fancyClass = 'clicked-menu-link';
$('#MenuBar a').removeClass(fancyClass).filter(this).addClass(fancyClass);
});

JQuery Show/Hide Link

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");
});

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