My question is about using Back and Next buttons (of the browser) on an AJAX (dynamical) webpage.
The solution I self came up with:
setInterval(function(){
if (location.hash != hash)
{
hash = location.hash;
app.url = window.location.href.toString().replace('http://xxxxx.nl/xxxx/#!/','')
app.handleURL();
}
}, 500);
this function reads the url(hash) and compares it with the last stored url(hash), every 0.5 second. If url has changed (back/next is pushed) it runs handleUrl() which runs more functions to dynamically build my page.
the problem is, this sort of works BUT when I click an html [A] element or when I change the url in an other way (javascript), that content will be loaded TWICE because of the setInterval()... functionality.
How can I build my HTML/Javascript in such way that my content will always be loaded once,
once when I push back/next
once when I click on an HTML element/use Javascript functions on
runtime
I searched the sh*t out of google for a solution, plz help!
You don't need a timer to check it. Just use the onhashchange event, and fire your AJAX calls when the event is called. This event isn't supported in IE versions below 8, though, so your method seems fine if you need IE support.
Also, it doesn't make sense that they're being called twice for a elements, since there's no reason for the interval to call your AJAX loader twice just because the hash was changed using an a element. You probably have an event listener attached to the a element which causes it to load the AJAX content, which wouldn't be needed since you're detecting any change in the hash, no matter how it was changed.
I suggest using a library for that. It will be tricky to make your own solution. Take a look at these:
http://www.asual.com/jquery/address/docs/#sample-usage
http://benalman.com/projects/jquery-bbq-plugin/
Related
This may seem like a simple question, but it doesn't seem to be answered anywhere that i can find.
I am writing an onClick event handler that simply calls dataLayer.push() when an anchor is clicked.
Is dataLayer.push() a synchronous operation?
Will the GET request to google definitely be sent, even though the browser has unloaded the page it was requested from due to the link being followed?
Some browsers show the connection get cancelled, some show it success.
My question is if the computer is slow, is it possible for the page to get unloaded before the request is sent?
This is why i assume that google started using the eventCallback property to redirect the user after the link has been followed.
e.g.
https://developers.google.com/tag-manager/enhanced-ecommerce#product-clicks
This source code does not include the click handler, but implies that the onClick event should stop propogation and let the eventCallback function set document.location.
However, as soon as you cancel the event, all its information has gone.
This (in my opinion) is just the wrong way to do it.
e.g.
(CTRL or COMMAND) + Click opens a new tab on browsers. This will not work unless the onClick event handler allows the prorogation to continue.
Relying on eventCallback also means that if the google scrips didn't load for one of the many reasons it could (but is still unlikely), your links don't work. And your site is broken.
So this leaves the correct way to do it for the onClick event handler to allow the event to propagate and return true.
Which also means that dataLayer.push() would need return after the GET request was sent for any of this to work properly.
Code example:
NOTE: You will get mixed results in mixed environments.
Link
$(document).on('click', 'a', function(event) {
// Is dataLayer.push() guaranteed to fire a GET ?
// data set externally
dataLayer.push(data);
return true;
});
Is there anyone out there that can guarantee that the GET request will get fired to the google server?
Have the google developers forgotten something here?
EDIT: Updated title to be more relevant to the question.
datalayer.push does not send anything to Google. It pushes objects with key/value pairs to the datalayer array. This might contain an event which in turn fires a tag. Whether the tag is sent depends on the setup of the tag, not on the dataLayer.push.
As a consequence, when you write your own click handlers your are yourself responsible to make sure your tags are actually fired.
If you use the built-in click handler you can configure a delay to make sure your tag has time to fire before the link redirects:
Since link clicks usually cause the browser to load a new page and
interrupt any pending HTTP request, you have the option to add a small
delay to allow tags fired by Tag Manager to execute properly before
redirecting to the next page. Checking the “Wait For Tags” option will
delay opening of links until all tags have fired or the specified
timeout has elapsed, whichever comes first.
You should be able to mix both methods (push data on the click, but still use the "native" link click handler for the event).
You can also try to specify "beacon" as the transport method in your Google Analytics tags, on browsers that support this (which I think is only Chrome at the moment) GA will then use the navigator.sendBeacon interface, which sends the data even in case the page unloads.
You might think that Google's solution is not very elegant (but the simple delay has the advantage that it works for all tags, not just for GA), but they have not "forgotten" the problem.
Also solutions that combine GA hit callbacks with timeouts that redirects if the callback fails as proposed i.e. by Simo Ahava somewhere should be be doable with GTM, even if they are probably more cumbersome to implement in GA.
I'm pushing values from website to Facebook through GTM, but I don't have access to make code changes on server side.
So every value that I need to send to Fb I have to find using Custom Javacripts in GTM.
I can get those values in console but I don't know why I can't see them in Debug mode. It's always undefined.
Here is one of the code in GTM:
function() {
var prod = document.getElementById("product_addtocart_form").elements.namedItem("product").value;
return prod;
}
So what am I doing wrong?
Assuming that line of code works in console, I suspect the code in your function is being fired too early and the elements aren't ready yet.
Make sure your code is not fired until the gtm.dom event is fired, if that still doesn't work then wait until gtm.load is fired. If that still doesn't work then have a look at when these elements are actually ready (maybe they're created using an AJAX call?).
If the gtm native events aren't late enough, when you know the elements are ready you should fire a custom event into your dataLayer which triggers your tags and repopulates the variables. Hopefully this will ensure your variables are populated correctly when your tags are fired.
If the elements are loaded using jQuery AJAX you should be able to bind to the ajaxComplete event on the document. See the jQuery docs. You would then fire a custom event into the data layer which would trigger the tags that using the data in the variables that should now be populated. You'd set up a trigger with type=custom event and the value being 'ajax_complete' (or whatever you call your event).
Your code would look something like this:
$(document).on('ajaxComplete', function(){
dataLayer.push({'event':'ajax_complete'});
});
If there's multiple AJAX events being fired on a single page then you'll have to write some logic to differentiate between calls and/or make sure you don't fire it multiple times. There's also a setting in tags in GTM to say 'only fire once per page load' so you could leverage that as well.
I am building a firefox extension that creates several hidden browser elements.
I would like to addProgressListener() to handle onLocationChange for the page that I load. However, my handler does not always get called.
More specifically, here's what I'm doing:
Create a browser element, without setting its src property
Attach it to another element
Add a progress listener listening for onLocationChange to the browser element
Call loadURIWithFlags() with the desired url and post data
I expect the handler to be called every time after 4, but sometimes it does not (it seems to get stuck on the same pages though).
Interestingly, if I wrap 3 and 4 inside a setTimeout(..., 5000); it works every time.
I've also tried shuffling some of the steps around, but it did not have any effect.
The bigger picture: I would like to be reliably notified when browser's contentDocument is that of the newly loaded page (after redirects). Is there a better way to do this?
Update: I've since opened a bug on mozilla's bug tracker with a minimal xulrunner app displaying this behavior, in case anybody wants to take a closer look: https://bugzilla.mozilla.org/show_bug.cgi?id=941414
In my experience developing with Firefox, I've found in some cases the initialization code for various elements acts as if it were asynchronous. In other words, when you're done executing
var newBrowser = window.document.createElement('browser');
newBrowser.setAttribute('flex', '1');
newBrowser.setAttribute('type', 'content');
cacheFrame.insertBefore(newBrowser, null);
, your browser may not actually be ready yet. When you add the delay, things have time to initialize, so they work fine. Additionally, when you do things like dynamically creating browser elements, you're likely doing something that very few have tried before. In other words, this sounds like a bug in Firefox, and probably one that will not get much attention.
You say you're using onLocationChange so that you can know when to add a load listener. I'm going to guess that you're adding the load listener to the contentDocument since you mentioned it. What you can do instead is add the load listener to the browser itself, much like you would with an iframe. If I replace
newBrowser.addProgressListener(listener);
with
newBrowser.addEventListener("load", function(e) {
console.log('got here! ' + e.target.contentDocument.location.href);
}, false);
then I receive notifications for each browser.
Given items on a webpage that get changed by AJAX calls over time, how can a userscript get notified about those changes, whenever they occur?
Imagine the Facebook newsfeed. It has 12 items in it when you load the page. Those items are wrapped in <li> tags contained within a <ul>. As you scroll the page down, new <li> chunks of data load into that <ul>.
I'm wondering how a userscript could be notified of such a change.
One idea is to constantly query that <ul>, counting its items, and watching to see if that number gets bigger. Possible, but to catch the change right when it happens it might have to run so often that it's too expensive.
Another idea would be to figure out what scroll position triggers the loading, and to watch for such a change. Less expensive, but very specific.
I'm wondering if there's a third option. Something that would notify me of the change, whenever it happens. I'm not just interested in the feed, but in this concept more generally. Given items on a page that get changed by AJAX calls, how can a userscript get notified about those changes?
Hijack the send method
var oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(){
// do what you need; then send the request
oldSend.apply(this, arguments);
}
I think what you are looking for is the DOMSubtreeModified event.
This works in firefox chrome and IE >= 9, if your scripting on facebook im guessing its for a greasemonkey/chrome extension? if that is the case this should be okay.
This event is fired on a node when ever a child node is added removed or changed
You can use it with
.addEventListener ("DOMSubtreeModified", handler, useCapture);
but I don't think it works with attachEvent.
Here's some more info on it.
http://help.dottoro.com/ljrmcldi.php
Do you have access to the Ajax calls that are updating the pages contents? Generally the better approach is to attach a call back to the actual Ajax call.
If the request are being made with Jquery use $.ajaxComplete() or $.ajaxSuccess() to trigger your code. These will fire any time a request completes so when this happens you can check if the content has changed without it being to expensive.
$.ajaxSuccess(function() { //check for update and do something });
Say I've loaded some arbitrary HTML page into my browser. Then into the address bar I append "#anchor-name" and hit enter.
Since I only added an anchor and didn't call a different page, the browser does not make another call to the server. So there is no onLoad event, etc.
Nonetheless, could some Javascript on the page detect this action? How? What's the event?
I think the answer is "no." Please prove me wrong.
Thanks
Note: Please assume there is no query string in the URL. It ends with "/index.html" or "/".
Related question: does it matter if an anchor named "anchor-name" actually exists on the page?
IE8 has an onhashchange event that is what you are looking for.
For the rest of the browsers, however, the "common" technique is to set a piece of code using setInterval that regularly checks the hash to see if it has changed since the last time it was called, and perform an action if it has. This article, however, offers a solution to onhashchange that doesn't rely on setInterval, however it looks to be way too clunky to reliably use. I would just stick to setInterval for all browsers:
var hash = window.location.hash;
setInterval(function() {
if(hash != window.location.hash) {
hashChanged();
hash = window.location.hash;
}
}, 2000); // 2 second timer, should be fine
It doesn't matter if there's no element with the hash provided.