IE browser caching and the jQuery Form Plugin - ajax

Like so many lost souls before me, I'm floundering in the snake pit that is Ajax form submission and IE browser caching.
I'm trying to write a simple script using the jQuery Form Plugin to Ajaxify Wordpress comments. It's working fine in Firefox, Chrome, Safari, et. al., but in IE, the response text is cached with the result that Ajax is pulling in the wrong comment.
jQuery(this).ajaxSubmit({
success:
function(data) {
var response = $("<ol>"+data+"</ol>");
response.find('.commentlist li:last').hide().appendTo(jQuery('.commentlist')).slideDown('slow');
}
});
ajaxSubmit sends the comment to wp-comments-post.php, which inelegantly spits back the entire page as a response. So, despite the fact that it's ugly as toads, I'm sticking the response text in a variable, using :last to isolate the most recent comment, and sliding it down in its place.
IE, however, is returning the cached version of the page, which doesn't include the new comment. So ".commentlist li:last" selects the previous comment, a duplicate of which then uselessly slides down beneath the original.
I've tried setting "cache: false" in the ajaxSubmit options, but it has no effect. I've tried setting a url option and tacking on a random number or timestamp, but it winds up being attached to the POST that submits the comment to the server rather than the GET that returns the response, and so has no effect. I'm not sure what else to try. Everything works fine in IE if I turn off browser caching, but that's obviously not something I can expect anyone viewing the page to do.
Any help will be hugely appreciated. Thanks in advance!
EDIT WITH A PROGRESS REPORT: A couple of people have suggested using PHP headers to prevent caching, and this does indeed work. The trouble is that wp-comments-post is spitting back the entire page when a new comment is submitted, and the only way I can see to add headers is to put them in the Wordpress post template, which disables caching on all posts at all times--not quite the behavior I'm looking for.
Is there a way to set a php conditional--"if is_ajax" or something like that--that would keep the headers from being applied during regular pageloads, but plug them in if the page was called by an Ajax GET?

jQuery.ajaxSubmit() takes any of the options for the standard jQuery.ajax(). You can thus use the standard cache: false option to turn off caching:
jQuery(this).ajaxSubmit({
cache: false,
success:
function(data) {
var response = $("<ol>"+data+"</ol>");
response.find('.commentlist li:last').hide().appendTo(jQuery('.commentlist')).slideDown('slow');
}
});

The way I have been doing this is by adding a rand=new Date().getTime() to the end
if(url.replace("?") != url)
url = url+"&rand="+new Date().getTime();
else
url = url+"?rand="+new Date().getTime();
The function above will append the rand=time to the address of the url [address to the .php] If you have supplied get parameters, it will add &rand=time... otherwise it will add ?rand=time
The browser keeps caching, but the pages won't overlap.
You could also use PHP's header() to disable caching by setting Cache-control: and Expires:

Put this in the beginning of Your php:
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");
This should help. If it doesn't - try putting a random number as a filename with the headers.
The post is redirected to a get request and You would have to send some info to the get page to control if it should be cached or not.

This will prevent caching globally
$(document).ready(function() {
$.ajaxSetup({ cache: false });
});

Related

Fancybox avoid caching of ajax requests

I'm currently facing an annoying (suspected) cache issue with fancybox 3.4.1:
<a data-fancybox="" data-type="ajax" data-src="src/views/forms/SpeiseplanCreateForm.php?ValidFrom=1560117600" href="javascript:;" id="fancybox-SpeiseplanCreateForm"><button id="fancybox-SpeiseplanCreateForm-button">Speiseplan bearbeiten</button></a>
has a GET parameter which is then evaluated by my PHP script, however, when I click on it for the first time, it works fine, but when I change the value of ValidFrom via JavaScript and try to open the box a second time, the get parameter is still the same as in the first call. I assume it's related to fancybox caching the requests.
I have verified that the URL parameter is getting changed properly and I also tried disabling the cache by adding this to my header:
<script>
$(document).ready(function() {
$(".data-fancybox").fancybox({
type : 'ajax',
ajax : { cache: false }
});
});
</script>
as suggested here: https://stackoverflow.com/a/17621281/4934937
Is there a way to disable the cache?
I just found a very dirty workaround for this. After editing the element in Firefox (Edit HTML), it worked. So I guessed it must have something in common with some weird caching (browser or fancybox, who knows).
The workaround is to create a new a element, remove the old a and append it to the old a's parent again.
let newElement = document.createElement("a");
newElement.setAttribute("id","fancybox-"+id)
newElement.setAttribute("data-fancybox","");
newElement.setAttribute("data-type","ajax");
newElement.setAttribute("href","javascript:;");
newElement.setAttribute("data-src",fancyboxSrc);
newElement.appendChild(button);
fancybox.outerHTML = "";
parent.appendChild(newElement);

IE10 - unable to prevent cache for iframe

I have modal boxes on a page are opening dynamic content in iframes.
Link 1 (fixed id)
Link 1 (fixed id)
...
But whatever I do, I can't prevent iframe content to be cached in IE10 (seems to other browsers are good).
I use html5 so meta tags are helpless.
Cache.manifest made my page messed up (or if to put just NETWORK: * - no effect).
PHP headers header("Cache-Control: no-cache"); header("Expires: -1"); also gives no effect for IE10.
JS/JQuery solutions found in web I couldn't apply correctly.
Any solution except to add another dynamic GET parameter for href ?
I'm not sure if this will work in IE10, but a few years ago Firefox had a similar issue with caching the content of iframes, and a trick to make it reload was to use JavaScript to force a reload like this:
var orig_src = iframe.src;
iframe.src = "blank.html"; # A blank document you'll need to create
setTimeout(function() { iframe.src = orig_src; }, 100);
or the simpler technique of
iframe.src = iframe.src;
... which also may or may not work in IE10.

Chrome displays ajax response when pressing back button

I've come across a problem that if I use jQuery's Get method to get some content, if I click back, instead of it actually going back one page in the history, it instead shows the content returned by the Ajax query.
Any idea's?
http://www.dameallans.co.uk/preview/allanian-society/news/56/Allanian-test
On the above page, if you use the pagination below the list of comments you will notice when clicking back after changing a page, that it shows the HTML content used to generate the list of comments.
I've noticed it doesn't always do it, but if you click on a different page a few times and click the back button, it simply displays json text within the window instead of the website.
For some reason, this is only affecting Chrome as IE and Firefox work ok.
Make sure your AJAX requests use a different URL from the full HTML documents. Chrome caches the most recent request even if it is just a partial.
https://code.google.com/p/chromium/issues/detail?id=108425
Just in case you are using jQuery with History API (or some library like history.js), you should change $.getJSON to $.ajax with cache set to false:
$.ajax({
dataType: "json",
url: url,
cache: false,
success: function (json) {...}
});
Actually this is the expected behavior of caching system according to specs and not a chrome issue. The cache only differentiate requests base on URL and request method (get, post, ...), not any of the request headers.
But there is a Vary header to tell browser to consider some headers when checking the cache. For example by adding Vary:X-Requested-With to the server response the browser knows that this response vary if request X-Requested-With header is changed. Or by adding Vary:Content-Type to the server response the browser knows that this response vary if request Content-Type header is changed.
You can add this line to your router for PHP:
header('Vary:X-Requested-With');
And use a middleware in node.js:
app.use(function(req, res) {
res.header('Vary', 'X-Requested-With');
});
You can also add a random value to the end of the ajax url. This will ignore the previous chrome cache and will request a new version
url = '/?'+Math.random()
Just add the following header to the Response headers :
Vary: Accept
I couldn't give different urls for each ajax request as it was an ajax pagination, declaring no cache on headers did nothing, so i included a little javascript in the view only when headers were for the ajax request:
<script>
if (typeof jQuery == 'undefined') {
window.location = "<?php echo $this->here; ?>";
}
</script>
It is a dirty trick, but it works, if the ajax content is normally loaded, the container has Jquery loaded so it does nothing. But if you load the ajax supposed content without the surrounding content, Jquery is missing (at least in my case), so i redirect to the current page requesting a normal GET page with all the headers and scripts.
If you put it in the top of the page, the user won't notice because it won't wait till the page loads, it will redirect as soon as the browser gets this 4 lines...
Replace here; ?> by the current url in your APP, this was a CakePhp 2.X
Still had this problem in 2021 in Chrome.
Problem is doing underlying ajax request to the same url as the one the user is currently on.
I was working in Symfony and the complete fix that did the work for me was
$response->headers->addCacheControlDirective('no-cache', true);
$response->headers->addCacheControlDirective('max-age', 0);
$response->headers->addCacheControlDirective('s-maxage', 0);
$response->headers->addCacheControlDirective('must-revalidate', true);
$response->headers->addCacheControlDirective('no-store', true);
/**
* from https://stackoverflow.com/a/1975677/5418514
*
* The HTTP request header 'Accept' defines the Content-Types a client can process.
* If you have two copies of the same content at the same URL, differing only in Content-Type,
* then using Vary: Accept could be appropriate.
*/
$response->headers->set('Vary', 'Accept');
The #abraham's answer is right.
I just wanted to post a solution for Rails: all you need is just add different path to routes.rb.
In example, I have resource :people and I want to compose index page from ajax parts one of those is list of people. The straightforward way is to create index.js.erb and to load partial via ajax using url: people_path. But here occurs the issue.
So, for Rails, it needs just add a different route, like
get 'people_list', to: 'people#index', as: :people_list, format: :js
If I want to use index method of a laravel controller returns both html and json response, I add a get parameter at the end of the endpoint to pass browser caching:
axios.get(url, {params: {ajax: 1}})

how to get information from php without refreshing the page

hi
sorry for the bad title but I'm not 100% sure what I need for this problem
I created a welcome page and then when you click on links you get more information, for example:
Click Me
And then the php would get the information based on the id.
so the information received is reloaded on the page after the pages refreshes
what I would like to be able to do is when user clicks on the link, use jquery to not allow the link to run but still run the url in the background (without refreshing the page)
I have no idea where to start from so I really hope you could help
thanks
In a nutshell, it's called Ajax: sending an HTTP request to your server through javaScript, and receiving a response which can contain results, data, or other information.
You mention jQuery, here are the docs about that:
http://api.jquery.com/jQuery.get/
http://api.jquery.com/jQuery.post/
are convenience methods, which encapsulate $.ajax with preset options.
http://api.jquery.com/category/ajax/ is an overview of the whole system in jQuery.
The basics go like
//include jquery, etc.
$(document).ready(function(){
$('#some_element').click(function(){
$.get('some_url_on_your_server.php',{'data':'whatever params'},function(data){
do_something();//
},'json');
});
This will bind an element to make an Ajax call on click, and then you use the function ('success' function, in $.ajax) to handle the json data.
Have your server send back the data in JSON by using json_encode in php. Be sure to send the right header back, like
<?php
header('Content-Type: application/json');
echo json_encode($some_array);
exit;
There's a lot of resources on the web and SO for learning about Ajax, it's a big topic. Best of luck.
Make a JavaScript function, like sendData(linkId) and then each tag would have an onclick event called sendData(this). SendData(linkId) can then do an HTTPRequest (also known as an asynchronous or AJAX request) to a php file, let's call it handler.php, which receives GET or POST methods. I prefer using the prototype framework to do this kind of thing (you can get it at prototypejs.org).
Okay, now that I have said all that, let's look into the nitty-gritty of how to do this (way simplified for illustrative purposes).
Download the prototype script, save it on your server (like prototype/prototype.js, for example) and then put somewhere in your html <script type='text/javascript' language='Javascript' src='prototype/prototype.js'></script>
Your tags would look like this:<a id='exampleLink' onclick = 'sendData(this)'>Click me!</a>
You need JavaScript to do this: function sendData(tagId){
var url = 'handler.php?' + 'id=' + tagId;
var request = new AJAX.Request(url, {method = 'get'});
}
Finally, you need a php file (let's call it handler.php) that has the following: <?php
$tag_to_get = $_GET['tagId'];
do_a_php_function($tag_to_get);
?>
That's it in a nutshell, but it's worth mentioning that you should give your user some sort of feedback that clicking link did something. Otherwise he will click the link furiously waiting for something to happen, when it is actually doing just what its supposed to but in secret. You do that by making your php script echo something at the end, like 'Success!', and then add an onSuccess parameter to your JavaScript's new Ajax.Request. I'll let you read how to do that on your own because the prototype website explains how to receive a response from the handler and put the feedback somewhere in your HTML without making the user refresh.
you can achieve that behavior with a jquery function called $.get ... you can get more information on how to use here http://api.jquery.com/jQuery.get/
If you really want to (and I don't think you really do), you can use XMLHTTPRequest (wrapped in jQuery.get) to facilitate loading content into the page without page refreshing. You want an id or class on that tag, i.e. Click Me, and then:
<script>
$(".fetch").bind("click", function(evt)
{
$.get(this.attr("href"), function(data)
{
$("#whereIWantMyContent").html(data);
});
evt.preventDefault();
});
</script>
I would recommend you use AJAX to start with. A good place to being is http://www.w3schools.com/Ajax/Default.Asp
The link comes with a handy AJAX ASP/PHP Example too =))
Good Luck.

Cannot make unload event fire in Firefox 4

I have run ajax-calls on the unload event for about a year.
It has generally worked in FF and IE but not to 100%, I cannot say when it has failed.
I register the event by writing in the bodytag:
onunload="...."
I got error messages in FF4 since the unload event also wanted to write in a div-tag of the page that just had unloaded. Fixed this by making the ajax-routine write nothing if the id of the target div is 'dummy'
I am no expert on AJAX, but the following code has worked:
http://yorabbit.info/e-dog.info/tmp/ajax_ex.php (the link is a text-page)
(You call ajaxfunction2 with the following arguments: filename, queryString for PHP, string to show in target div during update, name of target div)
I don't get any error messages in the FF error console and IE9 works. Is there any way I can make it work in FF too?? I have just started trying FF4, but my impression is that it works less well than in FF3.
Thanks.
(I am on a trip and ay not have the possibility to reply immediately, but I really appreciate suggestions and will reply in due course)
EDIT:
I had bettter add this:
The AJAX-call I make on unload does only send some data (how long time the user stayed on the page) to the PHP-MySQL server
I don't know what is happening here, but Firefox 4 has made notable changes to how unloading works: For example, if you do an alert() during a link click event, it will no longer freeze the page, but load the new location anyway. Maybe this is something similar.
However, you are never guaranteed for the Ajax call to finish if it is not synchronous in any browser anyway - the request may or may not come back with a response until the page has been closed. Whether this works will be down to chance, and the user's network speed.
Try using a synchronous request first, as outlined here: How does jQuery's synchronous AJAX request work?
this will usually guarantee that the request comes back. However, use it very sparingly - blocking behaviour at page unload can be very annoying for the user, and even freeze the browser.
I suggest to use jQuery instead of keeping track of browser changes yourself.
Solution:
Find working sample here: http://jsfiddle.net/ezmilhouse/4PMcc/1/
Assuming that your internal links are set relatively, and your external links therefore set starting with 'http':
Leave ...
Stay ...
You could hijack 'a' tags via jQuery events and ask the user to confirm the leaving (in case of external links). In 'ok' case you kick off your 'onleave' ajax call (async=true) and redirect user to external link:
$('a').live('click', function(event){
// cache link
var link = $(this).attr('href');
// check if external link (assuming that internal links are relative)
if (link.substr(0,4) === "http") {
// prevent default a tag event
event.preventDefault();
// popup confirm message
var reply = confirm('Do you really want to leave?');
if (reply) {
var url = 'http:mydomain.com/ajax.php';
var data = {'foo': 'bar', 'fee':'bo'};
// kick off your 'onleave' ajax call
// forced to be synchronous
$.ajax({
type: "POST",
async: false,
url: url,
data: data,
success: function( data ) {
// ok case: leave page, cached link
window.location.href = link;
}
});
}
return false;
}
});

Resources