jQuery Event Delegation for certain links - javascript

I'm having trouble delegating a click function to only certain links. Essentially, I'm trying to trigger a simple fadeout for all internal links that won't kill a lightbox functionality. Here's my problem (in essence):
HTML
<body>
<div id="fade">
<p>some content</p>
</div>
</body>
jQuery
$("#fade").on("click", "a", function () {
// get the href attribute
var newUrl = $(this).attr("href");
// veryfy if the new url exists or is a hash
if (!newUrl || newUrl[0] === "#") {
// set that hash
location.hash = newUrl;
return;
}
// now, fadeout the html (whole page)
$("body").fadeOut(function () {
// when the animation is complete, set the new location
location = newUrl;
});
// prevent the default browser behavior.
return false;
});
I can't figure out why this isn't working. The function isn't executed on any links. I'm trying to delegate it to all links within the wrapper id of "fade."
When I change
$("#fade").on("click", "a", function () {
to
$("document").on("click", "a", function () {
//specifying all links
The fade works perfectly, but it destroys the lightbox function that is needed for the site.
Is there a better way to delegate links for this event? Or perhaps not include the lightbox links in a different manner? Ideally I would keep the code above for executing on all links using $("document") and exclude the lightbox gallery from the function, but I don't know how I could do that.

Related

FadeIN FadeOUT page transition javascript bug

When I click any of my links to take me to a new HTML page, the javascript routes me to the same HTML page and not each links individual href.
Heres my code
$(document).ready(function() {
$('body').css('display', 'none');
$('body').fadeIn(1000);
$('.link').click(function(event) {
event.preventDefault();
newLocation = $('.link a').attr("href");
$('body').fadeOut(1000, newpage);
});
function newpage() {
window.location = newLocation;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="music" class="link">Music</div>
<div id="exhibition" class="link">Exhibition</div>
<div id="contact" class="link">Contact</div>
<div id="about" class="link">About</div>
My aim is to have the Page FadeIN on load and FadeOUT when a link has been clicked, I am getting my desired effect but im just not sure what this issue with the links is - Anyone know?
As #Taplar says, when you fetch the location from the link's href, you're not getting the right one. You're just fetch the first link in the document and looking at its href attribute.
You can easily fix this by replacing this (which looks for all anchor elements in the document that have an ancestor with the link class and then returns the first one it finds):
newLocation = $('.link a').attr('href');
with this (which finds all anchor elements as a child of whatever element has the click handler registered that was clicked):
newLocation = $(event.currentTarget).find('a').attr('href');
The other thing you're doing that is tricky, but doesn't necessarily break anything, is relying on newLocation being correctly shared between the click handler and the newpage function. I would suggest instead that you explicitly pass a parameter to newpage so that it is more reusable and you can be sure where the value is coming from.
You can see this working below.
$(document).ready(function() {
$('body').css('display', 'none');
$('body').fadeIn(1000);
$('.link').click(function(event) {
event.preventDefault();
newLocation = $(event.currentTarget).find('a').attr('href');
// Pass anonymous function to fadeOut that calls newpage with newLocation
$('body').fadeOut(1000, function () { newpage(newLocation); });
});
// newpage now accepts a parameter and uses it
function newpage(location) {
// Print to console so you can see what URL is getting used
// You'll always get 404 using StackOverflow's UI since they don't have the relevant pages
console.log(location);
window.location = location;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="music" class="link">Music</div>
<div id="exhibition" class="link">Exhibition</div>
<div id="contact" class="link">Contact</div>
<div id="about" class="link">About</div>

Show toggling div based on URL

I'm trying to have an anchor link, once clicked, show a div. I have a click toggle working on the page, but in addition to that functionality, if a user clicks a sidebar link, I don't want the div to toggle, I just want it to be shown, if hidden. I've tried several if thens, etc - I think this is the closest, but still not working.
Functions (first toggles the h4, the second is my attempt to have the same div shown if a URL is loaded...or the anchor link is clicked):
<script>
$(document).ready(function(){
//Hide (Collapse) the toggle containers on load
$(".toggle_container3").hide();
//Switch the "Open" and "Close" state per click then slide up/down (depending on open/close state)
$(".trigger3").click(function(){
$(this).toggleClass("active").next().slideToggle("slow");
return false; //Prevent the browser jump to the link anchor
}).first().click()
});
</script>
<script>
$(function() {
if ( document.location.href.indexOf('#papers') > -1 ) {
$("#papertoggle").show();
$("h4#papers").addClass("active");
})
});
</script>
Also tried this version, with the keyword either "papers" or "climate_change_test#papers" :
<script type="text/javascript">
// Get URL
var url = window.location.href;
// Get DIV
var msg = document.getElementById('papertoggle');
// Check if URL contains the keyword
if( url.search( 'climate_change_test#papers' ) > 0 ) {
// Display the message
msg.style.display = "block";
}
</script>
HTML of the link:
<li>Papers and Publications</li>
HTML of the h4 and div:
<h4 class="trigger3 dark_grey" id="papers">
Papers and Publications</h4>
<div class="toggle_container3" id="papertoggle"> content </div>
Entire test page:
http://www.sea.edu/sea_research/climate_change_test
This should work:
$("#over_left a").click(function(){
var id = $(this).attr("href");
$(id).toggleClass("active").next().slideToggle("slow");
});
However I would suggest to narrow down the $("#over_left a") selector so it only works on those specific submenu links.
Also tried this version, with the keyword either "papers" or "climate_change_test#papers" :
<script type="text/javascript">
// Get URL
var url = window.location.href;
// Get DIV
var msg = document.getElementById('papertoggle');
// Check if URL contains the keyword
if( url.search( 'climate_change_test#papers' ) > 0 ) {
// Display the message
msg.style.display = "block";
}
</script>
The reason why the above code didn't work, is because it is executed on page load. However, when you click an anchor tag url, the page doesn't reload (it only jumps to the relevant anchor div), so this code is never executed.
Please also be aware that you don't need a complicated search to look for the "#papers" part in your url. You can simply use:
window.location.hash
To find the anchor part at the end of your url.
So combining all of the info from above, you can also create a function that deals with the following example: What if someone shares a link with an anchor url? It should automatically expand already then, right?
// On page load
var anchor = window.location.hash;
// If there is an anchor in the URL, expand the relevant div
if (anchor) {
$(anchor).toggleClass("active").next().slideToggle("slow");
}

How to exclude JQuery/Javascript fade in & out function on certain links?

I'm using this fade in and out JQuery/Javascript effect on my site to have each page fade in and out when a link is clicked. It's working great when the link that is clicked leads to a different page, but it is causing problems when the link leads to a different part of the page (such as my back to top link), when a mailto link is clicked, and when a link that is suppose to open up in a new page or tab is clicked. When these type of links are clicked they just lead to a blank white page because they don't lead to a new page. Here is the script:
$(document).ready(function() {
//Fades body
$("body").fadeIn(1500);
//Applies to every link
$("a").click(function(event){
event.preventDefault();
linkLocation = this.href;
$("body").fadeOut(1000, redirectPage);
});
//Redirects page
function redirectPage() {
window.location = linkLocation;
}
});
Because of this I'm trying to figure out if there is a way where I can exclude this fade in/out function from certain links (such as the back to top link), but I don't know how to do it. I know that rather than set all the links to fade in/out I can set the fade in/out effect to a specific class that way it doesn't effect every link. However because the site is rather large, it would be extremely tedious and difficult to add that class to every link. So rather than do that I'm wondering if theres a way to define a no-fade class that would exclude this fade in/out function? That way I could apply that class to these few links that are having problems and make those links behave normally.
It seems like a simple thing to do, but because I'm still not very fluent in javascript/jquery I don't know how to do it. Any help would be much appreciated!
*EDIT: Here is the solution incase anybody else has a similar issue. Thanks to David for the missing piece!
$(document).ready(function() {
//Fades body
$("body").fadeIn(1500);
//Applies to every link EXCEPT .no-fade class
$("a").not(".no-fade").click(function(event){
event.preventDefault();
linkLocation = this.href;
$("body").fadeOut(1000, redirectPage);
});
//Redirects page
function redirectPage() {
window.location = linkLocation;
}
});
Yup, you could indeed define a class that when applied to an anchor would exclude it from performaing your fade out and redirect.
So if you had an anchor you wanted your default fade-out behaviour to apply to then simply leave it as is.If you didn't want this behaviour then you could apply a class (we'll call it *no-fade") to the anchor.
HTML
Another page
Back to top
jQuery
<script type="text/javascript>
$(document).ready(function() {
$("body").fadeIn(1500);
$("a").not(".no-fade").click(function(event){
event.preventDefault();
linkLocation = this.href;
$("body").fadeOut(1000, redirectPage);
});
// Redirects page
function redirectPage() {
window.location = linkLocation;
}
});
</script>
The only thing I've edited from your code is the selection of the anchors which I changed from:
$("a")
to
$("a").not(".no-fade")
The unobtrusive way would be to look for the hash symbol (#) or mailto:, etc. to prevent those types of links from fading out:
working fiddle
$("a").click(function (event) {
event.preventDefault();
linkLocation = $(this).attr('href');
if(linkLocation.indexOf('#') != -1 || linkLocation.indexOf('mailto:') != -1)
{redirectPage();}
else if($(this).attr('target') && $(this).attr('target').indexOf('_') != -1) window.open(linkLocation);
else $("body").fadeOut(1000, redirectPage);
});
Also, linkLocation = this.href should be linkLocation = $(this).attr('href')

Load javascript in html within content pane

I have an html file that I want to be loaded from various pages into a dijit.contentpane. The content loads fine (I just set the href of the contentpane), but the problem is that javascript within the html file specified by href doesn't seem to be executed at a consistent time.
The final goal of this is to load an html file into a contentpane at an anchor point in the file (i.e. if you typed in index.html#tag in order to jump to a certain part of the file). I've tried a few different methods and can't seem to get anything to work.
What I've tried:
1.
(refering to the href of the dijit.contentpane)
href="page.htm#anchor"
2.
(again, refering to the href of the dijit.contentpane -- didn't really expect this to work, but decided to try anyways)
href="#anchor"
3. (with this last try inside the html specified by href)
<script type="text/javascript">
setTimeout("go_to_anchor();", 2000);
function go_to_anchor()
{
location.href = "#anchor";
}
</script>
This last try was the closest to working of all of them. After 2 seconds (I put the delay there to see if something in the dijit code was possibly loading at the same time as my javascript), I could see the browser briefly jump to the correct place in the html page, but then immediately go back to the top of the page.
Dojo uses hashes in the URL to allow bookmarking of pages loaded through ajax calls.
This is done through the dojo.hash api.
So... I think the best thing you can do is use it to trigger a callback that you write inside your main page.
For scrolling to a given position in your loaded contents, you can then use node.scrollIntoView().
For example, say you have a page with a ContentPane named "mainPane" in which you load an html fragment called "fragment.html", and your fragment contains 2 anchors like this :
-fragment.html :
Anchor 1
<p>some very long contents...</p>
Anchor 2
<p>some very long contents...</p>
Now say you have 2 buttons in the main page (named btn1 and btn2), which will be used to load your fragment and navigate to the proper anchor. You can then wire that up with the following javascript, in your main page :
<script type="text/javascript">
require(['dojo/on',
'dojo/hash',
'dojo/_base/connect',
'dijit/layout/BorderContainer',
'dijit/layout/ContentPane',
'dijit/form/Button'],
function(on, hash, connect){
dojo.ready(function(){
var contentPane = dijit.byId('mainPane');
var btn1 = dijit.byId('btn1');
var btn2 = dijit.byId('btn2');
btn1.on("Click", function(e){
if (!(contentPane.get('href') == 'fragment.html')) {
contentPane.set("href", "fragment.html");
}
hash("anchor1");
});
btn2.on("Click", function(e){
if (!(contentPane.get('href') == 'fragment.html')) {
contentPane.set("href", "fragment.html");
}
hash("anchor2");
});
// In case we have a hash in the URL on the first page load, load the fragment so we can navigate to the anchor.
hash() && contentPane.set("href", "fragment.html");
// This callback is what will perform the actual scroll to the anchor
var callback = function(){
var anchor = Array.pop(dojo.query('a[href="#' + hash() + '"]'));
anchor && anchor.scrollIntoView();
};
contentPane.on("DownloadEnd", function(e){
console.debug("fragment loaded");
// Call the callback the first time the fragment loads then subscribe to hashchange topic
callback();
connect.subscribe("/dojo/hashchange", null, callback);
});
}); // dojo.ready
}); // require
</script>
If the content you're loading contains javascript you should use dojox.layout.ContentPane.

How to Separate Two jQuery Functions

I want to separate these functions. They should both work separately on click events:
FIRST FUNCTION
$("ul.nav li").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
ACTION A
});
$(window).trigger('hashchange');
});
SECOND FUNCTION
$("ul.subnav li").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
ACTION B
});
$(window).trigger('hashchange');
});
This is what happend in ACTION A:
$mainContent
.find(".maincontent")
.fadeOut(200, function() {
$mainContent.hide().load(newHash + " .maincontent", function() {
$mainContent.fadeIn(200, function() {
$pageWrap.animate({
height: baseHeight + $mainContent.height() + "px"
});
});
$(".nav a").removeClass("active");
$(".nav a[href="+newHash+"]").addClass("active");
});
});
The Problem is that if I click the Link of the Second function always the the first function fires.
Details of what I'm trying to do:
First, I build my site on .php to serve poeple without JavaScript. Now I want to load the "maincontent" dynamically. So I found this script I'm using:
http://css-tricks.com/6336-dynamic-page-replacing-content/
It does do a great job if you only want to load "maincontents".
But my site has sub-navigation on some pages where I want to load the sub-content. In .php these sites use includes. So I get my content by: href="page2.php?page=sub1"
So, when I click on the sub-links now they load also dynamically but the script also on the whole maincontent loading area. So it doesn't really load content by .load() but the sub-content of the includes do appear.
So what I thought was just to separate this function. The first to simply load the maincontents and a second one for the sub-navigation to refresh only the sub-content area. I don't even understand how this script loads the include content dynamically since the link is the straight page2.php?page=sub1 link. All dynamic loaded content usually looks like "#index", without the ending ".php".
Some quick history:
I'm trying to get the best page structure. Deliver .php for non JavaScript user and then put some dynamic loading stuff over it. Always with the goal to keep the browser navigation and the browser links (for sharing) for each page in tact.
I'm not an jQuery expert. All I have learned so far was by trial and error and some logical thinking. But of course, I have a lack of fundamental knowledge in JavaScript.
So my "logical" question:
How can I tell the "nav" links to perform only their "$(window).bind"-Event and to tell the "subnav" links only to perfom their "$(window).bin"-event.
Is this the right thinking?
Since I've already been trying to solve it for nearly the last 18h, I'll appreciate any kind of help.
Thank you.
IMPORTANT:
With the first function I not just only load the maincontent but also I'm changing a div on the page with every link. So for any solution that might want to put it together in one, it won't work, cause they should do different things on different areas on the page. That's why I really need to call on the window.bind with each nav/subnav click.
Can anyone show me how?
Melros,
In your second function, you are binding to the event hashchange2, which is incorrect. Instead, you STILL want to bind to hashchange. Instead of:
$(window).bind('hashchange2', function() {
...
});
Try:
$(window).bind('hashchange', function() {
...
});
If you want to namespace your event subscriptions, you can suffix the ending of the event you are binding to with a period (.) and then the namespace:
$("#test").bind("click.namespace1", function() { });
$("#test").bind("click.namespace2", function() { });
Ok, it seems that you want to execute action A when a link inside .nav is clicked, and action B when a link inside .subnav is clicked.
You can just put these actions inside the event handlers. Furthermor, if .subnav is nested inside .nav, you have to restrict your selector:
// consider only direct children
$("ul.nav > li").delegate("a", "click", function() {
var href = $(this).attr("href");
if(window.location.hash !== href) {
Action A
window.location.hash = $(this).attr("href");
}
return false;
});
// consider only direct children
$("ul.subnav > li").delegate("a", "click", function() {
var href = $(this).attr("href");
if(window.location.hash !== href) {
Action B
window.location.hash = $(this).attr("href");
}
return false;
});
I don't think listening to the hashchange event will help you here, as this event is triggered in both cases and you cannot know which element was responsible (you probably can somehow, but why make it overly complicated?).
Here's by the way the solution I came to:
After understanding that the haschange-event doesn't have to do anything with it (as long as you don't want to make the subcontent bookmarkable too) I just added a new load function for the subcontent:
$(function(){
$("ul.linkbox li a").live('click', function (e) {
newLink = $(this).attr("href");
e.preventDefault();
$(".textbox").find(".subcontent").fadeTo(200,0, function() {
$(".textbox").load(newLink + " .subcontent" , function() {
$(".subcontent").fadeTo(200,1, function() {
});
});
$("#wrapper").css("height","auto");
$("ul.linkbox li a").removeClass("activesub");
$("ul.linkbox li a[href='"+newLink+"']").addClass("activesub");
});
});
});

Categories