Loading JS functions on dynamically loaded pages - javascript

I am using CSS-Tricks dynamic page script found here.
http://css-tricks.com/dynamic-page-replacing-content/
$(function() {
var newHash = "",
$mainContent = $("#main-content"),
$pageWrap = $("#page-wrap"),
baseHeight = 0,
$el;
$pageWrap.height($pageWrap.height());
baseHeight = $pageWrap.height() - $mainContent.height();
$("nav").delegate("a", "click", function() {
window.location.hash = $(this).attr("href");
return false;
});
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if (newHash) {
$mainContent
.find("#guts")
.fadeOut(200, function() {
$mainContent.hide().load(newHash + " #guts", function() {
$mainContent.fadeIn(200, function() {
/*
$pageWrap.animate({
height: baseHeight + $mainContent.height() + "px"
});
*/
});
$("nav a").removeClass("current");
$("nav a[href="+newHash+"]").addClass("current");
});
});
};
});
$(window).trigger('hashchange');
});
Body
<body onload="onLoad()">
I am using a number generating script (below) on one of my pages, but I am having trouble getting it to only show on one, single page. When placed in the head of the document or my includes/scripts.php that is loaded on every page, it shows on every page. When only included on the page I want, it does not work.
<script>
function counter() {
var num = 0;
for (num = 0; num < 500; num++) {
document.write(num + ' ');
}
}
counter();
</script>
I have tried a few different things but can't seem to get it to only appear on a single page. Is there any way around this without ditching the CSS-Tricks Dynamic Page?

What if you insert your code into dynamicpage.js like this?
$(window).bind('hashchange', function(){
newHash = window.location.hash.substring(1);
if(newHash === 'somePage') { // the page you want to implement the effect
// your code
}
/*
....
*/
});

You might try adding a class to your <body> tag (or other near-to-top level wrapper if you're just dynamically loading to the HTML attribute of your body tag in the first place) that lets the script distinguish between pages that ought to use the function and those that don't, something like:
$(document).ready( function() {
$(`body.usesCounter`).on(eventToBeCounted, counterFuncAsCallback);
}
But the fact that it's not working when only loaded on a single page does suggest you've got something else going on. Can you give us the header for the single page, the script block (and where it is on the page), and some sense of how/when it's called?
Are you loading the single page dynamically? If you are, the script tags won't be accessible unless you reload the DOM somehow or else do some funky binding via jQuery's $.on() or something similar that listens for changes to the DOM.
UPDATE
Looking at the tutorial you are trying to emulate, the general problem you're facing is that the JS on that page you're loading isn't going to be registered with the DOM. I've had to write code that can read dynamically lodaded JS like this, and if you want to do it both effectively and securely, it's quite a lot of effort. The point of JS-based page loading is to be fetching "view-like" content; assets, html, etc.. In a single-page environment, any required logic should—generally—exist on that page.
I highly recommend you include the code in your initial page, and then conditionally call it when the appropriate page arrives. There are lots and lots of ways to do that, basically find some distinguishing feature of the page(s) where your counter should be run, and, after having loaded the page, look for said features and, if found, allow your code to run. You might have something as simple as a variable, isCounterPage set, by default, to false. Then, after a dynamic page load occurs, if the inspection fires and this var remains false, don't execute code associated with the counter. Otherwise, let it do its thing.

Related

JavaScript only being called once in Squarespace

I have some custom JavaScript on my SquareSpace site that manipulates Product titles beyond what you can do with SquareSpace's default style editor. It works when initially loading the page (https://www.manilva.co/catalogue-accessories/) but if you click on any of the categories on the left, the styling resets to the default.
I'm assuming the JavaScript is being overwritten by the SquareSpace style, but I can't figure out why. Perhaps I'm calling the function in the wrong place?
Any suggestions would be helpful.
Thanks!
Current code:
document.querySelectorAll(".ProductList-filter-list-item-link".forEach(i=>i.addEventListener("click", function()
{
var prodList = document.querySelectorAll("h1.ProductList-title");
for (i = 0, len = prodList.length; i < len; i++)
{
var text = prodList[i].innerText;
var index = text.indexOf('-');
var lower = text.substring(0, index);
var higher = text.substring(index + 2);
prodList[i].innerHTML = lower.bold() + "<br>" + higher;
});
The source of your problem is that your template has AJAX loading enabled. There are currently a couple generally-accepted ways to deal with this as a Squarespace developer:
Disable AJAX loading
Write your javascript functions in a
manner that will run on initial site load and whenever an "AJAX load" takes place.
Option 1 - Disable AJAX:
In the Home Menu, click Design, and then click Site Styles.
Scroll down to Site: Loading.
Uncheck Enable Ajax Loading.
Option 2 - Account for AJAX in Your JS
There are a number of ways that developers approach this, including the following, added via sitewide code injection:
<script>
window.Squarespace.onInitialize(Y, function() {
// do stuff
});
</script>
or
<script>
(function() {
// Establish a function that does stuff.
var myFunction = function() {
// Do stuff here.
};
// Initialize the fn on site load.
myFunction();
// myFunction2(); , etc...
// Reinit. the fn on each new AJAX-loaded page.
window.addEventListener("mercury:load", myFunction);
})();
</script>
or
<script>
(function() {
// Establish a function that does stuff.
var myFunction = function() {
// Do stuff here.
};
// Initialize the fn on site load.
myFunction();
// Reinit. the fn on each new AJAX-loaded page.
new MutationObserver(function() {
myFunction();
// myFunction2(); , etc...
}).observe(document.body, {attributes:true, attributeFilter:["id"]});
})();
</script>
Each of those works for most of the latest (at time of writing) templates most of the time. Each of those have their advantages and disadvantages, and contexts where they do not work as one might expect (for example, on the /cart/ page or other "system" pages). By adding your code within the context of one of the methods above, and ensuring that the code is of course working in the desired contexts and without its own bugs/issues, you will have your code run on initial site load and on each AJAX page load (with some exceptions, depending on the method you use).
Your problem is the page does not reload when clicking a button on the left, just some elements are removed, added and replaced. The changed elements will not be restyled. You will need to re-run your JavaScript after one of those buttons is clicked. Perhaps something like this:
document.querySelectorAll(
".ProductList-filter-list-item"
).forEach(
i=>i.addEventListener(
"click", ()=>console.log("hello")
)
)
where you replace console.log("hello") with whatever resets your formatting.

Building an Ajax System for loading New Page Content via link classes

The idea is each page has the same header and footer exactly, but each page has inner content that will change each page load
<header>blah blah blah</header>
<div id="main-content">Changes Each Page, but with links like Go to Another Page with smooth animation</div>
<footer>blah blah blah</footer>
I have written this script based off an earlier version I saw somewhere, however I am having an issue where no scripts are being fired. The site's overall scripts are all loaded on the initial page load, and I just need the scripts to be re-run each time you click on a link, that way I can have the seamless effect of the site pages loading inside the page, and adding custom CSS animations when each custom page loads.
var newHash = '',
$mainContent = $('#main-content');
$(".ajaxify").click(function(event) {
event.preventDefault();
newHash = $(this).attr('href');
history.pushState(null, null, newHash);
$mainContent.load(newHash + " #main-content > *");
return false;
});
I attempted to add a .getscript block when ajax is completed, but I found that it starts making the page loads really heavy and starts firing off errors.
$(document).on("ajaxComplete",function(){
$.getScript( "http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" );
$.getScript( "http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js" );
$.getScript( "../js/libraries.js" );
$.getScript( "../js/footer.js" );
});
What am I missing?
Big thanks to beercohol, he set me on the right direction. I didn't need to reload the whole javascript stack from the head each time; just the javascript in the footer. This solved so many issues at once.
EDIT: I also discovered that by changing it to "delegate" vs onclick, I dont' need to reload the initial ajax script again. Very handy and keeps the pages light.
Final Code example is this:
var newHash = '',
$mainContent = $('#main-content');
$('body').delegate(".ajaxify", "click", function() {
event.preventDefault();
$("html, body").animate({ scrollTop: 0 }, 500);
newHash = $(this).attr('href');
history.pushState(null, null, newHash);
$mainContent.delay(500).load(newHash + " #main-content > *");
return false;
});
$(document).on("ajaxComplete",function(){
jQuery.get('/js/footer.js', function(data) { eval(data); })
});
Assuming your scripts are loaded in your header, then you don't need to reload them with .getScript. That would just keep adding them into the page again for every link you click!
Your main function looks mostly correct - although it seems to be missing the first line - but the .load doesn't look quite right. Try something like this:
$(document).ready(function() {
var newHash = '',
$mainContent = $('#main-content');
$(".ajaxify").click(function(event) {
event.preventDefault();
newHash = $(this).attr('href');
history.pushState(null, null, newHash);
$mainContent.load(newHash + ' #main-content');
return false;
});

Measure loading time in Jquery

I have a question about a Javascript-file I've made. It makes sure hyperlinks open in a div and not in a new tab. However, I've also made a very simple text-inclusion to show while the page is loading.
$(document).ready(function () {
$('a').on('click', function(e){
e.preventDefault();
var page_url = $(this).prop('href');
var loading =
$('#content')
.html('<h2>The page is loading. A second please.</h2>')
.load(page_url);
});
});
However, some pages are considerably loading faster than others. In other words, in some pages it's very useful to have this script, but when a page is loading immediately, it's just simply very annoying.
Is it possible to measure the time that the 'load' takes, and accordingly, display html or not? (I was thinking about something like: "If time-loading>1000 .html('blabla') / Else").
You can do something like that:
var timer = setTimeout(function() {
$('#content').html('<h2>The page is loading. A second please.</h2>');
timer = null;
}, 1000);
$('#content').load(page_url, function() {
if (timer) {
clearTimeout(timer);
}
});
For fellow googlers, I combined the comments and the answer above to provide a solution. What I did was the following: instead of not displaying the loading message if the page was loading within a second, I made sure it was at least displaying at least a second:
$(document).ready(function () {
$('a').on('click', function(e){
e.preventDefault();
$('#content').html("<div id='status' class='status'></div>");
$('#status').html('<h2>The page is loading. A second please.</h2>');
var page_url = $(this).prop('href');
var loadingMsg = setTimeout(function(){
$('#content').load(page_url, function (){
clearTimeout(loadingMsg);
$('#status').html();
});
},1000);
});
});
The reasons why I did this, is because I couldn't get the timeout-function consistent. Sometimes it worked perfectly, but sometimes the screen just froze and nothing was displayed until the page loaded. Now, it is displayed at least a second, and if the loading takes more, it will be displayed until the page loads.
Thanks for your answers and I hope this helps for people with a similar problem!

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

Using jQuery-Smooth-Scroll from one page to another?

I am currently using jQuery-Smooth-Scroll to smoothly scroll up and down to various anchor positions on one of my pages (Page 1). However, what I would also like to be able to do is, from another page (Page 2), link to Page1 (appending #bookmark to the url) and have jQuery-Smooth-Scroll pick up on the fact I am calling the page with a #bookmark and have it smoothly scroll down to the relevant position once the page has completed loading. I don't know if this is a possibility or not?
This is the version of Smooth-Scroll that I'm using:
https://github.com/kswedberg/jquery-smooth-scroll
I'm still relatively new to jQuery so I may be overlooking something obvious.
Ajma's answer should be sufficient, but for completeness:
alert(location.hash)
Edit: a more complete example:
// on document.ready {
if (location.hash != '') {
var a = $("a[name=" + location.hash.substring(1) + "]");
// note that according to w3c specs, the url hash can also refer to the id
// of an element. if so, the above statement becomes
// var a = $(location.hash);
if (a.length) {
$('html,body').animate({
scrollTop: $(a).offset().top
}, 'slow');
}
}
// }
It's possible, you want to put a call into the smooth scroll function when the page is finished loading. in jQuery, it's using $(document).ready(function () { your code } );
You'll need to put something in to parse your url to extract the #bookmark and then call the smooth scroll.

Categories