Ajaxinate Endless scolling has stopped product Quick View from working - ajax

I am using Shopify "Streamline Theme" with quick product view and I recently added infinite scroll to products on each collection using Ajaxinate.js.
When I open a collection page it loads with some products which is supposed to do, The products already there work fine with quick view and quick add to cart and also.
The Infinite scroll works fine and it loads new product fine but the problem is raised when the new products loaded through AJAX call doesn't have work with the quick view function.
I have tried to create a callback function to activate the quick view with no success, using the theme initialisation code with no success.
function callBack(){
theme.init();
theme.initQuickShop();
};
document.addEventListener("DOMContentLoaded", function() {
var endlessClick = new Ajaxinate({
method: "scroll",
loadingText: 'Loading...',
callback: callBack
});
});
Edit -------
My problem, is that when the page is loaded only the initial loaded products quickview elements are loaded in the DOM. When the scroll more button is clicked, the newly loaded products are loaded without their respective quickview elements. Hence why the quickview does't work for them. The theme.js file comes with this initialisation code:
theme.reinitProductGridItem = function($scope) {
if (AOS) {
AOS.refreshHard();
}
if (theme.settings.currenciesEnabled) {
theme.currencySwitcher.ajaxrefresh();
}
// Reload quick shop buttons
theme.initQuickShop(true);
// Refresh reviews app
if (window.SPR) {
SPR.initDomEls();SPR.loadBadges();
}
// Re-register product templates in quick view modals.
// Will not double-register.
sections.register('product-template', theme.Product, $scope);
// Re-hook up collapsible box triggers
theme.collapsibles.init();
};
I have tried to integrate this into a callback but no success, the quickview modal doesn't seem to load for the newly loaded products:
function callBack(){
ReloadSmartWishlist();
var $container = $('#CollectionSection');
theme.reinitProductGridItem($container);
// I have tried the following init qith no success:
// theme.init();
// theme.initQuickShop(true);
// theme.initQuickShop();
// sections.register('product-template', theme.Product, $container);
// AOS.refreshHard();
};
document.addEventListener("DOMContentLoaded", function() {
var endlessClick = new Ajaxinate({
method: "click",
loadingText: 'Loading...',
offset: 0,
callback: callBack
});
});
I am missing something but what? :/
Note for other things like loading products images with the callback and the wishlist app, it works as intended...

When you load elements via AJAX and if the events are not attached to a parent element that is not removed from the DOM, those elements will not have an attached event to them.
The term used here is event delegation.
Here is an example of non-delegated event:
document.querySelectorAll('a').addEventListener('click', function(){
// Do something
})
Since you are attaching the event to the existing "a" elements if you add new 'a' via AJAX those elements will not have the event since Javascript already attached all the events and it will not reattach them if you don't specifically recall them again.
Here is an example of a delegated event:
document.querySelector('body').addEventListener('click', function(target){
let target = event.target;
if (target.tagName === 'A'){
// Do something here
}
})
Where we attach the event to the body tag ( where it's a better idea to attach it to a closer none-modified parent element of the ajax items ) and once we click we check if our target tag is an "a" and do something then.
So long story short, you will need to delegate the quick cart link so that it works after you load the items via AJAX.

Drip is correct you need to delegate your event, but for people like me it's hard to completely understand how to do that.
I'm not sure how your quickview is structured, but if you open it with a .click function and can use jquery use the [.on() function][1].
For example: I use a quickview that opens on a button click. My button is attached to my product-grid-item.liquid with this bit of code:
<div class="quick-view-button">
<a class="quick-view" data-handle="{{ product.handle }}" href="javascript:void(0);">Quick View</a>
</div>
My quickview function originally looked like this:
function quickView() {
$(".quick-view").click(function () {
//all of the quickview code
What happens is exactly like you described. The event listeners only loaded on the first product load but nothing after an AJAX load.
Using jquery's .on() binds the event listener to the element meaning when it's loaded in later it'll still have the event. Here's an example of what my code looks like after using .on()
function quickView() {
$('body').on('click','.quick-view',function(){
I really hope this helps you or someone else with this problem.
[1]: http://api.jquery.com/on/

Related

jquery.mobile: no event triggered when loading an external page into the dom

Ok, first off do NOT confuse my use of the word "external" with the keyword external used in anchor tags. That's NOT what this is about.
I have a multiple page document and everything there works fine. I also have several other .html pages that are rarely ever used (i.e. about page) so I don't want to clutter the dom with them but rather load them as needed.
So, starting with the about.html page, when loaded, this page will (or should) give some info about the device it's running on as well as the version number of my app and whether or not there's a later version available (some people turn off automatic updates).
Before I go further, I want to put it on the record that the about.html page is working in another app when it's loaded with the rel="external" attribute set but I'm trying to move away from that.
So, inside my index.html I have a header with a nav bar and the anchor tag is straight forward:
<div data-role="popup" id="homeMenu" data-theme="b">   
     <ul data-role="listview" data-inset="true" >
        <li>About</li>
When I run the app in a simulator, the about.html gets loaded into the dom and becomes the active page so that part is working but not one event that I can figure out gets triggered.
I have tried all of the following:
$("body").on("pagecontainerbeforeshow", function( event, ui ) {
console.log("Going to: " +ui.toPage[0].id);
});
$(document).on('pagecreate', function() {
$(':mobile-pagecontainer').on('pagecontainerbeforeshow', function(event, ui) {
console.log('pagecontainerbeforeshow triggered');
console.log("Going to: " +ui.toPage[0].id);
});
});
// $( "#aboutPage" ).on("pagecontainerbeforeshow", function( event ) {
$( "#aboutPage" ).on("navigate", function( event ) {
console.log("aboutPage Ready!");
initMenu();
onAboutReady();
$('#aboutPage').on("swiperight", function () {
// I know, I know... one step at a time ;-)
window.location.href = 'index.html';
}); 
});
I would imagine that I can't attach an event handler to the about page as the about page doesn't yet exist in the dom so there must be another way to attach an event that actually gets fired.
What am I missing here?
Turns out the answer is easier than one might think! Instead of trying to trap an event for specific page that's not in the dom, simply trap the event for all pages, add in a switch statement and viola!
$("body").on("pagecontainerbeforeshow", function( event, ui ) {
console.log("pagecontainerbeforeshow -> Going to: " +ui.toPage[0].id);
switch(ui.toPage[0].id)
{
case "aboutPage": // <div id="aboutPage" data-role="page"
break;
}
});

Eventlisteners for jqm side panel on multiple pages

I am new to JQM and I'm using Phongeap with JQM for a new project.
My javascript is in one single js file and I'm loading the views from multiple html files.
As the transitions of the siede panel are poor, when I change pages via <a href="page2.html"> I tried to to use event listeners for the Menuitems.
function setPanelListeners(){
$('#menu_search').click(function() {
switchPageTo('search.html');
});
$('#menu_schedule').click(function() {
switchPageTo('program.html');
});
$('#menu_news').click(function() {
switchPageTo('news.html');
});
}
I call this function on the pagebeforeshoe event of each page. To fix the transitions to the way I need it, I use this function
// Close Panel then change page
function switchPageTo(url){
$('#menupanel').panel('close');
setTimeout(function() {
$.mobile.changePage( url, { transition: 'fade'} );
},200);
}
So here is the Problem. It actually works fine on the first page. But on the second page the Menuitems won't work, I guess the event listers are not listening for the new panel, because in the html the panel is loaded twice! And the Event listeners only listen for the first panel (from the first page) which is not displayed on the second page.
Any help is appreciated!
Are you adding panel dynamically on the second page? In JQM 1.3 you have to add panel separately to each page, although this restriction will be removed in future versions.
Use event delegation for dynamic panels:
$(document).on('click' ,'#menu_search' function() {
switchPageTo('search.html')
});

simple modal loader

I am new in using jquery. I am trying add in the simplemodal.js (Eirc Martin's simple modal) a function called 'jBox' that will take the data (ie link) and options and using ajax will load the content into the modal container. This way I want on my pages in several places easy call this function
jBox = function(address, options){
$.get(address, function(data) {
$.modal(data);
});
};
});
The code is working fine, but i would like to add a loading image before the content is fully loaded. There is a lots of similar posts about loader/ spinner in simplebox but none of the works for me.
I was trying following code
$('#test').load('<img src="loader.gif">').html(data);
$('#test').modal();
But, some way, it doesnt work for me. Any ideas what I am doing wrong? Thanks
I use the ajaxStart and ajaxStop events.
$("body").on({
ajaxStart: function() {
$(this).addClass("loading"); // so page knows it's in loading state
// .. your modal code
},
ajaxStop: function() {
$(this).removeClass("loading"); // not it loading state anymore
// .. What you should do if loading is done. (eg. hide modal)
}
});
In this case I set the body class to 'loading'. So you can do some magic in css if you like.
I tend to use it to disable forms as well.
body.loading div.some-class {
// your special style for during loading
}

Jquery code not executing on elements that didn't exist on page load

I have a web application that loads javascript on page load:
$(function() {
$('.modal-delete').click(function() {
alert();
});
});
I have a html page with a series of buttons which alert a blank message box when they're clicked:
<button class="modal-delete btn danger"></button>
which works fine.
However, a have some AJAX calls that generate more buttons just like the ones above but NOT on page load! They can be created at any time. These buttons do not do anything but they're meant to load the alerts. They're identical but because they never existed on page load, the Jquery code doesn't work on these buttons. How do I attach the same code to these buttons too?
Many thanks :).
I think you'll want jQuery's 'live()' function:
$('.modal-delete').live('click', function() {
alert();
});
This binds to the elements which match but also rebinds when new elements are added in the future:
"Attach an event handler for all elements which match the current selector, now and in the future"
Change the ready code to this...
$(function() {
$("document").on("click", ".modal-delete", function() {
alert("click");
});
});

Ajax loader and events runs more than once

I have a website that pages' contents loaded by ajax. All of my pages are seperate files actually and when I need to call a page, I just passed the link to my "pageLoader" function.
pageLoader handle with content loading and re-ignite/re-define the necessary functions like close button.
Since the actual function have ~250 lines, I did re-write a short version;
var pageLoader = function(link){
var page = $(link).attr("href").replace('#','');
if(page != lastCalledURL){
// Load the page.
$.ajax({
beforeSend: function(){ /* remove previously loaded content; */ },
success: function(data){
// remove the loaded content if user clicked to close button.
$("a.close-button").live("click", function(){
$(this).parent().fadeOut().remove();
return false;
});
// load another page if user click another page's link.
$("a.content-loader-link").live("click",function(){
pageLoader(this);
});
// handle with tabs
$("a.tabs").live("click", function(){
var index = $("a.tabs").index(this);
console.log(index);
return false;
});
}
});
lastCalledURL = page;
}
return false;
OK. If I click a link in the page, It calls pageLoader. If I click one of the links just once, pageLoader called once. If I click another link, pageLoader called twice. If I click another link again, pageLoader called third times and so on.
Same things happen for the links that bind with "live" function in the code. If I click a.tabs, it write to console twite. If I clicked another .tabs link, it write to console four times and increasing double for every click.
I don't why it happens. Please let me know if you have any idea.
You can solve it by using the bind and unbind. Like this:
$("a.tabs").unbind('click').bind("click", function(){
var index = $("a.tabs").index(this);
console.log(index);
return false;
});
But i would prefer that you attach this events in your $(document).ready function instead of everytime you make an AJAX call.
$(document).ready(function() {
// Attach your events here.
});
Those live event handlers "Attach a handler to the event for all elements which match the current selector, now and in the future." so you shouldn't need them in your ajax call.

Resources