XMLHttpRequest on load in saveback to calling object - javascript

I'm trying to load in many json files for a HTML5 game that will serve as sprite sheets. Previously I've did this synchronously but my new goal is to do this asynchronously.
I have run into a problem though where I'm trying to saving back to the calling object. This is so the information loaded can be used later and so a flag (loaded) can be set so the system knows when a resource has been loaded. Below is my XMLHttpRequest code. I have substituted "spritesheet" for what ever the call should be to save back to the parent.
function SpriteSheet(filename)
{
var tmpFileName = "json/" + filename;
this.loaded = false;
var xhr = new XMLHttpRequest();
xhr.open("GET",tmpFileName,true);
xhr.onload = function(event){
var parsed = JSON.parse(this.responseText);
"spritesheet".img=new Image();
"spritesheet".img.src = "imgs/" + parsed["imgLoc"];
"spritesheet".animations = parsed["animations"];
"spritesheet".sprites = parsed["sprites"];
"spritesheet".loaded = true;
};
xhr.send();
}
Can somebody inform me how I can save back to the the parent or if this is completely the wrong approach can they point me in the direction of a solution.

I found that by creating a var in the 'class' that is a reference to the object and using it in the onload function works, for example:
function SpriteSheet(filename)
{
var tmpFileName = "json/" + filename;
this.loaded = false;
var caller = this;
var xhr = new XMLHttpRequest();
xhr.open("GET",tmpFileName,true);
xhr.onload = function(event){
var parsed = JSON.parse(this.responseText);
caller.img=new Image();
caller.img.src = "imgs/" + parsed["imgLoc"];
caller.animations = parsed["animations"];
caller.sprites = parsed["sprites"];
caller.loaded = true;
};
xhr.send();
}

Related

How can I delete blob files in JavaScript?

I am creating an image viewer using XMLHttpRequest. It includes this function:
public view_image(_tImagen: iConfigImagen){
var img_view = this.prop_div_vizualizador;
var _window: any = window;
var xhr = new XMLHttpRequest();
xhr.open("GET", _tImagen.url, true);
xhr.responseType = "blob";
xhr.onload = function () {
var urlCreator = _window.URL = _window.URL || _window.webkitURL;
var imageUrl = urlCreator.createObjectURL(this.response);
_tImagen.urlBlob = imageUrl;
img_view.style("background-image", "url(" + _tImagen.urlBlob + ")");
}
}
It works fine, but I am trying to delete the blob files that it generates somehow. I tried URL.revokeObjectURL(url), but that only deletes the url and not the file. How can I delete the files? Is there any way to remove them?
Thanks in advance.
The XMLHttpRequest allows you to make an HTTP request and receive a response, but it does not give you access to the file system. You cannot delete files without access to them.

Increment variable in constructor function (JS)

I am fetching the data from 2 different APIs and I wrote a constructor function that will start XMLHttpRequest based on the new instance of the object creation (if it makes any sense...). Once the data is fetched and parsed I want to save it into different named variables. For instance: trial1data, trial2data. At the minute the new instances of the objects overwrite the data variable. Code below:
var api = "http://www.filltext.com/?rows=10&fname={firstName}&lname={lastName}&pretty=true";
var api2 = "http://www.filltext.com/?rows=10&fname={firstName}&lname={lastName}&tel={phone|format}&address={streetAddress}&city={city}&state={usState|abbr}&zip={zip}&pretty=true";
function FetchData(apiType) {
var r = new XMLHttpRequest();
this.apiType = apiType;
this.request = function() {
r.open("GET", apiType, true);
r.onload = function() {
var data = JSON.parse(r.responseText);
}
r.send(null);
}
}
trial1 = new FetchData (api);
trial1.request();
trial2 = new FetchData (api2);
trial2.request();
Thanks for the XMLHttpRequest tip, but the issue was to save each data into separate variables such as trial1data and trial2data (or anything else that has got a meaning and I can re-use later on), based on how many new objects I will create.
Your var r = new XMLHttpRequest(); is common.
You need to move it inside the function to create separate request everytime the constructor function is called.
function FetchData(apiType) {
this.apiType = apiType;
this.request = function() {
var r = new XMLHttpRequest();
r.open("GET", apiType, true);
r.onload = function() {
var data = JSON.parse(r.responseText);
console.log(data);
}
r.send(null);
}
}
You should put the request object creation inside the constructor:
function FetchData(apiType) {
var r = new XMLHttpRequest();
this.apiType = apiType;
this.done = new Promise( res => {
r.onload = function() {
res(JSON.parse(r.responseText) );
};
});
this.request = function() {
r.open("GET", apiType, true);
r.send(null);
};
}
So you can do:
const req = new FetchData("whatever");
req.request();
req.done.then(console.log);
Create new instance on var r = new XMLHttpRequest(); inside of constructor, or as a better approach, make it an argument for a constructor and inject new XMLHttpRequets object for each.
To answer the second part of your question, you could store response data in object's property and access it directly or getter interface. So instead of
r.onload = function() {
var data = JSON.parse(r.responseText);
}
Do something like:
function FetchData(apiType) {
var self = this;
this.apiType = apiType;
this.request = function() {
var r = new XMLHttpRequest();
return new Promise(function(resolve, reject) {
r.open("GET", apiType, true);
r.onload = function() {
self.data = JSON.parse(r.responseText);
resolve(self.data);
}
r.send(null);
}
}
Then
trial1 = new FetchData (api);
var trial1resp;
trial1.request().then(function(data) {
trial1resp = data;
}
The last assignment is just to show how is response stored. You must handle async processess to achieve your goal.
You could read little bit more about promisses and how to handle xhr async tasks here https://developers.google.com/web/fundamentals/primers/promises

Add progress bar to lightbox2

I was searching a way to add a progress indicator to lightbox2 script. My JS is pretty poor and I need a hint on where to start.
I assume I need to rewrite Image class prototype, to add methods like onprogress. This is well described here
But when I add those methods at the start of the script, they don't operate at all. I tried inserting console.log() to one of them, nothing logged, they just don't execute.
See comments in code below.
What exactly am I doing wrong, please?
//start of the original lightbox.js
//this is the code I've inserted, you can see I've added
//multiple console.log()s here just to check if methods called
Image.prototype.load = function(url){
console.log('1');
var thisImg = this;
var xmlHTTP = new XMLHttpRequest();
xmlHTTP.open('GET', url,true);
xmlHTTP.responseType = 'arraybuffer';
xmlHTTP.onload = function(e) {
var blob = new Blob([this.response]);
thisImg.src = window.URL.createObjectURL(blob);
console.log('2');
};
xmlHTTP.onprogress = function(e) {
thisImg.completedPercentage = parseInt((e.loaded / e.total) * 100);
console.log('3');
};
xmlHTTP.onloadstart = function() {
thisImg.completedPercentage = 0;
console.log('4');
};
xmlHTTP.send();
console.log('5');
};
Image.prototype.completedPercentage = 0;
//original script continues from here
....
//here imgPreloader declared, I assume it inherits methods from
//rewritten Image's prototype above
var imgPreloader = new Image();
imgPreloader.onload = (function(){
this.lightboxImage.src = this.imageArray[this.activeImage][0];
this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
}).bind(this);
//preloader's src changes and his methods should execute here
//but they don't
imgPreloader.src = this.imageArray[this.activeImage][0];

preload image with ajax

Found this technique of using ajax to preload things at: http://perishablepress.com/3-ways-preload-images-css-javascript-ajax/
window.onload = function() {
setTimeout(function() {
// XHR to request a JS and a CSS
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain.tld/preload.js');
xhr.send('');
xhr = new XMLHttpRequest();
xhr.open('GET', 'http://domain.tld/preload.css');
xhr.send('');
// preload image
new Image().src = "http://domain.tld/preload.png";
}, 1000);
};
I noticed that the 'ajax' preloading for this image isn't really ajax at all. It is the same as what I have been using for years already, just setting the url in a new image object's source and letting the browser load it into the cache.
Now imagine that there was an application where, I needed to actually cancel the preloading of the image if it took over a certain amount of time. There really is no good way to do this with just setting the image to src, unlike the xhr.abort() method which stops the loading of an actual xhr request.
Is there any reason that doing some thing like the below wouldn't preload the image just as well and allow the cancellation of the preload request?
function preload(url, timeout){
this.canceltimeout = function(){
clearTimeout(this.timeout);
this.loaded = true;
return false;
}
this.abort = function(){
this.xhr.abort();
this.aborted = true;
}
//creates a closure to bind the functions to the right execution scope
this.$_bind = function(method){
var obj = this;
return function (e){ obj[method](e);};
}
//set a default of 10 second timeout
if(timeout == null){
timeout = 10000;
}
this.aborted = false;
this.loaded = false;
this.xhr = new XMLHttpRequest();
this.xhr.onreadystatechange = this.$_bind('canceltimeout');
this.xhr.open('GET', url);
this.xhr.send('');
this.timeout = setTimeout(this.$_bind('abort'), timeout);
}
var llama = new preload('/image.gif');
show_image();
function show_image(){
if(llama.loaded){
var l = new Image();
l.src = '/image.gif';
application.appendChild(l);
}else if(llama.aborted){
var l = document.createElement('p');
l.innerHTML = 'image.gif got cancelled';
application.appendChild(l);
}else{
setTimeout(show_image, 10);
}
return false;
}
The main drawback is that unless you have configured your webserver to provide future freshness info(an Expires, or Cache-control: max-age http header that is in the future), the web browser may make a second http request to the server when you set the image.src, or just plain actually use the image in the document. If your web server had sent freshness validation headers(last-modified, or e-tag) then the image won't be redownloaded, but the request asking the server for freshness validation will stil be made, which is wasteful and adds latency to the process.
I don't know why, but browsers really like to cache the images when you hold a reference to an Image() object.
If you watch the net panel in a web browsers debug tools, you'll most browsers make the first 2 requests, but not the 3rd. Commenting out the code in the ajax callback, ands you'll see the request made for #3
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.js"></script>
<script>
var f = "0.png?" + (new Date); // 0.png should not have future freshness info headers
$.get(f, function() {
var i = new Image();
i.src = f;
});
setTimeout(function(){
//#3
var i = new Image();
i.src = f;
}, 5000);
</script>

Accessing variable outside on load function

Hi I am working Android application development using titanium studio.I have developed small application.my problem is that I can not access variable which is define inside the xhr.on load.I used following code:
xhr.onload = function()
{
var json = this.responseText;
var to_array = JSON.parse(json);
var to_count = to_array.length;
};
I want to access to_count and to_array outside onload function and pass it to another child window.For that I used following code:
var feedWin = Titanium.UI.createWindow({
url:'home/feed.js'
});//alert(to_count);
feedwin.to_array = to_array;
feedwin.to_count = to_count;
The XHR client is asychronous by default, which means that code will continue to execute while the XHR is running. If you have code that is dependent on your XHR being finished, then you will need to either call that code from within the onload function, or force the XHR to be synchronous by adding "false" as a third parameter to xhr.send() (I've found the first option to be the more reliable one, and more in line with what Titanium expects/feels is best practice, just FYI).
The best way to accomplish this is to initialize your feedWin in the onload. So, one of the following two snippets should work:
xhr.onload = function()
{
var json = this.responseText,
feedWin = Titanium.UI.createWindow({
url:'home/feed.js'
});//alert(to_count);
feedWin.to_array = JSON.parse(json);
feedWinto_count = to_array.length;
};
or
var feedWin = Titanium.UI.createWindow({
url:'home/feed.js'
});
xhr.onload = function()
{
var json = this.responseText,
feedWin.to_array = JSON.parse(json);
feedWinto_count = to_array.length;
};
I'm not familiar with Titanium, so I don't know particulars, but that is my best guess.
I am not very familiar with Titanium, but wrt to scope of declaration, I think this is what you need to do to use them outside the function.
var to_array;
var to_count;
xhr.onload = function()
{
var json = this.responseText;
to_array = JSON.parse(json);
to_count = to_array.length;
};

Categories

Resources