I have built a pretty simple WordPress blog however nearing the final stages I have run into a small problem that I cannot figure out for the life of me!
The site is http://lincsbusiness.co/, its running an ajax request so when you get the the bottom on the page its calls the next issues from the next page. Pretty simple.
However, if you follow these step you will be able to see the problem that I am talking about.
Refresh the home page
Expand the first issue, so you can see the sub headlines
Scroll to the bottom and till you get to issue 12
Try and expand that, and you will notice that the expansion bounces.
I am using the jQuery call back feature so after the AJAX request has finished it allows the jQuery to keep working.
And to stop having duplicate piece of jQuery for one before the event and one after, I have given the first four issue in the list unique identifiers, which are different to the one in the callback.
Here is the code I am using
jQuery(document.body).on('click', '.before-load', function(event) {
jQuery(this).closest('.thepost').find('.thepost-entry').slideToggle('slow');
});
And I use another piece, which is identical but just uses the '.after-load' class, just so I can separate them.
If you can replicate the issue and see whats going on, and have a potential fix. that would seriously save me my sanity.
Thanks
I have a feeling this is because you are re-adding the listener for the click each time you expand the page, so probably every time you load more posts, the next post you click bounces +1 times.
I'd recommend stopping any other jQuery execution, removing the 'click' handler, then letting the ajax call expand the page...and then re-adding the 'click' handler to each post.
Related
I have a page with bunch of 3rd party JS scripts. When I load the page, it scrolls down to a specific div.
I already spent 2 hours trying to find out which code is causing the scroll.
Is there a way to find out which script / part of the code is triggering the scroll?
Wow, was this hard to debug. Seems like the debugger has some missing features, like tracking the emitter of an event.
The problem is WooCommerce. Specifically, it appears that WooCommerce is setting autofocus on the billing_last_name input field. The browser is then automatically scrolling the page to bring the field into view.
One would hope that there is a configuration option to turn off autofocus, but it appears WooCommerce does not provide this.
You can try adding this to your theme
function disable_autofocus_firstname($fields) {
$fields['billing']['billing_first_name']['autofocus'] = false;
return $fields;
}
add_filter('woocommerce_checkout_fields', 'disable_autofocus_firstname');
If that doesn't work, you can create a CSS rule to hide the billing name field and then run a delayed JS function to show the billing name field after the page is fully loaded.
How I debugged it
Per the OP's request, and considering the bounty offered, I will describe how I debugged this.
I'm a little embarrassed that I didn't just say to myself "Hmm, the page scrolls up to a form, the cursor is in the first field of the form, I wonder if it has autofocus set." Unfortunately, I'm not mainly a front-end programmer, and autofocus did not come to mind at first.
I started with the idea that it was being scrolled via JavaScript, either an explicit call to a scroll function or by setting scrollTop on something. I put an event breakpoint on the scroll event and tried to determine where the scroll event was being generated. Although I found the scroll event, I did not find the source of it. All I could determine at this stage is that the scroll event was targeting the document, not something inside it.
I used monitorEvents to listen for events on document and found only 3, a click and 2 scrolls, the last of which was caused by a delayed scroll-to-top function inserted by the OP to work around the first scroll. I put an execution breakpoint on setting that timeout (not executing the function) in an attempt to "divide and conquer", that is, to see if the scroll was happening before or after that. I maintained that breakpoint for the rest of my debugging effort.
The weird thing was that generally, the page would not scroll before it hit that breakpoint, but sometimes it did. I thought that was odd, and although I didn't know what to make of it, it had me on the lookout for something unusual.
I tried searching all the JavaScript for "scroll" and "update" (text) to look for more breakpoints to set, and set a bunch at JavaScript that did scrolling, but nothing hit.
I noticed that there was a lot of JavaScript dynamically updating the page, and thought that maybe the scroll was due to an update of some sort.
I tried putting a jQuery event listener that logged all events on document (since the JS was using custom events not logged by monitorEvents, and I had already determined that document was the target of the scroll event) to emit all the events and see if it was some custom update event. There were a bunch of custom events, and I later generated the events in the console to see if the page would scroll in response. Since I could not get the page to scroll that way, I concluded that events were likely a dead end.
I switched tactics. I looked at where the page was scrolling to, and saw it was scrolling the WooCommerce form into place. So, while stopped at the execution breakpoint (described above), I deleted the entire WooCommerce form from the DOM, and verified that the page no longer scrolled. This had me convinced that whatever the problem was, it was caused by WooCommerce.
Unfortunately, my Google Fu failed me, and I did not immediately find the problem through a Google search. Instead I found how WooCommerce scrolls the page on errors to make sure the error messages are visible. This led me back to the JavaScript.
Still, there was a lot of JavaScript, a lot of it dynamically creating the form (localizing it on the fly), and a bunch of German (which I don't speak), and I wasn't finding any JavaScript causing scrolling. I really wanted to narrow down which JS file was causing the scroll.
Chrome allows you to set a breakpoint on "script first statement" (under Event Listener Breakpoints -> Scripts), so I did that. In addition to stopping at the first line in every script file, it stops at the beginning of every <script> tag on the page. I found this script tag near the bottom of the page
<script type="text/javascript">
if(typeof jQuery == 'undefined' || typeof jQuery.fn.on == 'undefined') {
document.write('<script src="https://www.prored3.de/wp-includes/js/jquery/jquery.js"><\/script>');
document.write('<script src="https://www.prored3.de/wp-includes/js/jquery/jquery-migrate.min.js"><\/script>');
}
</script>
The weird thing about this script tag was that the scroll happened immediately after this script tag was processed, but jQuery was already loaded, so the script actually did nothing. I was also able to confirm via the console that both before and after this script tag (which is before and after the scroll), the DOM was not flagged as ready. This means that all the jQuery ready handlers had not run by the time the scroll happened. That eliminates a lot of JavaScript, and got me thinking about why the scroll happened after but not before this tag.
I guessed that internally, the browser saw the document.write calls and determined that the DOM was not complete until after it passed that tag, but as soon as it was past it, the DOM was complete and it could start processing page-level attributes. That, along with the earlier observations, led me to look at the WooCommerce form more closely and discover the autofocus attribute set on the billing_first_name field.
Oddly enough, I was not able to prevent the scrolling by deleting the autofocus attribute. I don't know why, but I'm guessing it has to do with browser internals and the fact that the DOM was not ready. I was, however, able to prevent the scrolling by hiding the the billing_first_name in put element via CSS, which convinced me it was the cause of the scroll.
Adding "autofocus" to my Google search led me to other complaints of similar behavior with WooCommerce, and combining posts led me to the PHP solution I posted.
Updated
As I don't have OP's page for testing, the following method of finding registered event listener actually DO NOT solve the issue OP is addressing.
However, this is the general method when I want to find a specific event, just reserved for someone's reference.
If I understand your meaning correctly, you want a method to tell you where do the specific events occur. Please tell me if this is not doing what you want.
You can try to add a breakpoint on chrome debugger.
F12 -> Sources -> Event Listener Breakpoints (in list with those Breakpoints, Scope, etc) -> Control -> Click the box of scroll.
For Sure it may captures some other scroll event you are not interested, but you can go through it next by next until you find the one you want.
Besides, there may be also event not related to scroll, you may also need to try focus or DOM Mutation -> DOMFocusIn.
programs! I've found solutions to similar problems such as mine here on the site but what's happening to me is rather unusual and I don't think they apply.
On this page: http://tdg.gswitchhost.com/calendar/
I'm locked into using this plugin which I really don't care for. This is a Wordpress site but the plugin, which lists upcoming events, doesn't behave like Wordpress. It has this system in place which is entirely unique to it. Posts live outside of the posts database table and you have to query these in an entirely different way. It's a bummer. So my problem:
We have some jquery working its magic on the events list to add an accordion effect and this works. However. When you click on the pagination links to load the next set of events, the plugin, instead of linking to page 2 of events, it runs an asynchronous query and loads the next set of events on to the existing page without a page reload. If you click on one of the new events, the accordion no longer works.
What I think is happening is that on click, the plugin removes the entire UL which contains the events and loads a second entirely new one, containing the second record set, with the same class name but since the javascript initialized on the first UL, the one the plugin removed, the new set hasn't been affected since the page didn't reload and run the javascript again.
I've tried using .on() and the Livequery plugin to rerun the javascript when you click the pagination links but there's a delay as the query is running and loading the new UL so I believe that the javascript runs again when you click on the link but because the UL hasn't been loaded already when you click, there's nothing for the jquery to work on.
Sorry this is so long but I just want to be as clear as possible. Am I wrong? This is killing me, I'm running out of time and I really need to get this to work so that no matter which set of events has been loaded on the page, the accordion function works on it.
Here's the javascript that initializes the accordion:
$('.eventListingNew').accordion({
headerClassName: 'accordionHeader',
headerActiveClassName: 'accordionHeader-active',
contentClassName: 'accordionContent',
collapseAll: false,
speed: 250
});
And here's a pastebin of the entire accordion function since it's so long. http://pastebin.com/BvDseg3g
Easy thing is just call it when the Ajax complete is done running to reinitialize it.
$(document).ajaxComplete(function(event, xhr, settings) {
$('.eventListingNew').accordion({
headerClassName: 'accordionHeader',
headerActiveClassName: 'accordionHeader-active',
contentClassName: 'accordionContent',
collapseAll: false,
speed: 250
});
});
I'm working on a web app in ASP.NET 2.0 that involves several GridView elements. When users click one of the rows in a grid, that row needs to show its selection by changing color. Each row has attributes set to identify its record type and unique ID:
<tr data-elementType='myType' data-myID='12' onclick='selectionFunction();'></tr>
I accomplish the selection through a javascript onclick handler on each row that calls a function that:
Removes the selected class from the previously selected row
Adds the selected class to the new selected row
Updates the value of a hidden field with the new selected unique ID so server-side code can know which element to perform an action on when a button is clicked (view, delete, etc).
One of these grids now has just over 700 records in it. In Firefox 3.6, the selection operation on this grid is horribly slow (about two seconds); in other browsers (even IE 7 and 8) it's not a problem. I put console.log statements at the start and end of the selection function, and in Firebug they show up very fast at the end of the delay, suggesting that it's not the selection function that is slowing things down. I used the profiler in Firebug and it says that "createCallback", which is defined in one of the "ScriptResource" script files generated by ASP.NET, is taking the huge majority of the time. What is createCallback and why does it seem to be so slow in Firefox 3.6? Is it a bug in FF, or is it a problem I can solve?
UPDATE: I am, of course, using jQuery to add/remove classes from the rows. I've been working with jQuery 1.5.2 and jQueryUI 1.8.11, but I updated to the latest (1.6.2 and 1.8.14 currently) to no avail. I tried putting a breakpoint in createCallback to see where it's getting called, and when it breaks there it's several frames down in the call stack from my call to removeClass. Here is what the stack looks like in Firebug:
createCallback() - in ScriptResource.axd?......
wherever possible trim: trim ? function(text=" ") - in jQuery
removeClass(value="selectedRow") - in jQuery
removeClass(classNames="selectedRow", speed=undefined, easing=undefined, callback=undefined) - in jQueryUI
selectionFunction() - in my .aspx page
onclick
I don't understand why jQuery is triggering an ASP.NET generated function like this.
UPDATE 2: some more investigation has provided some more detail. It seems that this "createCallback" function is getting called A LOT when I use addClass/removeClass, and it's happening in both Firefox 3.6 and Firefox 5. I found the same function in Chrome and put a breakpoint on it, and it's not getting called at all, so this seems to be a Firefox thing. I put a breakpoint on the function/line in question and selected a row, and the breakpoint got it 57 times. Only the first two involved me calling removeClass and addClass; the rest had createCallback several times in the callstack, and sometimes BeginRequestEventArgs too. I've noticed it getting called also when I mouseover other jQueryUI stuff on the page (tabs), when jQuery uses addClass and removeClass. But why is it getting called so many times when I do work on tr elements?
I'm changing the title and tags to reflect the real issue.
UPDATE 3: createCallback is getting called about the same number of times whenever I select a row in any of the grids, even if it only has 6 rows in it. But in that case it's not a performance problem, and the profiler shows it only taking about 30% of the execution time, while it's at least 80% when I profile selection on the larger table. So createCallback seems to perform worse when it's used in the context of more stuff visible on the page. But it still seems like jQuery shouldn't cause a call to createCallback, especially since I couldn't fine any references at all to it in Firebug's script search. And it appears to only get called in Firefox!
Note also that all of these grids are on the same page, but only one is visible at once, because I'm using jQueryUI tabs.
UPDATE 4: I managed to get something similar up on jsFiddle as requested. See here. In Firebug, find createCallback and set a breakpoint (just below my click handler in the script, where it begins with Function.__typeName = "Function"; Function.__class = true; Function.createCallback = function (b, a) and reload the page. I get a lot of calls to it.
I have very little knowledge of ASP however it sounds like your problem is purely client side.
Declaring on "onclick" event for each row is not the most sensible way to handle the rows being clicked. Especially when you get into the quantity of rows you're talking about (~700+).
A better way would be to add a click event handler to the table and figure out what is clicked when it happens. I have written an application where a similar size table is being handled and we're not seeing anything like the lag you're experiencing upon click. there may well be other factors causing your click events to slow down however I would still suggest something along the following lines is worth implementing in any case:
$(function(){
var rowSelectedClass = 'rowSelectedClass';
$('#myTableID').click(function(e){
if(e.target.nodeName === 'TD'){
var $tr = $(e.target).parent();
$('tr.' + rowSelectedClass).removeClass(rowSelectedClass);
$tr.addClass(rowSelectedClass);
// ....
// Do whatever else you want to do when the row is clicked
// ....
}
});
}
A good article to take a look at which advocates this method (and a few other handy jQuery tips) can be found here: http://www.artzstudio.com/2009/04/jquery-performance-rules/#leverage-event-delegation
Also worth noting that if your table has rows added dynamically after the page is loaded then consider using .live() instead of .click().
UPDATE # July 28th 2011 9AM
Having taken a look at the source more closely, I think the supposed calls to "createCallback" are a red herring. The line within your original jsFiddle source which contains the "createCallback" function is actually a really long string (~90,000 characters) of javascript. I think the fact that "createCallback" is the first function within that string is misleading Firebug's profiler. When you profile your original page's load, there are 2261 calls and as you said, there appear to be lots to "createCallback"
I've "beautified" (hate that phrase) this long JS string via http://jsbeautifier.org/ to make it readable and re-added it to a jsFiddle page. You can see it here: http://fiddle.jshell.net/KvpmE/1/show/. Now when you profile this page's load you'll see a similar number of calls (2267 - not sure what happened to the other 6!) but importantly not a single one to "createCallback".
I still can't offer any solution though because essentially I've been unable to re-create your original issue which was that there was a 2 second lag in Firefox 3.6 when clicking a row.
Is this still the problem you're having?
Could you try and see whether you can re-create the problem within the updated jsFiddle page?
Also try and add the de-minified JS to your page to see if it helps you track down the actual functions being called when the row is clicked and therefore where the lag is taking place.
Mr. Jefferson,
It really sounds to me like you're actually performing a postback without knowing it. Have you set a breakpoint on the server side yet to see if something is inadvertently firing your update panel? It really sounds like some kind of postback is happening that is requiring a reload of dependant scripts.
I say this because 1) the problem you're having makes absolutely no sense - you're 100% on the money with JQuery and the ASP.NET Client Framework not even knowing they're neighbors in this case, and 2) the BeginRequestEventArgs instantiation sounds like the PageRequestManager thinks it should be doing something in response to your triggers... You could also try breaking out Fiddler and just doing a quick sanity check to make sure some update panel of yours isn't firing. There should be no HTTP traffic during the ops you're describing.
Sorry if this is an absolutely useless post for you, but with all of the work you've gone through to troubleshoot the client side it can't hurt to set a server side breakpoint just to do a quick sanity check / occam's razor...
Good luck - happy coding.
B
Function.createCallback is used a lot internally by Ajax Toolkit and maybe its being called within your code unintentionally too http://msdn.microsoft.com/en-us/library/dd409287.aspx.
Since this is browser dependent, I would check code paths that are executed based on a specific browser.
Another clue to look for is if you're having any Ajaxtoolkit components for the grid or its individual rows as that would explain the increase in number of calls with the increase in rows.
There is also Type.createCallback function (http://msdn.microsoft.com/en-us/library/bb397568.aspx) so if you have any Type related code or methods, I would check those.
I'm having trouble recreating the issue in jsbin without giving away project-specific details (I'm using JSON from an API), but I'm running into an issue that I can't seem to get around, and would really appreciate any help or insight.
I start with the following markup:
I have a blank unordered list.
<ul id="results-list">
<!-- it is blank for now, and will be populated via jQuery -->
</ul>
And also an input.
When that input has been submitted, I run some code to populate #results-list with data, based on a JSON response. All's well. In that population of the data, I embed links that go nowhere, to make it like a sidebar navigation (user clicks on a link, and the main content area's content changes accordingly). This works fine the first time around.
Then, I've got an anonymous function running inside of .live() for clicking on those links in #results-list.
$("#results-list a").live('click', function(){
// populate the main content area with the correct information.
});
Okay, so that works just perfectly the first time around. Once the user changes what's in the input, and resubmits the form, all of the items in the main content area change accordingly, but there are two of them. If they resubmit the form again, there are three. And so on.
So, the main content stuff is duplicated X times, with X being the number of times the form has been submitted.
I realize this is a somewhat vague question, but I wanted to see if anyone had any pointers as to what may be going on? This is all happening within a normal $.getJSON method call.
Any ideas?
If you call the live function after each post, jQuery will just keep adding event handlers to the DOM, so the handler will get called multiple times. To get round this, either just call the live function once, or if you have to set up event handlers after each post use unbind and then a bind function (i.e. bind or something more specific like click).
Go here: http://www.infinite-scroll.com/
Play with the infinite scroll. Notice that you can't click a link and then hit "back". It has glitches when you do that.
So, I plan on writing my own Infinite scroll.
When the user gets to the bottom, load an AJAX call. Then do a JQuery "append" the result to the div. Then, call my other functions on those elements. (I set the background images of all those elements in javascript).
Will this work? If I do that...will I be able to handle the back button?
I considered the very same thing on a project I worked on. One option I thought about was to allow the back button to return to the place where the link was clicked (just like normal browsing).
Firstly, you need to record what page of the infinite scrolling your on so that you can load up to that section again. You can do this with some clever playing around with the window.location.hash value. If you look at my answer to this question, I explain in more detail how to do it in plain JavaScript or jQuery using Asual's address plugin.
The basic part of it would like like this:
// Whatever you're using to load the next page
function scrollToNextPage(page){
// Your infinite scrolling stuff
$.address.parameter("currentPage", page);
}
$.address.externalChange(function(){
var page = $.address.parameter("currentPage"),
top = $.address.parameter("linkTop");
loadAjaxUpTo(page);
$('html, body').animate({ scrollTop: top }, 500);
});
// Set a parameter for the location of a clicked link
$("a").live('click', function(){
$.address.parameter("linkTop", $(this).scrollTop());
});
I didn't implement the last bit (getting the position of the link clicked) but I can't see why it wouldn't work. It would cause the window to scroll nicely to where you where. You can always set it with an anchor to the loaded page instead (but when you scroll to it, it will always go to the top of the page).
A couple of points though, I wouldn't recommend this. At least for the project I was doing, it wasn't really necessary. In my project, we expected the user to go back to change their options and figured that scrolling wouldn't be a problem (although we didn't have that many pages to scroll through). The AJAX (and your JavaScript to set the images) needs to be loaded and executed again which takes a lot of time depending on how many pages you need to reload. On top of the time to scroll to the link (you could just window.scrollTo but you don't get animation so everything is very jerky. You could always just load the page the person was on and forget about the previous pages, but you're still breaking the user experience that way. Or (what I tried) was to implement a two way infinite scroll. So it would load the page the user clicked from and prepend the previous pages if they scrolled up - this was too much work for what it was though.
Another point is that, if you were to still do it, you want to use a GET request to get your pages (and make sure the cache isn't set to expire immediately). I found that pages requested by Ajax with the GET request would take from the cache (at least on some of the browsers I tried). Sending your details over a POST will always ignore the cache.
The only way to be able to handle the back button is to alter the location hash (the bit after the # symbol). Handling pressing of the back and forward buttons can be done in two ways:
Have an <a name="bookmark1"></a> which is unique to each section added, and change the location.hash to match it.
Use a setInterval with a short time like 100ms to watch the location.hash for changes and go to the required part of the page. You have to do this because you can't actually detect when the back/forward buttons are clicked.
This is an implementation of the second method to show you how it works. In this, each ajax request contains <a name="ajax-section-1"></a> and ajax-section-2 etc.
function addToBottom(htmlToAdd) {
$('#main-div').append(htmlToAdd);
window.location.hash = $('#main-div a[name^=ajax-section-]').last().attr('name');
}