Preload page into turbolinks transition cache - ruby-on-rails

I'm using turbolinks to simulate a "single-page" app. The app is acceptably quick once pages are cached, however the first clicks are too slow. Is there a way to pre-fill the transition cache by loading some pages in the background?
I'm going to be looking into hacking into the page cache, but wondering if anyone has done this before.
(If this seems unusual, well, just trust that I'm doing this for good reason. Turbolinks gets nearly the performance of a far more complex implementation and overall I'm quite happy with it.)
UPDATE: So it seems like this SHOULD be relatively easy by simply adding entries to the pageCache of Turbolinks, something like:
$.ajax({
url: url,
dataType: 'html',
success: function(data) {
var dom = $(data);
Turbolinks.pageCache[url] = {
...
}
}
});
however it doesn't seem possible to construct a body element in javascript, which is required. Without out that, it doesn't seem like I can't construct the object that is stored in the cache without the browser first rendering it.
Any ideas beyond hacking more into Turbolinks?
UPDATE 2: There was the further problem that pageCache is hidden by a closure, so hacking Turbolinks is necessary. I have a solution that I'm testing that leverages iFrames - seems to be working.

First Hack Turbolinks to allow access to pageCache, the end of your turbolinks.js.coffee should look like this.
#Turbolinks = {
visit,
pagesCached,
pageCache,
enableTransitionCache,
enableProgressBar,
allowLinkExtensions: Link.allowExtensions,
supported: browserSupportsTurbolinks,
EVENTS: clone(EVENTS)
}
Then implement a fetch function. This is what you were thinking about, we can use DOMParser to convert string into DOM object.
function preFetch(url) {
$.ajax({
url: url,
dataType: 'html'
}).done(function(data) {
var key = App.Helper.getCurrentDomain() + url;
var parser = new DOMParser();
var doc = parser.parseFromString(data, "text/html");
Turbolinks.pageCache[key] = {
url: url,
body: doc.body,
title: doc.title,
positionY: window.pageYOffset,
positionX: window.pageXOffset,
cachedAt: new Date().getTime(),
transitionCacheDisabled: doc.querySelector('[data-no-transition-cache]') != null
};
});
};
Usage:
$(function() {
preFetch('/link1'); // fetch link1 into transition cache
preFetch('/link2'); // fetch link2 into transition cache
});

Related

jquery mobile 1.4 not updating content on page transition

From the index page, a user clicks a navigation link, the data attribute is passed via ajax, the data is retrieved from the server but the content is not being updated on the new page.
Been stuck for hours, really appreciate any help!
js
$('a.navLink').on('click', function() {
var cat = $(this).data("cat");
console.log(cat);
$.ajax({
url: 'scripts/categoryGet.php',
type: 'POST',
dataType: "json",
data: {'cat': cat},
success: function(data) {
var title = data[0][0],
description = data[0][1];
console.log(title);
$('#categoryTitle').html(title);
$('#categoryTitle').trigger("refresh");
$('#categoryDescription').html(description);
$('#categoryDescription').trigger("refresh");
}
});
});
Im getting the correct responses back on both console logs, so I know the works, but neither divs categoryTitle or categoryDescription are being updated. I've tried .trigger('refresh'), .trigger('updatelayout') but no luck!
This was not intended to be an answer (but I can't comment yet.. (weird SO rules)
You should specify in the question description that the above code IS working, that your problem occurs WHEN your playing back and forth on that page/code aka, using the JQM ajax navigation.
From what I understood in the above comment, you're probably "stacking" the ajax function every time you return to the page, thus getting weird results, if nothing at all.
Is your example code wrapped into something ? If not, (assuming you use JQM v1.4) you should consider wrapping it into $( 'body' ).on( 'pagecontainercreate', function( event, ui ) {... which I'm trying to figure out myself how to best play with..
Simple solution to prevent stacking the ajax definition would be to create/use a control var, here is a way to do so:
var navLinkCatchClick = {
loaded: false,
launchAjax: function(){
if ( !this.loaded ){
this.ajaxCall();
}
},
ajaxCall: function(){
// paste you example code here..
this.loaded = true;
}
}
navLinkCatchClick.launchAjax();

Ajax call on ruby on rails

I have a ajax call using ruby on rails. I'm getting a success but I don't know how to use the data result of the ajax call.
$.ajax({
url: "/search/get_listing?listing_id" + id,
dataType: 'JSON',
success: function(data) {
var listing = JSON.parse(data);
$("#modalPrice").html(data.city);
}
});
Controller:
#listings_data = Listings.find_by(id: params[:id])
render :json => #listings_data.to_json
Using data.city won't work. I'm expecting to get the values retrieve from the model by simply putting . on the variable
var listing = JSON.parse(data);
Still no luck. Help guys. Thanks!
JSON.parse is Ruby code, API of JSON gem. How can you guys use that in Javascript :)
jQuery can process JSON object data directly. Just use:
success: function(data) {
$("#modalPrice").html(data.city);
}
For example, you can render in the controller:
render :json => { :city => #listings_data }
On the JS:
success: function(data) {
var listing = data.city;
}
I'm having similar problems everytime I use AJAX in rails since the response seems to differ depending on how you return the value or how you are handling the success in JS. Try this:
success: function(data, status, xhr) {
var listing = JSON.parse(xhr.responseText);
$("#modalPrice").html(data.city);
}
I usually use Firebug (Firefox Plugin) to set a breakpoint in my success handlers to check the arguments where exactly the response is in. Sometimes it's in the first value, sometimes in some other and then it may be xhr.response or even xhr.responseText. It's confusing me every time.
To use Firebug for this, press F12 on your page, select the 'Script' pane and find the code you want to check. Click next to the row number of your code where you want your breakpoint. In this case, you could've chosen the var listing line. When the code is executed (after your click), the browser will stop there and you can check the passed arguments on the right side.

IE memory leak and eval with jQuery

I've created a page which needs to have its elements updated according what's happening with the data in our database. I'd like to know what do you think about this approach using eval, I know it's risky but in my case it was the fastest way.
$('.updatable').each(function () {
var data;
data = 'ViewObjectId=' + $(this).attr('objectid');
$.ajax({
async: true,
url: '/Ajax/GetUpdatedViewObjectDataHandler.ashx',
data: data,
type: 'POST',
timeout: 10000,
success: function (data) {
$.each(data, function (index, value) {
eval(value);
});
}
});
Now the issue I have is when the page is loaded, for each 10 seconds the page is updated, until here it's perfect.
After each round of updates, my Internet Explorer steal some memory, and it gets the whole machine memory after some hours, terrific.
What would you do in this case? Some other update approach is recommended? Or even, is there something you think I could do to avoid this memory leak?
Found the answer here: Simple jQuery Ajax call leaks memory in Internet Explorer
THE SOLUTION:
var request = $.ajax({ .... });
request.onreadystatechange = null;
request.abort = null;
request = null;
JQuery doesn't do that and the memory never releases.
jQuery version 1.4.2.
Now it's working like a charm.

Strange underscore param in remote links

I use Rails3, JQuery and will_paginate gem to make remote pagination links. Known solution for this is:
$('.pagination a').live('click',function (){
$.getScript(this.href);
return false;
});
With this code I get links like: http://localhost:3000/products?_=1300468875819&page=1 or http://localhost:3000/products?_=1300468887024&page=2. So the little question is: what is this strange param _=1300468887024 (looks like Unix-time). What is its purpose? As I know this can cause some problems with search crawlers.
UPD: The solution is described here.
it's a cache buster. It's also used in development mode, so to avoid getting an old request from the browser cache.
(unfortunately, all the explanations I found are realated to advertisement :S)
This is a simple solution if you don't mind removing it for all requests:
jQuery.ajaxSetup({ cache: true });
Another solution would be to extend jQuery's getScript function as per the documentation:
jQuery.cachedScript = function(url, options) {
options = $.extend(options || {}, {
dataType: "script",
cache: true,
url: url
});
return jQuery.ajax(options);
};
This way, only the ajax calls using this new method will use the cache. On the other hand, if you used the ajaxSetup method, all your ajax calls would cache by default since ajaxSetup sets the cache property globally.
Now you can use $.cachedScript(location.href); instead of $.getScript(this.href);.

jQuery UI AutoComplete Plugin - Questions

I have an ASP.NET MVC 3 Web Application (Razor), and a particular View with the jQuery UI AutoComplete plugin (v1.8).
Here's the setup i currently have:
$('#query').autocomplete({
source: function (request, response) {
$.ajax({
url: "/Search/FindLocations",
type: "POST",
dataType: "json",
data: { searchText: request.term },
success: function (data) {
response($.map(data, function (item) {
return { name: item.id, value: item.name, type: item.type }
}))
},
error: function (xmlHttpRequest, textStatus, errorThrown) {
// don't know what i should do here...
}
})
},
select: function (event, ui) {
$.get('/Search/RenderLocation', { id: ui.item.name }, function (data) {
$('#location-info').html(data);
});
},
delay: 300, minLength: 3
});
The AutoComplete returns locations in the world, basically identical to Google Maps auto complete.
Here are my questions:
1) What are the recommended settings for delay and minLength? Leave as default?
2) I thought about putting [OutputCache] on the Controller action, but i looks as though the plugin automatically does caching? How does this work? Does it store the results in a cookie? If so when does it expire? Is any additional caching recommended?
3) I've noticed if i type something, and whilst the AJAX request is fired off, if i type something else, the dialog shows the first result momentarily, then the second result. I can understand why, but it's confusing to the user (given the AJAX request can take 1-2 seconds) but i'm thinking about using async: false in the $.ajax options to prevent multiple requests - is this bad design/UX?
4) Can you recommend any other changes on my above settings for improving performance/usability?
1) It really depends on your usage and your data.
2) You should use [OutputCache]. If there's any caching happening on the plugin, it's only going to be for each user, if you use caching at the controller action level, it'll cache one for all users. (again, this might actually be bad depending on your usage, but usually this is good to do)
3) This questions kind of hard too because of the lack of context. If ajax requests are 1-2 seconds and there's no way to make this shorter, you really should be a pretty big delay in so that users aren't sending off many requests while typing out a long word (if they type slow).
4) sounds like you need to look at your /search/FindLocations method and see where you can do caching or pref improvements. Give us a look at your code in here and I can try to suggest more.

Resources