The general SPA feature is working well however my slider inside the content is not working. It appears that the Javascript for the slider does not reload on XHR load.
What can I do to reload this script (and others) on XHR load?
Hi @novella, you probably don’t need to reload any script – just define a function with the desired functionality, and call that again after populating the page with the new content.
BTW there's a bug in your code, which is preventing the `load()` function from getting called after clicking a link; in jQuery, there's no `classList.add()` (this would be the regular DOM API), the corresponding method would be `addClass()`:
$('#tabs-loader').addClass('load')
Edit: Ah scratch that, just noticed you defined your own $() function which does indeed return a DOM element.
No problem… well the documentation says the slider has still to be instantiated after loading the script:
<script src="siema.min.js"></script>
<script>
new Siema();
</script>
So after loading new content, you don’t need to load siema.min.js again but just create new Siema() instances as necessary. Not sure if siema requires manual cleanup, but to be sure you might also destroy the existing slider beforehand:
let slider = new Siema()
function load (href, pushState) {
const xhr = new XMLHttpRequest()
slider.destroy()
xhr.onload = function () {
// ... populate content, then
slider = new Siema()
}
}
I’ve tried to implement this today and this either breaks Tabs or the Siema any way I do it.
Here is my the setup as of now:
(function () {
'use strict';
function load(href, pushState) {
let slider = new siema();
const content = $('main');
const xhr = new XMLHttpRequest();
slider.destroy();
xhr.onload = function () {
const d = xhr.responseXML;
const dTitle = d.title || '';
const dcontent = $('main', d);
content.innerHTML = (dcontent && dcontent.innerHTML) || '';
document.title = dTitle;
if (pushState) {
history.pushState({}, dTitle, href);
}
content.focus();
window.scrollTo(0, 0);
document.body.classList.remove("opened");
slider = new Siema();
};
xhr.onerror = function () {
// fallback to normal link behaviour (fail graciously)
document.location.href = href;
return;
};
xhr.open('GET', href);
xhr.responseType = 'document';
xhr.send();
}
function $(sel, con) {
return (con || document).querySelector(sel);
}
/**
* Search for a parent anchor tag outside a clicked event target
*
* @param {HTMLElement} el the clicked event target.
* @param {number} maxNests max number of levels to go up.
* @returns the anchor tag or null
*/
function findAnchorTag(el, maxNests = 3) {
for (let i = maxNests; el && i > 0; --i, el = el.parentNode) {
if (el.nodeName === 'A') {
return el;
}
}
return null;
}
window.addEventListener('click', function (evt) {
const el = findAnchorTag(evt.target);
const href = el?.getAttribute('href');
if (el && href) {
if (
href.startsWith('#') ||
el.getAttribute('target') === '_blank' ||
/\.\w+$/.test(href)
) {
// eleventy urls in this configuration do not have .html extensions
// if they have, or if target _blank is set, or they are a hash link,
// then do nothing and load normally.
return;
}
// initiate SPA
evt.preventDefault();
load(href, true);
}
});
window.addEventListener('popstate', function (e) {
load(document.location.pathname, false);
});
})();
So this should be destroying Siema and then repopulating it on XHR. This is breaking the SPA functionality though so I have no way to identify if it is actually re-initing Siema.
The constructor is misspelled here, and the let declaration is at the wrong place… have a closer look at my previous post, you’d need to keep a slider reference outside the load() function.
Okay so I have moved the reference out of load() function and this now breaks tabs.
(function () {
'use strict';
let slider = new Siema()
function load(href, pushState) {
const content = $('main');
const xhr = new XMLHttpRequest();
slider.destroy()
xhr.onload = function () {
slider = new Siema()
const d = xhr.responseXML;
const dTitle = d.title || '';
const dcontent = $('main', d);
content.innerHTML = (dcontent && dcontent.innerHTML) || '';
document.title = dTitle;
if (pushState) {
history.pushState({}, dTitle, href);
}
content.focus();
window.scrollTo(0, 0);
document.body.classList.remove("opened");
};
xhr.onerror = function () {
// fallback to normal link behaviour (fail graciously)
document.location.href = href;
return;
};
xhr.open('GET', href);
xhr.responseType = 'document';
xhr.send();
}
function $(sel, con) {
return (con || document).querySelector(sel);
}
/**
* Search for a parent anchor tag outside a clicked event target
*
* @param {HTMLElement} el the clicked event target.
* @param {number} maxNests max number of levels to go up.
* @returns the anchor tag or null
*/
function findAnchorTag(el, maxNests = 3) {
for (let i = maxNests; el && i > 0; --i, el = el.parentNode) {
if (el.nodeName === 'A') {
return el;
}
}
return null;
}
window.addEventListener('click', function (evt) {
const el = findAnchorTag(evt.target);
const href = el?.getAttribute('href');
if (el && href) {
if (
href.startsWith('#') ||
el.getAttribute('target') === '_blank' ||
/\.\w+$/.test(href)
) {
// eleventy urls in this configuration do not have .html extensions
// if they have, or if target _blank is set, or they are a hash link,
// then do nothing and load normally.
return;
}
// initiate SPA
evt.preventDefault();
load(href, true);
}
});
window.addEventListener('popstate', function (e) {
load(document.location.pathname, false);
});
})();
Here is my Siema reference to enable multiple sliders:
const siemas = document.querySelectorAll('.siema'); // allows for mutiple sliders on a page
for (const siema of siemas) {
new Siema({
selector: siema,
perPage: {
0: 1,
1024: 2,
1280: 3
},
multipleDrag: true
})
}
Well where exactly are you doing this? In your load() function you’re now initializing a new Siema()before populating the content… so if you go back to post #6, it should be something like this:
Carousel’s working okay now with Tabs however they do not initialize on page load too. Can I make it reference a new Siema on XHR load and initial page load.
This also breaks this code that references the Siema as well:
Surely I do not have to put this in under XHR load as well.