JQuery doesn't handle dynamic events with .load - javascript

On a webpage, when you click a link, the content of that page is fetched using the .load function. If nothing is found, then nothing happens.
The issue now is that if you go from one page to the next, and then back again, the code doesn't work.
Its a lot easier to go to my test site - http://joshblease.co.uk/JQuery/
Click on the orange link "Page"
Click on the header link "Index"
Now click on the orange "Page" link again
The page refreshes and I do not know why?
Edit: I am using Chrome to test this at the moment
Edit: My Code
function JLoad (url, elem, type) {
if(type != "ext"){
var $link = elem;
var uri = url + ' #content';
$("#content").load(uri, {'body_only': '1'}, function(response, status, xhr){
if (status != "error") {
if (window.history && window.history.pushState){
window.history.pushState({}, 'JoshBlease Test', url);
}else{
window.location.hash='!/'+url;
}
if(type == "menu"){
$("a").removeClass("active");
$link.addClass("active");
}
}else{
if(type == "menu"){
var linkText = $link.text();
$link.fadeOut(function(){$link.addClass("notFound").text("404 Error")}).fadeIn().delay(2000).fadeOut(function(){$link.removeClass("notFound").text(linkText)}).fadeIn();
}
}
});
}
};
This is in the header of the pages:
$(document).ready(function() {
$("a").on("click", function(event) {
console.log("Click");
event.preventDefault();
var url = $(this).attr("href").replace('./', '');
JLoad(url, $(this), $(this).attr("type"));
return false;
});
});
The Link being used:
Page

I am not sure why, but by using an old version of JQuery, I replaced the "on" event with "live". It now seems to work?

Related

AJAX call not updating partial page content after clicking backwards/forwards on website

I am trying to generate history states so I can click backwards and forwards on my AJAX-powered pages. It largely works, but on one page my AJAX call doesn’t update page content when I click a button after loading a previous/later page state. Why?
The issue happens with the #filtered_posts div. On my home page, I display posts inside #filtered_posts with a category filter above it. When I click a button on the category filter, it updates the content inside #filtered_posts. If I click back or forward on the homepage without pressing a category filter button, it successfully retrieves the page with the correct state of #filtered_posts. But if I then click on a category filter button, my website URL updates but #filtered_posts doesn't, and clicking back/forward only changes the URL. How can I fix this?
Also, is there a way for me to only update the state of #filtered_posts when clicking back or forwards on the home page, and update content in the .main div for all other pages?
Here is my simplified code:
$(document).ready(function () {
var $mainContent = $(".main");
var mainContentHTML;
var value;
var title;
var filtered_posts = $("#filtered_posts");
$(document).on("click", "nav li a", function (e) {
e.preventDefault();
value = $(this).attr("href");
$mainContent.load(value + " .main", function (data) {
console.log("this function works properly");
})
});
$(document).on("click", "#category-filter li.filter-button", function (e) {
e.preventDefault();
value = $(this).find("a").attr("href");
var category = $(this).data("category");
$.post(wp_ajax.ajax_url, {
action: "filter",
category: category
},
function (data, status, xhr) {
if (status == "success") {
filtered_posts.html(data);
}
if (status == "error") {
console.warn(data);
}
});
});
//Create history to enable back button functionality
$(document).ajaxComplete(function (event, jqXHR, settings) {
mainContentHTML = $(".main").html();
title = $(document).find("h1.entry-title").text();
var stateObj = {
content: mainContentHTML
};
window.history.pushState(stateObj, title, value);
});
window.addEventListener('popstate', function (event) {
var state = event.state == null ? mainContentHTML : event.state.content;
$mainContent.html(state);
});
});
I've managed to fix this by replacing the filtered_posts variable with $("#filtered_posts") in the code.

Hash anchor links fail to find/target ID DOM element target (in certain circumstances)

Hash anchor links fail to find/target ID DOM element target (and therefore fail to trigger JS UI tab change)
Hi visit https://eurosurveillance.org/content/10.2807/1560-7917.ES.2019.24.40.1900157 and scroll down the HTML fulltext (shown in this tab) and try clicking on the link marked 'Supplement 1' or 'Supplement 2' note nothing happens.
There is nothing clever about the links they are normal html hash links....
Supplement 1
Now if you visit the same page but this time do a hard reload with the following URL in the browser address bar https://eurosurveillance.org/content/10.2807/1560-7917.ES.2019.24.40.1900157#html_fulltext (notice the only change is the hash in the URL). Now try following the same instructions as before and you will notice that for some reason the anchor link is now followed and the anchor tab JS is triggered this is behaviour that I am expecting
Please advise. thanks in advance.
Hi many thanks the issue was resolved by refactoring the responsive-tabs.js code:
$(document).ready(function() {
//responsive tabs API code.
var Tabs = {
init: function() {
this.bindUIfunctions();
this.pageLoadCorrectTab();
},
bindUIfunctions: function() {
// Delegation
$(document)
.on("click", ".js-transformer-tabs a[href^='#']:not('.active, .disabled')", function(event) {
Tabs.changeTab(this.hash);
event.preventDefault();
})
.on("click", ".js-transformer-tabs a.active, .js-transformer-tabs a.disabled", function(event) {
Tabs.toggleMobileMenu(event, this);
event.preventDefault();
})
.on("click", ".js-textoptionsFulltext a.html:not('.disabled')", function(event) {
//console.log("tab?" + this.hash);
event.preventBubble=true;
var anchorTab = Tabs.changeTab(this.hash);
anchorTab.trigger("click"); //trigger click event in this case it will be html fulltext.
//event.preventDefault();
});
//We also need to handle the back state by telling the browser to trigger the tab behaviour!
$(window).on('popstate', function(e) {
anchor = $('[href="' + document.location.hash + '"]');
if (anchor.length > 0) {
Tabs.displayTab(anchor);
} else {
var defaultAnchor = $('.js-transformer-tabs li.active a');
if (defaultAnchor) {
Tabs.displayTab(defaultAnchor)
}
}
});
},
changeTab: function(hash) {
var anchor = $(".js-transformer-tabs a[href='" + hash + "']");
var activeTab = anchor.find('span strong');
Tabs.displayTab(anchor);
$(".js-dropdown li").hide();
$(".js-mobile-tab").text($(activeTab).text());
// update history stack adding additional history entries.
// pushState is supported!
history.pushState(null, null, hash);
// Close menu, in case mobile
return anchor; // make property available outside the function
},
pageLoadCorrectTab: function() {
//console.log("document.location.hash: " + document.location.hash);
if (document.location.hash.length > 0) {
// If the page has a hash on load, go to that tab
var anchor = $(".js-transformer-tabs a[href='" + document.location.hash + "']");
if (!anchor.hasClass("disabled")) {
var anchorTab = this.changeTab(document.location.hash);
// this is a further amendment to allow the fulltext and
//(any future event if its attached) to load when bookmarking a page with a particular tab.
anchorTab.trigger("click");
}
} else if ($(".js-transformer-tabs .active.tabIcon .active").length > 0) {
// go to which ever tab is defined as active in the JSP page and trigger a click on it
// but, only when no hash in the url
var activeTab = $(".js-transformer-tabs .active.tabIcon .active");
activeTab.trigger("click"); //trigger click
}
},
toggleMobileMenu: function(event, el) {
$(el).closest("ul").toggleClass("open");
},
displayTab: function(anchortab) {
var url = anchortab.attr("href");
//console.log("url" + url);
var divtabContent = $(url);
// activate correct anchor (visually)
anchortab.addClass("active").parent().siblings().find("a").removeClass("active");
// activate correct div (visually)
divtabContent.addClass("active").siblings().removeClass("active");
}
}
Modernizr.load([{
//test
test : Modernizr.history,
//if yes then do nothing as nothing extra needs loading....
//if no then we need to load the history API via AJAX
nope : ['/js/' + ingentaCMSApp.instanceprefix + '/vendor/history.min.js'],
complete : function() {
var location = window.history.location || window.location;
Tabs.init();
}
}])
});
//end of responsive tabs API code.
$(".js-select").click(function(){
$(".js-dropdown li").slideToggle();
});

jQuery Issue about Continue button opens external link in multiple browser tabs

I am doing one feature about showing alert on external link(apart from current domain) click. For that, I have written below code. All is working fine except below scenario.
$('a').each(function() {
var $a = jQuery(this);
if ($a.get(0).hostname && getDomain($a.get(0).hostname) != currentDomain) {
$a.click(function(event) {
//console.log($a.get(0));
//var myClasses = this.classList;
//console.log(myClasses.length + " " + myClasses['0']);
$("#redirectconfirm-modal").removeClass('hide');
if (!confirmed) {
event.preventDefault();
event.stopPropagation();
$modal.on('show', function() {
$modal.find('.btn-continue').click(function() {
confirmed = true;
$a.get(0).click();
$modal.modal('hide');
location.reload();
});
});
$modal.on('hide', function() {
$a.get(0).removeClass("selected");
confirmed = false;
});
$modal.modal('show');
}
});
}
});
Scenario which produces this issue:
Click on any external link from the site, it open a modal popup for redirection confirmation with continue & return button.
If I click on "Return" button it closes the modal popup.
Now, I am clicking on external link from my site, it open the modal again but this time I am clicking on "Continue" button & guess what, it open that external link in 3 different tabs
Actually on each anchor tag click, it saves whole anchor tag value. I think, if remove all these anchor tag values on modal close code i.e. $modal.on('hide', function() { }) it will resolve problem. I had tried with many different ways but still facing this issue.
Can you please provide solution/suggestion on that?
Problem is when you have 3 external links (as you probably have), than you set 3 times this part of code:
$modal.on('show', function() { ... });
$modal.on('hide', function() { ... });
which is wrong. Those events listeners should be set only once.
Some simplified code would look like this:
var $modal = $("#redirectconfirm-modal");
var currentDomain = 'blabla';
$modal.on('click', '.btn-continue', function(e) {
window.location = $modal.data('redirectTo');
});
$('a').each(function() {
var $a = jQuery(this);
if( $a.get(0).hostname && getDomain($a.get(0).hostname)!=currentDomain ) {
$a.click(function(e) {
$modal.data('redirectTo', $a.attr('href'));
$modal.modal('show');
});
};
});
Don't inline your events, you may try something like this:
$('a').each(function() { //add a class to all external links
var $a = jQuery(this);
if ($a.get(0).hostname && getDomain($a.get(0).hostname) != currentDomain) {
$a.addClass('modalOpen');
}
});
$('.modalOpen').not(".selected").click(function(event) { //open the modal if you click on a external link
event.preventDefault();
$('.modalOpen').addClass('selected'); //add class selected to it
$modal.modal('show');
});
$modal.on('hide', function() {
$('.selected').removeClass("selected");//remove the class if you close the modal
});
$('.btn-continue').click(function() {
$('.selected').click();//if the users clicks on continue open the external link and hide the modal
$modal.modal('hide');
});

Event triggered before data is inserted into page (After AJAX call)

This site (http://nelation.net/) loads pages by using AJAX and pushState. AJAX retrieves the contents of section#body and the path for the new CSS.
The following code sends the AJAX request, retrieves the new contents of section#body (page contents) and a new CSS path. Then it inserts those into the page, and after that it calls the "pageLoad" event - That's the event I believe is triggered too early.
function loadPage(url) {
var target = document.getElementById("body");
var xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.onreadystatechange = function() {
if (xhr.readyState < 4) {
target.innerHTML = "";
}
if (xhr.readyState == 4 && xhr.status == 200) {
// Function to decode the new page
var decodeEntities = (function() {
// this prevents any overhead from creating the object each time
var element = document.createElement('div');
function decodeHTMLEntities (str) {
if(str && typeof str === 'string') {
// strip script/html tags
str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
element.innerHTML = str;
str = element.textContent;
element.textContent = '';
}
return str;
}
return decodeHTMLEntities;
})();
var resultJSON = JSON.parse(xhr.responseText);
var page = decodeEntities(resultJSON.page);
// Remove existing CSS and insert new one
$(".page-css").remove();
if (resultJSON.css != "none") {
$("<link/>", {
"class": "page-css",
rel: "stylesheet",
type: "text/css",
href: resultJSON.css
}).appendTo("head");
}
// Insert page contents, then trigger the pageLoad event
$(target).html(page);
$("body").trigger("pageLoad");
}
};
xhr.send();
}
// Detect link clicks, and make AJAX calls out of them + pushState.
$("body").on("click", '[data-ajax="true"]', function(event) {
event.preventDefault();
// detect which page has been selected
var newPage = $(this).attr("href");
if (newPage != window.location) {
window.history.pushState({path: newPage}, "", newPage);
}
loadPage(newPage);
});
The "pageLoad" event handler is found in this script. It re-executes most of the script, most notably the centerPlayButton_Featured() function if you're in the home page. That function resizes the overlay you see when you hover the image on the home page; It works fine when you load the page normally, but when you get to the page via AJAX it will not. The function is still executed (Logs to console), but I suspect it executes before the content is loaded properly into the page.
// DOES NOT RE-EXECUTE ON AJAX
function centerPlayButton_Featured() {
console.log("centerPlayButton_Featured() just executed");
var coverWidth = $("section.home-latest-release img.cover").width();
var coverHeight = $("section.home-latest-release img.cover").height();
$("section.home-latest-release div.cover-overlay").css({
"height": coverWidth + "px",
"width": coverHeight + "px"
});
}
$("body").click(function(e) {
if ($(e.target).hasClass("dropdown-text")) {
if ($(e.target).siblings(".menu").hasClass("open")) {
$(e.target).siblings(".menu").removeClass("open");
$(e.target).removeClass("open");
} else {
$(".dropdown .menu, .dropdown .dropdown-text").removeClass("open");
$(e.target).siblings(".menu").addClass("open");
$(e.target).addClass("open");
}
} else {
$(".dropdown .menu, .dropdown .dropdown-text").removeClass("open");
}
});
// RE-EXECUTES ON AJAX
$("body").on("pageLoad", function() {
$(function() {
// HOME PAGE
if ($("#body").children().hasClass("home-latest-release")) {
centerPlayButton_Featured();
$(window).on('resize', function() {
centerPlayButton_Featured();
});
}
// MUSIC PAGE
if ($("#body").children().hasClass("music-tracks")) {
//...
}
// CONTACT PAGE
$(function() {
if ($("#body").children().hasClass("contact")) {
$("textarea").bind("input", function() {
var offset = this.offsetHeight - this.clientHeight;
$(this).css("height", "auto").css("height", this.scrollHeight + offset);
});
}
});
});
});
$("body").trigger("pageLoad");
I appreciate any help/feedback. Go to the link to see more of the code, and tell me if you need to see the back-end. I apologize if the code is messy and comment-lacking. Thank you very much for the help.
Another problem I'm having is when you go to the music page, you may see all the dropdown menus fading out. Not as important as the main question, but help would be appreciated :)
The pageLoad event is not triggered because it is bound to the window load event:
$(window).bind("load", function() {
$("body").trigger("pageLoad");
});
load happens only once during the lifetime of a window, and that time has long passed when an ajax request can even start. Trigger pageLoad directly.
$(function () {...}) is executed once when the DOM has finished loading. Effectively, you are wrapping the code to be executed twice with the same event load which only happens once. Execute your setup code directly inside the pageLoad event handler. I'd write it like this:
function pageSetup () {
// HOME/MUSIC/CONTACT PAGE setup code
}
$("body").on("pageLoad", pageSetup);
pageSetup();

Reduce HTTP requests

I'm using this code to dynamically load external pages
$(function() {
$('#nav a').click(function() {
var page = $(this).attr('href');
$('#content').load(page + '.php');
return false;
});
});
I've noticed that each time I click on one of the menu tabs, a new HTTP request is sent and the page is loaded again. I'm wondering how to make each page load once so when I go through the tabs, the pages that have been already loaded display without sending new requets ?
You could "tag" tabs that are already loaded with a flag using .data() and only issue the HTTP request when the tag is non-existent.
Edit: Regarding Kryptonite's comment this would be a simple approach to the problem:
var pages = {};
$(function() {
$('#nav a').click(function() {
var page = $(this).attr('href');
if (!(page in pages)) {
$.get(page, function (data) {
pages[page] = data;
});
}
$('#content').html(pages[page]);
return false;
});
});
$('#nav a').click(function(e) {
e.preventDefault();
$this = $(this);
if ($this.data('loaded') !== true) {
// Load it.
$this.data('loaded', true);
} else {
alert('Already loaded that one!');
}
});
This will do what you need. You'll need to throw your load code in where I have the // Load it. comment, and might want to remove the else block as well. http://jsfiddle.net/rRumK/

Categories