Load data from URL parameters faster - javascript

Assuming I am loading a web with domain.com/1/?nick=lili
Right now I am including in my html - multiple files, in one of them I do :
$(document).ready(function(){
let path = window.location.href ;
let nick = path.split('=')[1];
getData(nick,loadUI);
});
Using fast servers (Google's Firebase) I still get quite a delay, about 1-2 seconds while at this time the page is loaded with placeholders so no data, and the experience is not good.
I do not want to put a loader UI element, but to load faster.
Is there anywhere else in the code that I can put this to make things faster? (assuming I also need to load Google's server API on the body).
Removing all of this to the head should work better?

The window.location.href will be populated on pageload - there's no need to wait before checking it. Since getData does not need any data from the page in order to start the request, you can move it outside of the $(document).ready(, and even move it up to the top of the document, in the <head>, before any other scripts have run or elements have loaded. This ensures that the request gets sent out as fast as possible.
But
when someone open the page, all html placeholders (texts and photos) are loaded, then I need to fill them with data from DB
Because you need the page to be loaded when the request comes back, you can't just call getData alone, in the rare case that the page hasn't finished loading by then. So, if you change getData to return a Promise that resolves to the desired data, you could use Promise.all to wait for both the data and for the page to be loaded, after which you can populate the page elements:
Promise.all([
getData(nick,loadUI),
new Promise(res => window.addEventListener('DOMContentLoaded', res))
])
.then(([data]) => {
// Populate page with data from request
});

Related

Load JSON before anything else

I'm trying to load the JSON before anything else loads, because I need to access the JSON immediately when a browser connects to the server.
This is how I load my json
$.getJSON('icons.txt', function(iconData) {
icons = iconData;
});
How can I make it so javascript loads the json first before anything else? or at least makes it so that it's loaded before the user connects.
Just put all your other code inside function(iconData) {icons = iconData;}); callback function, it will be executed after the JSON will be fetched.
If you put your tag in the head of your HTML, it should be executed at first.
Maybe duplicate of: Load javascript before rendering page?
The code loaded on the head, and then set to synchronize loading
$.ajaxSettings.async = false;
$.getJSON(url, data, function(data){ });

Load data with AJAX only if it has not already been loaded?

I need to load data for my JavaScript app to use. I would like to load the following:
userlist JSON
milestones JSON
Tags JSON
user ACL permissions JSON
These 4 items of data from the server as JSON should be loaded using AJAX but only loaded once.
So I need code that will check to see if the data is loaded already and if it is, use it. If it is not loaded yet, it would make an AJAX request and load the data, and then use it.
I have multiple JavaScript files which need access to this data so I want to make sure that any of them can access it, and whichever once calls for it first will load it using AJAX and make it available for the other scripts to call it without making multiple repeat AJAX requests.
How could I go about this using JavaScript and jQuery?
A basic example would be super appreciated and useful. Thank you
If any of these are not set, load them using AJAX. After loading with AJAX, set these vars for the next caller to access them without a new AJAX request being made...
var userList = userJsonData;
var milestoneList = milestoneJsonData;
var tagList = tagJsonData;
var useAclPermissions = useAclPermissionsJsonData;
Just store the data in a global javascript variable, which is set to null, when your page loads. The first script which loads the data, stores it in the variable, all the other scripts try to access the content of the variable, and if not set, load it:
var milestoneData = null;
function getMilestoneData() {
if (milestoneData === null) {
//make the ajax request, and populate milestoneData variable
} else return milestoneData;
}
According to can i use you can check out localstorage aka webstorage. If you can use it, it might solve your issues. There is a jQuery plugin available. jstorage is an alternative, and has a really simple example at the bottom of the page. Hope this helps.

make sure javascript external script has completed before continuing

I am creating a few web pages that use the same large set of data, and it takes a few seconds to load and be processed. So it only has to load & process once, I put the loading in an external .js script, and assign the resulting array to a variable that I then could use in the other pages that reference that script.
Let's call the external script that loads the data external.js and one file that uses the data index.html. index.html has script tags with src="external.js" followed by script tags containing page-specific javascript.
How can I ensure that the index.html script waits for external.js to finish, or at least waits for the data portion to finish? I tried enclosing the code in $(function() { ... }); which is supposed to wait until the page loads, but it didn't work. I can see via console.log that it executes index.html before it finishes external.js.
Is there another strategy I can try to ensure the external.js is completely done before the javascript in index is executed?
Added info:
The external.js is kinda long and I'd rather not post it all, just the relevant parts. In index.html and the other pages to come, I will do a lot of stuff with the data so I want it as small as possible.
External.js uses d3's json() function (here is the latest incarnation):
json = [];
var loadJson = function() {
d3.json("data/file.json", function(error, json) {
// above file is an array of about 40,000 objects, ~36MB.
json = json.filter(function(d) { .. };
// above filter keep only the objects with certain properties.
// then I drop the properties I don't care about to reduce the size of the data
var tempdata = [];
json.forEach(function(d, i) {
tempdata[i] = {
"property1thatIwant":d.property1thatIwant,
// etc.
};
json = tempdata;
console.log(json);
(Imagine all the closing brackets and stuff.)
Then in index, I want to be able to use json as a regular array of objects that I can different things with on each of my pages, but it wasn't letting me. All I'm doing right now in that file is console.log(json). That produces [] in the console, after which I get the correct data for json.
This is not an ajax question. It has nothing to do with ajax.

How do I render a partial asynchronously/using AJAX in Rails?

I currently have the following code to load a partial when I scroll to the bottom of a div with a table:
$(document).ready(function () {
$("#pastGigs").scroll(function () {
if (isScrollBottom()) {
$('#pastGigs tr:last').after('<%= render "layouts/pastGigs" %>');
$(this).unbind("scroll");
}
});
function isScrollBottom() {
var elementHeight = $("#pastGigs")[0].scrollHeight;
var scrollPosition = $("#pastGigs").height() + $("#pastGigs").scrollTop();
return (elementHeight == scrollPosition);
};
});
It works fine, but the reason I'm using the partial is because I don't want everything to load immediately, as it really slows the page down. Should I not be using a partial at all, or is there another way to execute the script and load the content only after scrolling? I've had a look around similar questions on stackoverflow, they all explain how to render the partial (I didn't know about escape_javascript and deleted all whitespace in the partial manually...), but none seem to solve my current speed issue. There is a difference of about 15 seconds (!) due to the amount of data in the partial, which is why I don't want to load it synchronously.
EDIT: Current config/routes.rb:
root "resnate_pages#home"
resources :users, :path => ''
EDIT 2: Current error in Terminal:
Processing by UsersController#show as */*
Parameters: {"id"=>"pastGigs"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? LIMIT 1 [["id", "pastGigs"]]
Completed 404 Not Found in 3ms
ActiveRecord::RecordNotFound (Couldn't find User with id=pastGigs):
app/controllers/users_controller.rb:5:in `show'
After looking over everything, it looks like you have the right idea with rendering the partial except that, as we discussed, it is not actually being loaded asynchronously. Since you have the ERB tags in the body of the javascript, the ERB is actually being rendered server-side before being delivered to the browser (as you noticed, with the huge blob of HTML text). The reason this appeared to work (meaning avoiding the huge 15-second load times you mentioned) is because the HTML text isn't actually interpreted as HTML yet by the browser when the page loads (its just a plain 'ol string at this point). It will of course be parsed and evaluated when you do add it to the DOM with the .after function.
So basically we just need to ajax this stuff up. Good that you're looking at the jQuery ajax documentation; definitely worth the time and its pretty informative. There is also a $.get function which you might want to see as well. Its a convenience method for sending a GET request; you have less control, but if that doesn't matter, it can help keep things clean. I'll demonstrate with the $.get function, and you can choose to use the $.ajax function instead if you need the control (or prefer the other).
Put this in your scroll function:
$("#pastGigs").scroll(function () {
if (isScrollBottom()) {
$.get("/pastGigs", function(result){
$('#pastGigs tr:last').after(result);
});
$(this).unbind("scroll");
}
});
You can name the pastGigs route however you like, its only for demonstration purposes. Ensure you set up the route in your routes.rb
get "/pastGigs" => "users#pastGigs"
OR
get "/pastGigs", to: "users#pastGigs"
Again, I don't know what your controller is called, so replace it and the action name with the correct ones in your system.
And finally, the controller action:
def pastGigs
render :partial => "layouts/pastGigs"
# OR
# render "layouts/pastGigs", :layout => false
end
The end result will be that when the scroll reaches the bottom, an ajax call is fired off to that URL and your partial is rendered and returned to the success function (the second parameter of $.get). The result variable will contain the rendered HTML partial.
Let me know if that works.
Quickly adapted Paul's code to populate a modal for anyone who's interested:
$('#seeAll').click(function(){
$.get("/pastGigs", function(result){
$('#pastGigsBody').html(result);});
});
When the user clicks on "See All" in the Past Gigs div, it opens the modal with the all of the past gigs. Thanks to Paul for teaching me about the $.get request.

What is the best way to paginate xml results using jQuery?

I am using jQuery to get results, as xml, from a MySQL database. What is the best way to paginate the results?
Right now my script gets the xml and appends each result as a <li> element to a <ul> element.
I'm guessing it will have something to do with creating a global var that gets changed with the next/previous page button that runs a script to remove, then re-append the correct results range, but I'm not really sure.
You shouldn't make pagination dependent on Javascript, it should be done server-side instead. So, for example, the server could return a "next" link that would be something like View next 50 results. The script would take that variable of 50 and return the 50 next results and the link would then be returned as results.php?entry=100. You could integrate this with Ajax so the results would come back without a page refresh, however, but the pagination itself would still be done in the backend.
i would do something like this
var numRows = $table.find('tbody tr').length
var numPages = Math.ceil(numRows / numPerPage)
var $pager = $('</p><br>
<div class="pager"></div>
')
for (var page = 0 page < numPages page++) {
$('<span class="page-number">' + (page + 1) + '</span>')
.appendTo($pager).addClass('clickable')
}
$pager.insertBefore($table)
There are a few plugins, but you're on the right track. When you do the remove/re-append thing, do a $('#mydiv').load('/path/to/myfile.php'). Pass your file the start and stop points, which would serve as the points in your array from which to grab your data.
function paginate(start, limit) {
// Maybe show a preloader?
$('#loader').show();
$("#mydiv").load("/path/to/myfile.php", {start: start, end: limit}, function(){
// hide preloader or do other code here
$('#loader').hide();
});
}
Do you get the entire result set (all the pages) in one go, or do you get one page at a time? In any case you should keep a local cache of the data you received from the server and use that when the user navigates the pages. For example, if you retrieve one page at a time, and the user goes from page 1 to page 2, then you need to retrieve page 2 from the server. But if the user now goes back to page 1, then you should load that from the cache. If the user goes to page 3, then you should fetch that from the server and add it to the cache.
Next I would separate the logic for displaying a single page to the user and fetching a page from the server. When the user clicks on the next page button, you should ask the cache object for the next page, but don't return anything. Instead the cache will call a callback function once it has data. If the data is in the cache, it would call the callback function immediately, passing the result as an argument. The callback function would then update the view presented to the user. If the data is not in the cache, an ajax request is made to the server for that data. Once the data is retrieved, the callback function would be called.
I'm usually against using xml with ajax (I prefer ajaj; Asynchronous JavaScript and JSON. It's also a lot more fun to say out loud). JSON is a better alternative, because it's a lot easier to work with in JavaScript, it takes up less space, both in memory and during transport. Since JSON objects are normal JavaScript objects, adding them to a local cache is as easy as concatenating two arrays (the cache you already have and the new elements retrieved from the server).

Categories

Resources