Messed up with .bind() and .unbind() in jQuery - ajax

Ok, so i have two ways to perform div refresh
$('#player').load('/videos/index');
in my rails app. One is through link
next
other is through shortcut of that button. And they work fine, until i discovered, that if I refresh player twice in a row through the link, and then through the shortcut, it loads div twicely. If i refresh through the link three times in a row, than through the shortcut, than it's loading div three times. And so on..
So, i've started to trying configure binds (as I assumed, that was the reason), but there were mo result.
Here is my messed up in binds shortcut part of application.js
$(document).ready(function(){;
$(document).bind('keydown', 'space', function() {
$('#player').unbind('load');
$('#player').load('/videos/index');
$(document).unbind();
});
});
I tried to click on link through the shortcut, but the same result, so I've assume, the problem is in load. Any suggestions would help.

The best way to avoid a double refresh, is having an state flag, indicating if it can load again, or if it's loading:
$(document).ready(function() {
var loading = false;
function reloadDiv() {
if(!loading) {
loading = true;
$('#player').load('/videos/index', null, function() { loading = false; });
}
}
$('#nextb').click(reloadDiv);
$(document).bind('keydown', 'space', reloadDiv);
});
Good luck!

Related

logout and click back takes me to authenticated pages in Safari browser [duplicate]

Got an issue with safari loading old youtube videos when back button is clicked. I have tried adding onunload="" (mentioned here Preventing cache on back-button in Safari 5) to the body tag but it doesn't work in this case.
Is there any way to prevent safari loading from cache on a certain page?
Your problem is caused by back-forward cache. It is supposed to save complete state of page when user navigates away. When user navigates back with back button page can be loaded from cache very quickly. This is different from normal cache which only caches HTML code.
When page is loaded for bfcache onload event wont be triggered. Instead you can check the persisted property of the onpageshow event. It is set to false on initial page load. When page is loaded from bfcache it is set to true.
Kludgish solution is to force a reload when page is loaded from bfcache.
window.onpageshow = function(event) {
if (event.persisted) {
window.location.reload()
}
};
If you are using jQuery then do:
$(window).bind("pageshow", function(event) {
if (event.originalEvent.persisted) {
window.location.reload()
}
});
All of those answer are a bit of the hack. In modern browsers (safari) only on onpageshow solution work,
window.onpageshow = function (event) {
if (event.persisted) {
window.location.reload();
}
};
but on slow devices sometimes you will see for a split second previous cached view before it will be reloaded. Proper way to deal with this problem is to set properly Cache-Control on the server response to one bellow
'Cache-Control', 'no-cache, max-age=0, must-revalidate, no-store'
Yes the Safari browser does not handle back/foreward button cache the same like Firefox and Chrome does. Specially iframes like vimeo or youtube videos are cached hardly although there is a new iframe.src.
I found three ways to handle this. Choose the best for your case.
Solutions tested on Firefox 53 and Safari 10.1
1. Detect if user is using the back/foreward button, then reload whole page or reload only the cached iframes by replacing the src
if (!!window.performance && window.performance.navigation.type === 2) {
// value 2 means "The page was accessed by navigating into the history"
console.log('Reloading');
//window.location.reload(); // reload whole page
$('iframe').attr('src', function (i, val) { return val; }); // reload only iframes
}
2. reload whole page if page is cached
window.onpageshow = function (event) {
if (event.persisted) {
window.location.reload();
}
};
3. remove the page from history so users can't visit the page again by back/forward buttons
$(function () {
//replace() does not keep the originating page in the session history,
document.location.replace("/Exercises#nocache"); // clear the last entry in the history and redirect to new url
});
You can use an anchor, and watch the value of the document's location href;
Start off with http://acme.co/, append something to the location, like '#b';
So, now your URL is http://acme.co/#b, when a person hits the back button, it goes back to http://acme.co, and the interval check function sees the lack of the hash tag we set, clears the interval, and loads the referring URL with a time-stamp appended to it.
There are some side-effects, but I'll leave you to figure those out ;)
<script>
document.location.hash = "#b";
var referrer = document.referrer;
// setup an interval to watch for the removal of the hash tag
var hashcheck = setInterval(function(){
if(document.location.hash!="#b") {
// clear the interval
clearInterval(hashCheck);
var ticks = new Date().getTime();
// load the referring page with a timestamp at the end to avoid caching
document.location.href.replace(referrer+'?'+ticks);
}
},100);
</script>
This is untested but it should work with minimal tweaking.
The behavior is related to Safari's Back/Forward cache. You can learn about it on the relevant Apple documentation: http://web.archive.org/web/20070612072521/http://developer.apple.com/internet/safari/faq.html#anchor5
Apple's own fix suggestion is to add an empty iframe on your page:
<iframe style="height:0px;width:0px;visibility:hidden" src="about:blank">
this frame prevents back forward cache
</iframe>
(The previous accepted answer seems valid too, just wanted to chip in documentation and another potential fix)
I had the same issue with using 3 different anchor links to the next page. When coming back from the next page and choosing a different anchor the link did not change.
so I had
House 1
View House 2
View House 3
Changed to
House 1
View House 2
View House 3
Also used for safety:
// Javascript
window.onpageshow = function(event) {
if (event.persisted) {
window.location.reload()
}
};
// JQuery
$(window).bind("pageshow", function(event) {
if (event.originalEvent.persisted) {
window.location.reload()
}
});
None of the solutions found online to unload, reload and reload(true) singularily didn't work. Hope this helps someone with the same situation.
First of all insert field in your code:
<input id="reloadValue" type="hidden" name="reloadValue" value="" />
then run jQuery:
jQuery(document).ready(function()
{
var d = new Date();
d = d.getTime();
if (jQuery('#reloadValue').val().length == 0)
{
jQuery('#reloadValue').val(d);
jQuery('body').show();
}
else
{
jQuery('#reloadValue').val('');
location.reload();
}
});
There are many ways to disable the bfcache. The easiest one is to set an 'unload' handler. I think it was a huge mistake to make 'unload' and 'beforeunload' handlers disable the bfcache, but that's what they did (if you want to have one of those handlers and still make the bfcache work, you can remove the beforeunload handler inside the beforeunload handler).
window.addEventListener('unload', function() {})
Read more here:
https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/1.5/Using_Firefox_1.5_caching

CasperJS form fill sometimes stays on the current page

I have a simple casperjs test to submit a search form on my homepage. Then I assert that the title on the landing page is correct.
Works fine on my computer (OSX 10.9.2) but on my colleague's laptops (a Win 7 and Win 8), the test fails randomly because casper "thinks" it is still on the search page.
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, { query: goodQuery }, true);
});
casper.then(function() {
// sometimes fails, says it's "My Project" main title
test.assertTitle('Search Result', 'Search result title is ok');
});
}
Introducing a casper.waitFor(3000) before checking the page title does not change the outcome. I've also tried to replace the then step by a waitForUrl, but it fails after 5 secs, saying it is still on the current page.
Plenty of other tests work fine on all computers but it's the only one with form submition.
Any hints on how to solve or properly work around this? I'd rather not simulate a click on the submit button (more coupling to the form internals) if possible (but it would be okay I guess).
Thanks
$ casperjs --version
1.1.0-beta3
$ phantomjs --version
1.9.7
EDIT: submitting the form and waitForUrldid not help. I found out that the test actually runs fine on its own, even on the Windows 7 machine. But when I run two tests:
01 search.js (the one described above)
02 menu.js (a simple one, merely containing assertExists)
'search.js' fails most of the time... and sometimes 'menu.js' fails instead! I suspect some mishandled concurrent access, although it consistently works on OSX. I must be doing something wrong. Both tests have the same structure:
casper.test.begin('Some test', function(test) {
casper.start(someUrl, function() {
// some test
});
casper.run(function() {
test.done();
});
});
Any clue?
Try :
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, {
query: goodQuery
},false);
this.click("your selector for submit button");
});
casper.then(function() {//you should use waitForUrl/Selector/Text() instead
// sometimes fails, says it's "My Project" main title
test.assertTitle('Search Result', 'Search result title is ok');
});
casper.run(function() {
this.test.comment('------ Tests over ----\n');
test.done();
});
});
It's better to submit the form by clicking. Sometimes (often) it doesn't pass putting the fill arg at true. Just put the correct selector for the submit button.
You should wait for an item to appear on the following page. I would change your code to the following:
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, { query: goodQuery }, true);
});
casper.waitForSelector('#someSelectorOnNextPage', function() {
test.assertTitle('Search Result', 'Search result title is ok');
});
}
I also experience same issue. Suprisingly adding empty then() handler fixes that in v1.1.0-beta3. I don't think this is expected behavior though:
casper.test.begin('Search', function(test) {
casper.start("http://localhost:8080/site", function() {
this.fill(searchForm, { query: goodQuery }, true);
});
// Do nothing here, just call it as a placeholder
// Here http://localhost:8080/site sends us to the next endpoint
casper.then(function() {});
// Now this is the final page we actually want to assert
casper.then(function() {
test.assertTitle('Search Result', 'Search result title is ok');
});
}
EDIT:
Although question author says casper.waitForUrl() didn't work for them, it did work for me as an alternative solution.
What does look strange is that in verbose mode whatever returns a 301 status code along with Location Header is recognized as HTTP 200 response by Casper.
EDIT 2:
Well obviously it doesn't happen every time, but what I noticed is that Casper sometimes doubles the previous response (that's why I thought it recognizes some specific HTTP codes as 200 mistakenly and that's why author's code functioned as if it stayed on same page after form submission) and sometimes not.
waitForUrl() fixes that obviously but there is still some underneath issue in Casper which scares me a bit and I hope I will find some time to report it with all the dumps to Casper issue tracker.

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
}

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.

Ajaxed div hide and show hides only after div load

I have this issue. I'm working on a jquery ajaxed site. I have the main content div in the middle and on top the navigation. I need to AJAX the content, because I have flash backgound so that the flash video won't start from beginning after every page load. The only way I was able to do this was with this sort of code:
$(document).ready(function(){
$.ajaxSetup ({
cache: false
});
//For loading
var ajax_load = "<img src='img/load.gif' alt='loading...' /><p>";
// Var
var loadPage1 = "page1.html";
// Load page
$("#page1").click(function(){
$("#content").hide(2000);
$("#content").html(ajax_load).load(loadPage1);
$("#content").show(2000);
});
All other ways to get the div didn't work because there was issues on getting plugins etc. working in the ajaxed div (content).
So... everythig is working fine - but, the div loads it's content from page1.html and shows it and only after this does it hide it and show it. So it loads the page and then does the effects I want to.
Do I need to queue this some how or what's the proper jquery way? I tried delay, stop etc.. but can't seem to solve this out. It's propably very simple.
Thanks.
Show the element in the load callback handler.
i.e:
$("#page1").click(function(){
$("#content").hide();
$("#content").html(ajax_load).load(loadPage1, function(){
$("#content").show(2000)
});
});
.load() takes 2 arguments, the URI and a callback to fire after load.
API is found here: http://api.jquery.com/load/
function() {
$("#content").hide(2000);
$("#content").html(ajax_load).load(loadPage1, function() {
$("#content").show(2000);
});
}

Resources