ajax links retaining links from previous click - javascript

i have this previous question here but i'm not sure if i should reply there or make a new one so i decided to make a new one instead since it's quite a different (or a sequel) kind of issue.
the code in question is here: http://jsfiddle.net/sab60pzd/2/
jquery:
$('.load-me').click(function(e){
e.preventDefault();
var url = $(this).attr('href');
var txt = $(this).text();
$('.main-container').fadeOut(200, function(){
$(this).load(url, function() {
// for demo:
$(this).html('Loaded some awesome content from ' + txt).slideDown(200);
});
});
});
basically, this code works great & the way it should. except for one thing, i only found this out when i uploaded it on the server. the links overlap each other if another link were to be clicked while the page is loading.
a good example would be let's say i clicked link 1, while it's loading i clicked on link 2 & then link 3. what happens is that sometimes it will load up link 2 instead of 3. then when i click on, say link 1. or even link 4 perhaps, the page that would appear is from link 3. there's sort of a queue that makes them line up & get messed up if someone is not patient enough to wait on a page to load.
what i'm looking for is perhaps a way to abort the previous click event & start with the new one if it's activated while a page is loading. i've tried the queue() & dequeue() ones but i just couldn't grasp what it does so i still haven't had any success so far.
any help will be really awesome.

The problem you are having is that whatever link is the "last to load" is displayed, they do not always load in the same order as they were clicked because not all links may be of the same file size (some take longer to load than others). So you need a way to keep track of which link was pressed last. Id suggest a simple global variable that records the last request.
var lastURL;
$(".load-me").on("click", function(){
var url = $(this).attr("href");
lastURL = url;
(function(){
var thisURL = url;
$.get(url, function(x){
if(thisURL==lastURL)
$(".main-container").html(x);
});
}()); // Anon function for scoping thisURL;
})
This should load the last one pressed reguarless of the order they loaded, another issue I see is you may potentially be loading the same content over and over again, you should save the content in an array and check to see if its already loaded and if it is use the already loaded content instead of reloading the content again.
var lastURL;
var contents = [];
$(".load-me").on("click", function(){
var url = $(this).attr("href");
lastURL = url;
(function(){
var thisURL = url;
for(var i=0;i<content.length;i++){
if(content[i].url == thisURL){
$(".main-container").html(content[i].content);
return; // kills the anon function
}
}
$.get(url, function(x){
contents.push({
url: thisURL,
content: x
});
if(thisURL==lastURL)
$(".main-container").html(x);
});
}()); // Anon function for scoping thisURL;
})
This will make the content load faster the 2nd, 3rd, 4th... time that the same page is loaded because its not doing another get request.

Related

How to invoke javascript function when # is present in URL

I am trying to call JavaScript function when # is present in URL. I know normal behavior is to navigate / scroll to the specific tag. But could not find how to invoke a JavaScript function.
The below example is close but not solving my problem.
What is the meaning of # in URL and how can I use that?
You might be able to leverage the hashchange event to trigger the function, assuming you don't just want to keep polling the location to see if it changes.
DOCS: https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event
This code snippet will add the listener to the current page, then manipulate the hash and fire the function, displaying the new hash value. You could call any function here.
window.addEventListener('hashchange', function() {
alert(location.hash);
});
window.location += "#test";
var hash = window.location.hash;
if(hash){
// do something
}
<script>
if (window.location.href.includes('#')) {
// run your code here
}
</script>
use a location.hash function will solve your problem
var hash = window.location.hash.replace(/#/g, '');
if(hash){
// found a hash
console.log("heyy I found a hash")'
}
else{
// did not find a hash
console.log("Uh oh")
/*
try using :
window.location = window.location + '#' + "some random variable"
to create a new URL and every time the page loads find the hash and
display the wanted data.
*/
}
PS: this only works if your URL is like example.com/#xyz
then it will give you xyz as a console output. This may sound
vague but if you do this you may get a Idea

Differentiate between button click and javascript page reload

I'm trying to differentiate between page click and auto reload. Auto reload is done through javascript below.
var pageReload = {
Initialize: function () {
window.setTimeout("location.reload(true);", 60000);
}
pageReload.Initialize();
I'm trying to set a hidden variable in the above code for which I'm trying to check the changed value in Page_PreRender to understand the difference between page click and auto reload.
var hdnReloadType = document.getElementById('<%=hdnReloadType.ClientID%>');
hdnReloadType.value = "1";
The javascript is loaded after PreRender and I'm sure how to proceed.
Any thoughts?
Thank you for all the replies.
Because I'm using asp.net, I was able to capture the previous page click url from Request object and from there I'm determining if this was a page auto reload or button click. The query string reload option is great too but we didn't want to expose that to the user. This solution worked for my case.
Instead of just doing a reload(), you could add a "reloaded" parameter to the URL. If we use something like the replaceUrlParam() function from this answer, we can say:
var pageReload = {
Initialize: function () {
window.setTimeout(
function() {
var url = replaceUrlParam(window.location.href, 'reloaded', '1');
window.location.href = url;
},
60000
);
}
}
pageReload.Initialize();
Now, when the page has been auto-reloaded (and only then), the query string will contain "reloaded=1".
You could always use localStorage to leave a breadcrumb behind when your function reloads the page:
localStorage.setItem( 'page-reloaded', 'true' );
When the page loads, check for the breadcrumb:
var reloaded = localStorage.getItem('page-reloaded') || false;
And then cleanup afterwards:
localStorage.removeItem('page-reloaded');

Potential errors in asynchronous loading of images in photo viewer (Javascript and jQuery)

I'm going through a book called "Javascript & jQuery" by Jon Duckett. In it, there's an example of a photo viewer that can be found here:
http://javascriptbook.com/code/c11/photo-viewer.html
In the book, he states that
because larger images take longer to load, if a user clicks on a two different images in quick succession: 1) The second image could load faster than the first one and be displayed in the browser. 2) It would be replaced by the first image the user clicked on when that image had loaded. This could make users think the wrong image has loaded.
I get this concept, however, the code he cites does not seem to fix the problem, at least not in my eyes. Here is an abbreviated version of the full script, which can be found here: http://javascriptbook.com/code/c11/js/photo-viewer.js (his version is much better commented)
var request;
var $current;
var cache = {};
var $frame = $('#photo-viewer');
var $thumbs = $('.thumb');
// Other code goes here...
$(document).on('click', '.thumb', function(e){ // User clicks on thumbnail
var $img;
var src = this.href;
request = src;
// Other code goes here...
$img = $('<img/>');
cache[src] = {
$img: $img,
isLoading: true
};
$img.on('load', function() { // Code to run when image loads
$img.hide();
$frame.removeClass('is-loading').append($img);
cache[src].isLoading = false;
if (request === src) { // Check to make sure the image that is loading is the most recently requested image
crossfade($img); // Call function to load new image
}
});
$img.attr({
'src': src,
'alt': this.title || ''
});
So basically his solution is to create a global "request" variable and a local "src" variable. When a user clicks on a thumbnail, the request variable is assigned the value of src, which is the path to the image being requested. Later on, when the image loads, that request variable is checked to ensure that it equals src.
The logic behind the line that performs the check seems faulty to me. However, I'm new to programming and I'm not sure if there's a concept I'm not fully understanding. The line in question is this one:
if (request === src) {
Since the request variable was assigned the value of the src variable earlier in the script, they would still be the same, even when an old image loads after the new one has been clicked. The only difference is that value of each would be different.
Wouldn't the following be the right way to check this?
if (request === this.src) {
That way if the old image loads after the most recently requested image, the request variable would have stored the most recent path, and the old image's src attribute would no longer match it.
This might be pretty confusing, since I didn't include the whole script, so let me know if you need any elaboration. I tried to only include the absolutely critical aspects of the code so that you wouldn't have to go through all of it to understand my question.
Thank you for any help!
The code in the book is correct. The trick here is to have a variable across all instances of the callback that contains the most recently clicked href.
|---1----------...loading...------------cb------------|
|---2--...loading...--cb------------------------------|
|---3-----...loading...-----------cb------------------|
If this were the timeline of three clicks...we click a large image first (longer loading time before callback (cb)) and then we click a second, smaller image, finally followed by a medium image. We would have three click events all firing at the same time. The first callback we'd get is the 2nd click, followed by the third click, followed by the first click. However, since our request variable is outside the scope of our callback, it's value will be equal to the last thing it was set to, in this case, the href of click three.
I think all this logic makes sense to you but it's the timing you're not understanding. When click one happens, we set the external variable request to href1, when click two happens, we set it to href2 and then finally click three sets it to href3. These things all happened prior to the .on('load') callback which means, when image two loads first and we check the value of request, it's already been set to href3 which is !== src (href2), once image 3 loads next in the timeline, we see that this is the image we expect so we load it. Some few odd seconds/minutes later when image one calls it's callback, we see that request is not the href for image 1 and we don't show image one.
Either your code or the suggested code should work. The key you are missing is the scopes of the two variables.
var request;
$(document).on('click', '.thumb', function(e){ // User clicks on thumbnail
var $img;
var src = this.href; //variable exists only inside this onclick callback
request = src;
request exists outside of the enclosure so every time an image is clicked, its value gets overridden and stored.
src is declared inside of the onclick callback function and initialized with the link href. If another image is clicked while the first is loading, a new src variable is created to store the new data. As far as the onload callback is concerned, src doesn't change at that scope. src remains the value that it was first set at (the href of the link) and isn't overridden by following clicks.

Multiple Tracking onclick link of omniture's s.tl(), Cant figure out

I am using a omniture jasavscript for Site Catalyst.
In which, I am populating the required variables onclick of a link.
But the problem is I get a multiple (2) tracking on a single click, which is not the ideal behaviour. in these 2 tracking, The FIrst one I get is the old one and right after that I get the second latest tracking.
It seems like it is using the cache memory.
UPDATE
I tried reinitializing the object by using var s = {}; before and after the use of s.tl('this','e','',null);
But it didn't worked
Could someone suggest how it can be rectified.
Without seeing any code I can only speculate, but my guess is the additional hit is from SiteCatalyst's auto-link tracking - either an exit link because the target URL is not listed in linkInternalFilters, or a download link because the target URL ends with something listed in linkDownloadFileTypes.
I suspect, given the 'e' argument of your s.tl() example, that the link is an exit link. So on that note.. perhaps the solution here is to piggyback off the auto-exit-link tracking, instead of making your own s.tl() call. Adobe has a plugin called exitLinkHandler that will let you trigger additional variables whenever the auto-exit-link tracking occurs.
Here is the plugin:
/*
* Plugin: exitLinkHandler 0.5 - identify and report exit links
*/
s.exitLinkHandler=new Function("p",""
+"var s=this,h=s.p_gh(),n='linkInternalFilters',i,t;if(!h||(s.linkTyp"
+"e&&(h||s.linkName)))return '';i=h.indexOf('?');t=s[n];s[n]=p?p:t;h="
+"s.linkLeaveQueryString||i<0?h:h.substring(0,i);if(s.lt(h)=='e')s.li"
+"nkType='e';else h='';s[n]=t;return h;");
Within your s_doPlugins function, add the following:
s.url = s.exitLinkHandler();
if (s.url) {
// pop your variables here. Don't forget to pop `linkTrackVars` and `linkTrackEvents`, same as you would have done before
}
Now, this will make your additional variables pop on any exit link triggered. If you want it to only trigger on certain URL matches, or only on a specific match, you can do this several ways, depending on your needs:
If you only need to do a general substring match, you can pass some
or all of the target URL as the first argument for
s.exitLinkHandler() and it will match the passed argument against
the target URL.
If this isn't good enough, within the if(s.url) condition, you can
perform your own matching (e.g. regex matching) against the target
URL using s.url.
If you need to target by some DOM attribute of the link, within the
condition, s.eo is an object reference to the link that was
clicked, so you can write your own conditions around that.
Option 1
Omniture does not track links with # as exit links so you can do something like:
Search
<script>
(function (){
'use strict';
var links = document.querySelectorAll('.prepended-with-hash-for-tracking');
var track = function(e) {
e.preventDefault();
var link = e.currentTarget;
var url = link.href;
var trackingMessage = link.getAttribute('data-track-msg');
// Remove the hash.
if (url[0] === '#') {
url = url.substr(1);
}
// Track in omniture.
var s = s_gi('InsertYourRSID');
s.tl(link, 'o', trackingMessage, null, function(){
window.location.href = url;
});
};
for (var i = 0, len = links.length; i < len; i++) {
links[i].addEventListener('click', track, false);
}
})();
</script>
Option 2
Another work-a-round is to set s.linkLeaveQueryString = true; and then append the url with a query parameter containing your domain name which matches a string in s.linkInternalFilters. e.g. Share
Option 3
Disable omniture's default external link tracking by setting s.trackExternalLinks=false; and then you can handle all external links with an event handler that calls s.tl() with JavaScript similar to option 1.
I would recommend option 3.

How to run a javascript function using the # in the url?

hi this all started when i ran a function (lets call it loadround) that altered the innerHTML of an iframe. now once loadframe was loaded there were links in the iframe that once clicked would change the iframe page. the only problem is when i click the back button the loadround page was gone. i've thought about this numerous times to no avail. so i tried this code.
loadround
then
function loadround(a,b){
window.location.hash = "#loadround('"+a+"','"+b+"')";
var code = "<(h2)>"+a+"</(h2)><(h2)>"+b+"</(h2)>"
var iFrame = document.getElementById('iframe');
var iFrameBody;
iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0]
iFrameBody.innerHTML = code;
}
(the brackets in the h2 are intentional)
then i would try to reload the function by possibly an onload function but for now i was testing with a simple href as followed.
function check(){
var func = location.hash.replace(/#/, '')
void(func);
}
check
unfortunately the check code doesn't work and im almost certain there is an easier way of doing this. i tried changing the src of the iframe instead of the innerhtml and there was the same problem. thanks in advance
The modern browsers are starting to support the event window.onhashchange
In the meantime you can use the workaround proposed by Lekensteyn or maybe you can find something useful here: JavaScript/jQuery - onhashchange event workaround
You are misunderstanding the function void, which just make sure the return value is undefined. That prevents the browser from navigating away when you put it in a link. You can test that yourself by pasting the next addresses in your browser:
javascript:1 // note: return value 1, browser will print "1" on screen
javascript:void(1) // note: undefined return value, browser won't navigate away
It's strongly discouraged to execute the hash part as Javascript, as it's vulnerable to XSS without proper validating it. You should watch the hash part, and on modification, do something.
An example; watch every 50 milliseconds for modifications in the hash part, and insert in a element with ID targetElement an heading with the hash part. If the hash part is not valid, replace the current entry with home.
var oldHash = '';
function watchHash(){
// strip the first character (#) from location.hash
var newHash = location.hash.substr(1);
if (oldHash != newHash) {
// assume that the parameter are alphanumeric characters or digits
var validated = newHash.match(/^(\w+)$/);
// make sure the hash is valid
if (validated) {
// usually, you would do a HTTP request and use the parameter
var code = "<h1>" + validated[1] + "</h1>";
var element = document.getElementById("targetElement");
element.innerHTML = code;
} else {
// invalid hash, redirect to #home, without creating a new history entry
location.replace("#home");
}
// and set the new state
oldHash = newHash;
}
}
// periodically (every 50 ms) watch for modification in the hash part
setInterval(watchHash, 50);
HTML code:
Home
About Me
Contact
<div id="targetElement">
<!-- HTML will be inserted here -->
</div>

Categories