Javascript variable reverting to original - javascript

function loadAll() {
var zip64;
var zipURL = 'settings/Images.zip';
var xhr = new XMLHttpRequest();
xhr.open('GET', zipURL, true);
xhr.responseType = 'arraybuffer';
xhr.onload = function() {
if (this.status == 200) {
var responseArray = new Uint8Array(this.response);
var d = responseArray.length;
var binaryString = new Array(d);
while (d--) {
binaryString[d] = String.fromCharCode(responseArray[d]);
}
var data = binaryString.join("");
zip64 = window.btoa(data);
zip.createReader(new zip.Data64URIReader(zip64), function(reader) {
reader.getEntries(function(entries) {
z = 0;
zloopid = setInterval(function() {
if (z >= entries.length || !entries[z]) {
clearInterval(zloopid);
reader.close();
start();
return;
}
if (entries[z].filename.split("/")[0] == "__MACOSX") {
z++;
return;
}
$("#loadimg").html("Loading " + entries[z].filename + ".... (" + (z + 1) + " of " + entries.length + ")");
var isMask = (entries[z].filename.replace(/^.*[\\\/]/, '') == "mask.jpg");
entries[z].getData(new zip.Data64URIWriter(), function(uri) {
if (isMask) {
imgtemp = new Image();
imgtemp.src = uri;
}
else {
var lol = new Image();
lol.src = uri;
imageLibrary.push(lol);
}
});
z++;
}, 0);
});
}, function(error) {
window.location = "error.html?err=Error by unzipper: " + error + " (Problem in Images.zip)";
});
}
else {
window.location = "error.html?err=Error while retrieving zip file (" + zipURL + ") : " + this.status;
}
};
xhr.send();
}
function start() {
var image = imgtemp;
width = image.width;
height = image.height;
So I have this piece of code. I have a global variable named imgtemp but everytime I set it in the if (inMask) block, it reverts to undefined when start() is called. Why is this?
loadAll() is called first, then start(). I can confirm that when the code that calls start() in loadAll() executes, imgtemp already turned back to undefined.
Thanks in advance!

It is because loadAll becomes async and returns before anything is loaded so when you call start the image has not been set yet. You'll need to "chain" them instead of calling them separately.
Only call loadAll() and then inside the loadAll add an event handler for loading the image which when loaded calls the start() function.
/* snip */
entries[z].getData(new zip.Data64URIWriter(), function(uri) {
if (isMask) {
imgtemp = new Image();
imgtemp.onload = function(event) {
start(); /* <--- HERE */
}
imgtemp.src = uri;
}
else {
/* snip */

Related

How can I execute code after .onload function

I'm working with image preview before upload.
So I'm displaying the choosen files. It's working well.
But I'm stuck in a situation.
Foreach file on the "input file", the scripts tests if it's too small (smaller than 300px w:h).
If one of these files disobey this rule (must be width and height greater than 300px), the script has set an error var as true. And, after the "for" block, check if "error" is true or false.
I'm working in this scenario:
window.onload = function () {
var fileUpload2 = document.getElementById("inputFileID");
fileUpload2.onchange = function () {
var error = false;
if (typeof (FileReader) != "undefined") {
var dvPreview = document.getElementById("divToShowPreview");
dvPreview.innerHTML = "";
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.jpg|.jpeg|.gif|.png|.bmp)$/;
if(fileUpload2.files.length > 3) {
alert('Only 3 files allowed!');
} else {
for (var i = 0; i < fileUpload2.files.length; i++) {
var file = fileUpload2.files[i];
if (regex.test(file.name.toLowerCase())) {
var reader = new FileReader();
reader.onload = function (e) {
var img = document.createElement("IMG");
img.src = e.target.result;
img.onload = function() {
console.log(this.width + " " + this.height);
if(this.width >=300 && this.height >=300 ) {
dvPreview.appendChild(img);
} else {
error = true;
}
};
};
reader.readAsDataURL(file);
} else {
alert(file.name + " is not a valid image file.");
dvPreview.innerHTML = "";
return false;
}
}
console.log(error);
}
} else {
alert("This browser does not support HTML5 FileReader.");
}
};
};
As you can see, the console.log(error) still shows FALSE!
How can I get this var set as true?
Thanks
the problem is that the img.onload functions is asynchronously executed. therefore console.log(error) is executed before or between the img.onload
this can be proven by looking at the sequence of your console.log, that look something like:
false
300 300
200 300
to solve this problem, create a variable to count how many images have been load, then count it in every img.onload. when the count of image that has been load is equal to the uploaded image count, call a function to check if error exists. for example:
function imageError(){
alert('image size to small');
}
window.onload = function () {
var fileUpload2 = document.getElementById("inputFileID");
// add variables
var imgLoaded = 0;
fileUpload2.onchange = function () {
var error = false;
if (typeof (FileReader) != "undefined") {
var dvPreview = document.getElementById("divToShowPreview");
dvPreview.innerHTML = "";
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.jpg|.jpeg|.gif|.png|.bmp)$/;
if(fileUpload2.files.length > 3) {
alert('Only 3 files allowed!');
} else {
for (var i = 0; i < fileUpload2.files.length; i++) {
var file = fileUpload2.files[i];
if (regex.test(file.name.toLowerCase())) {
var reader = new FileReader();
reader.onload = function (e) {
var img = document.createElement("IMG");
img.src = e.target.result;
img.onload = function() {
//increase the loaded img count
imgLoaded++;
console.log(imgLoaded); // another check to show the sequence of events
console.log(this.width + " " + this.height);
if(this.width >=300 && this.height >=300 ) {
dvPreview.appendChild(img);
} else {
error = true;
}
// call imageError if all image have been loaded and there is and error
if (imgLoaded == fileUpload2.files.length){
console.log(error) // just to check
if (error){
imageError();
}
}
};
};
reader.readAsDataURL(file);
} else {
alert(file.name + " is not a valid image file.");
dvPreview.innerHTML = "";
return false;
}
}
//console.log(error); // no need for this line
}
} else {
alert("This browser does not support HTML5 FileReader.");
}
};
};
You have to break your for when you find a error, so it will not perform the next verification.
...
} else {
error = true;
break;
}
...

Validate the image upload with size, height and width

function displayPreview(files) {
var reader = new FileReader();
var img = new Image();
reader.onload = function (e) {
img.src = e.target.result;
fileSize = Math.round(files.size / 1024);
if(fileSize>50) {
ret1=false;
alert("File size is " + fileSize + " kb");
return ret1;
} else {
var ret1 = true;
return ret1;
}
img.onload = function () {
if(this.width!="181" && this.height!="181") {
ret1=false;
alert("width=" + this.width + " height=" + this.height);
return ret1;
} else {
var ret1 = true;
return ret1;
}
console.log("width=" + this.width + " height=" + this.height+"File size is " + fileSize + " kb");
};
};
reader.readAsDataURL(files);
}
function chkform() {
var ret = false;
if (document.getElementById("file").value === "") {
console.log("empty");
} else {
var file = document.getElementById("file").files[0];
var tt=displayPreview(file);
console.log(tt+"nis");
}
return ret;
}
When a user clicks on the submit button, the form has an onsubmit="return chkform();", then my checkform checks if the id name file is empty or not.
If not, then it call the function displayPreview(). In that function I am checking whether the size is not more than 50 and width and height is not equal to width="181px" and height="181px".
I am returning ret through which I can get the information it's returning true or false
but In my checkform I am getting UNDEFINED... why?
Edit
Added reproduction code at JSFIddle: http://jsfiddle.net/nishit_bhardwaj/zaukV/
Sorry I didn't work with your code but this is how you can get the filesize. After that it's easy to validate. You also could disable or hide the submit/upload-button if the filesize is incorrect:
http://jsfiddle.net/rq8nA/
JS:
$("input:file").change(function () {
if ($(this).val() !== "") {
var file = $('#file_select')[0].files[0];
console.log(file.size);
}
});
HTML:
<input type="file" name="file" id="file_select" />
I added something to get width and preview image too:
http://jsfiddle.net/rq8nA/1/

Maintaining state of variables when changed inside a timer

I am using JavaScript.
I amusing a setInterval timer method.
Inside that method I am changing the values of module variables.
The thing is in IE the changes to the variables are not 'saved'. But in Chrome they are.
What is the accepted practice to do what I need to do?
this is my code:
function start()
{
var myVar = setInterval(function () { GetTimings() }, 100);
}
var currentts1;
var currentts2;
var currentts3;
var currentts4;
var frameCounter;
function GetTimings() {
if (frameCounter < 1) {
frameCounter++;
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("GET", urlTS, false);
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4) {
var nextts = xmlhttp.responseText;
var bits = nextts.split('|');
if (currentts1 != bits[0]) {
currentts1 = bits[0];
postMessage("0|" + bits[0]);
}
if (currentts2 != bits[1]) {
currentts2 = bits[1];
postMessage("1|" + bits[1]);
}
if (currentts3 != bits[2]) {
currentts3 = bits[2];
postMessage("2|" + bits[2]);
}
if (currentts4 != bits[3]) {
currentts4 = bits[3];
postMessage("3|" + bits[3]);
}
frameCounter--;
}
}
xmlhttp.send();
}
}
The variables:
currentts1
currentts2
currentts3
currentts4
frameCounter
values are not preserved...
Try this, but notice I changed the currentts* to an Array when you try to view them
function start() {
var myVar = setInterval(GetTimings, 100);
}
var currentts = [null, null, null, null];
var in_progress = 0; // clear name
function GetTimings() {
var xhr;
if (in_progress > 0) return; // die
++in_progress;
xhr = new XMLHttpRequest();
xhr.open('GET', urlTS);
function ready() {
var nextts = this.responseText,
bits = nextts.split('|'),
i;
for (i = 0; i < currentts.length; ++i)
if (currentts[i] !== bits[i])
currentts[i] = bits[i], postMessage(i + '|' + bits[i]);
--in_progress;
}
if ('onload' in xhr) // modern browser
xhr.addEventListener('load', ready);
else // ancient browser
xhr.onreadystatechange = function () {
if (this.readyState === 4 && xhr.status === 200)
ready.call(this);
};
// listen for error, too?
// begin request
xhr.send();
}

XMLHttpRequest loop memory leak

I'm trying to check many items against information on ajax URL. But when I'm running this function in browser, memory usage goes above 2 gigs and then browser crashes (Chrome, Firefox). What am I doing wrong? items variable is really big - >200 000 and also includes some large strings.
var items = [1,2,3,4,5,6,7,8,9,10,...,300000]
var activeItems = {}
function loopAjax(){
for (i=0; i < items.length; i++) {
var currItem = items[i];
var request = new XMLHttpRequest();
var found = 0
request.open("GET", "/item=" + currItem);
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status == 200) {
var response = JSON.parse(request.responseText);
var active = response[0].active;
if (active) {
console.log("FOUND ACTIVE! " + currItem);
activeItems[found] = {"active": true, "item": currItem};
found++;
}
}
}
request.send();
}
}
Thank goodness the browser stalls and dies. If it didn't you just created a denial of service attack!
The problem needs to be reapproached. You better off creating a state machine which has a stack of requests in it. That way you only doing say 5 concurrent requests at a time.
function ItemChecker(sample_size, max_threads) {
this.sample_size = sample_size;
this.max_threads = max_threads;
this.counter = 0;
this.activeItems = [];
this.isRunning = false;
this.running_count = 0;
}
ItemChecker.prototype.start = function start() {
this.isRunning = true;
while (this.running_count < this.max_threads) {
this.next();
}
return this;
};
ItemChecker.prototype.stop = fucntion stop() {
this.isRunning = false;
return this;
};
ItemChecker.prototype.next = function next() {
var request, item_id, _this = this;
function xhrFinished(req) {
var response;
if (req.readyState !== 4) {
return;
}
_this.counter--;
if (req.status === 200) {
try {
response = JSON.parse(request.responseText);
if (response[0].active) {
_this.activeItems.push({
active: true,
item: item_id;
});
}
} catch(e) {
console.error(e);
}
// When finished call a callback
if (_this.onDone && _this.counter >= _this.sample_size) {
_this.onDone(_this.activeItems);
}
}
else {
console.warn("Server returned " + req.status);
}
}
if (!this.isRunning || this.counter >= this.sample_size) {
return;
}
item_id = this.counter;
this.counter++;
request = new XMLHttpRequest();
request.onreadystatechange = xhrFinished;
request.open("GET", "item=" + item_id);
request.send();
};
ItemChecker.prototype.whenDone = function whenDone(callback) {
this.onDone = callback;
return this;
};
This might work? Didn't try it for real. But you would call it with:
var item_checker = new ItemChecker(300000, 5);
item_checker.whenDone(function(active) {
// Do something with active
}).start();

How to wait for all XHR2 send calls to finish

I have done some code to upload multiple files from browser to server, while showing progressbars as well.
XHR2 send calls are asynchronous. The problem is that I want to call some functions after all the XHR2 send calls are finished.
Here is a very simplified snippet of my code:
<input id="upload" multiple="multiple" />
<script>
var files = document.getElementById("upload").files;
for (var i = 0, length = files.length; i < length; i++) {
var file = files[i];
var uploadFunc = function (arg) {
return function () {
processXHR(arg);
};
}(file);
uploadFunc();
}
function processXHR(file) {
var normalizedFileName = getNormalizedName(file.name);
var url = 'upload_file/';
var formData = new FormData();
formData.append("docfile", file);
var xhr = new XMLHttpRequest();
var eventSource = xhr.upload;
eventSource.addEventListener("progress", function (evt) {
var position = evt.position || evt.loaded;
var total = evt.totalSize || evt.total;
console.log('progress_' + normalizedFileName);
console.log(total + ":" + position);
$('#progress_' + normalizedFileName).css('width', (position * 100 / total).toString() + '%');
}, false);
eventSource.addEventListener("loadstart", function (evt) {
console.log('loadstart');
}, false);
eventSource.addEventListener("abort", function (evt) {
console.log('abort');
}, false);
eventSource.addEventListener("error", function (evt) {
console.log('error');
}, false);
eventSource.addEventListener("timeout", function (evt) {
console.log('timeout');
}, false);
xhr.onreadystatechange = function (evt) {
if (xhr.readyState == 4) {
console.log('onreadystatechange: File uploaded.');
}
};
xhr.open('post', url, true);
xhr.send(formData);
}
</script>
Whenever "onreadystatechange: File uploaded." is printed in console, I know that one of the files is done uploading.
But I am not able to write any code that will say "All Files uploaded.".
Thanks for any help.
I am using jquery as well in case some one has a solution using jquery.
Do you know how many calls you are making? If so, at least ajax callback, you check the count. Something like
if (ajaxCallCount === ajaxCallsLength) {
// Do stuff involving post all ajax calls
} else {
ajaxCallCount++;
}
You will need a counter and setInterval method in your case, try this:
<input id="upload" multiple="multiple" />
<script>
var files = document.getElementById("upload").files;
var counter = 0;
for (var i = 0, length = files.length; i < length; i++) {
var file = files[i];
var uploadFunc = function (arg) {
return function () {
processXHR(arg);
};
}(file);
uploadFunc();
}
var interval = setInterval(function() {
if(counter == files.length) {
clearInterval(interval);
console.log("All Files uploaded!");
}
}, 100);
function processXHR(file) {
var normalizedFileName = getNormalizedName(file.name);
var url = 'upload_file/';
var formData = new FormData();
formData.append("docfile", file);
var xhr = new XMLHttpRequest();
var eventSource = xhr.upload;
eventSource.addEventListener("progress", function (evt) {
var position = evt.position || evt.loaded;
var total = evt.totalSize || evt.total;
console.log('progress_' + normalizedFileName);
console.log(total + ":" + position);
$('#progress_' + normalizedFileName).css('width', (position * 100 / total).toString() + '%');
}, false);
eventSource.addEventListener("loadstart", function (evt) {
console.log('loadstart');
}, false);
eventSource.addEventListener("abort", function (evt) {
console.log('abort');
}, false);
eventSource.addEventListener("error", function (evt) {
console.log('error');
}, false);
eventSource.addEventListener("timeout", function (evt) {
console.log('timeout');
}, false);
xhr.onreadystatechange = function (evt) {
if (xhr.readyState == 4) {
counter += 1;
}
};
xhr.open('post', url, true);
xhr.send(formData);
}
</script>

Categories