How can I execute code after .onload function - javascript

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;
}
...

Related

Chrome Extensions, scope the local variable in.in.inside a function (from backgound.js )and use it globally (or in popup.js).

Recently I want to start a project by piggyback someone's extension. I want to scope one of the image source (local variable, a base64 url) and then photo recognize it on the popup page. I keep getting error "imgb64.replace is not a function" or "imgb64" not defined.
like my title said, I want to scope the local variable in.in.inside a function (from backgound.js )and use it globally (or in popup.js). very new to this, please help guys.
// this is popup.js
chrome.runtime.getBackgroundPage(function(bg) {
bg.capture(window);
});
/// what I did
function img_find() {
var imgs = document.getElementsByTagName("img");
var imgSrcs = [];
for (var i = 0; i < imgs.length; i++) {
imgSrcs.push(imgs[i].src);
}
return imgSrcs;
}
var imgb64 = img_find();
try {
const app = new Clarifai.App({
apiKey: 'mykey'
});
}
catch(err) {
alert("Need a valid API Key!");
throw "Invalid API Key";
}
// Checks for valid image type
function validFile(imageName) {
var lowerImageName = imageName.toLowerCase();
return lowerImageName.search(/jpg|png|bmp|tiff/gi) != -1;
}
var imageDetails = imgb64.replace(/^data:image\/(.*);base64,/, '');
console.log(imageDetails)
app.models.predict("e466caa0619f444ab97497640cefc4dc", {base64:
imageDetails}).then(
function(response) {
// do something with response
},
function(err) {
// there was an error
}
);
/// end what I did
below is background.js, I think what I need is the local var img.src, thats all.
function capture(popup) {
function callOnLoad(func) {
popup.addEventListener("load", func);
if (popup.document.readyState === "complete") {
func();
}
}
crxCS.insert(null, { file: "capture.js" }, function() {
crxCS.callA(null, "get", function(result) {
var scrShot, zm, bufCav, bufCavCtx;
function mkImgList() {
for (var i = 0; i < result.vidShots.length; i++) {
var img = new popup.Image();
img.onload = function() {
this.style.height = this.naturalHeight /
(this.naturalWidth / 400) + "px";
};
if (result.vidShots[i].constructor === String) {
img.src = result.vidShots[i];
} else {
bufCav.width = result.vidShots[i].width * zm;
bufCav.height = result.vidShots[i].height * zm;
bufCavCtx.drawImage(scrShot, -result.vidShots[i].left *
zm, -result.vidShots[i].top * zm);
img.src = bufCav.toDataURL('image/png');
////// maybe clarifai here ?
////end clarifai
}
popup.document.body.appendChild(img);
}
popup.onclick = function(mouseEvent) {
if (mouseEvent.target.tagName === "IMG") {
chrome.downloads.download({ url: mouseEvent.target.src,
saveAs: true, filename: "chrome_video_capture_" + (new Date()).getTime() +
".png" });
}
};
popup.onunload = function(mouseEvent) {
crxCS.callA(null, "rcy");
};
} /// end mkImgList
if (result.needScrShot) {
bufCav = popup.document.createElement("canvas");
bufCavCtx = bufCav.getContext("2d");
chrome.tabs.captureVisibleTab({ format: "png" },
function(dataUrl) {
scrShot = new Image();
scrShot.onload = function() {
chrome.tabs.getZoom(function(zoomFactor) {
zm = zoomFactor;
callOnLoad(function() {
mkImgList(zoomFactor);
});
});
};
scrShot.src = dataUrl;
});
} else if (result.vidShots.length) {
callOnLoad(mkImgList);
} else {
popup.document.body.appendChild(notFound);
}
}); // end crxCS.callA
}); // end crxCS.insert
} // end capture
Please help guys. :)

Do 3 unified checks

I have a form with 3 file input fields, but Laravel is giving me this problem: link
So, I will check before sending the files, the maximum resolution will be 2000x2000, I got this code and modified, but it is still giving an error because one passes the other. I want to know how I can unify the 3 checks into one.
Here's my code:
$("#personal").change(function() {
var fr = new FileReader;
fr.onload = function() {
var imgPersonal = new Image;
imgPersonal.onload = function() {
if (imgPersonal.width > 2000 && this.height > 2000) {
$("#submitDocs").attr("disabled", true);
} else {
$("#submitDocs").removeAttr("disabled");
}
};
imgPersonal.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
$("#self").change(function() {
var fr = new FileReader;
fr.onload = function() {
var imgSelf = new Image;
imgPersonal.onload = function() {
if (imgSelf.width > 2000 && this.height > 2000) {
$("#submitDocs").attr("disabled", true);
} else {
$("#submitDocs").removeAttr("disabled");
}
}
};
imgSelf.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
$("#address").change(function() {
var fr = new FileReader;
fr.onload = function() {
var imgAddress = new Image;
imgPersonal.onload = function() {
if (imgAddress.width > 2000 && this.height > 2000) {
$("#submitDocs").attr("disabled", true);
} else {
$("#submitDocs").removeAttr("disabled");
}
}
};
imgAddress.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
Try putting all the duplicate code in a single function, in keeping with DRY, and keeping a persistent object that checks to see if any of the uploaded images are invalid:
const checks = {
personal: true,
self: true,
address: true,
};
function validate(file, checkAttr) {
const fr = new FileReader();
fr.readAsDataURL(file);
fr.onload = function() {
const img = new Image();
img.onload = () => {
if (img.width > 2000 || img.height > 2000) checks[checkAttr] = true;
else checks[checkAttr] = false;
if (checks.personal && checks.self && checks.address) $("#submitDocs").removeAttr("disabled");
else $("#submitDocs").attr("disabled", true);
}
img.src = fr.result;
}
}
$("#personal").change(function() {
validate(this.files[0], 'personal');
});
// other handlers
#CertainPerformance, Thanks, I was able to do it your way, I did this function and I used onblur = "btndisabled();" in each input
function btndisabled() {
var sizePersonal = personal.files[0].size;
var sizeSelf = self.files[0].size;
var sizeAddress = address.files[0].size;
if (sizePersonal < 1000000 && sizeSelf < 1000000 && sizeAddress < 1000000) {
$("#submitDocs").removeAttr("disabled");
} else {
alert('File larger than 1MB');
$("#submitDocs").attr("disabled", true);
}
}

How setting a variable in img.onload function

From here i learned how to check if an image is available or not.
But i have a question. I have a variable and i would set her value according id the image is available or not.
For example i have this:
app.checkImage = function (imageSrc, good, bad) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
}
I have an app object like this:
var app = {
offlineChecked: false,
offline: false,
};
Inside another function i have this code listing:
if(app.offlineChecked == true)
{
//don't do nothing
}
else
{
app.checkImage("https://mysite" + data.image_150,
function(){ app.offline = false; },
function(){ app.offline = true; });
app.offlineChecked = true;
}
But this doesn't work. app.offline is always false, in case the image isn't available and img.onerror fires.
Edit - i read the app.offline value after that code listing, as follow here:
if(app.offlineChecked == true)
{
//don't do nothing
}
else
{
app.checkImage("https://mysite" + data.image_150,
function(){ app.offline = false; },
function(){ app.offline = true; });
app.offlineChecked = true;
}
if(app.offline == true)
{
console.log('offline');
}
else
{
console.log('online);
}
Problem, that onerror function fires more late, than you try to check it.
Try this example
var app = {
offlineChecked: false,
offline: false
};
var ready = false;
app.checkImage = function (imageSrc, good, bad, onready) {
var img = new Image();
img.onload = good;
img.onerror = bad;
img.src = imageSrc;
img.onreadystatechange = onready;
};
if (app.offlineChecked == true) {
//don't do nothing
}
else {
app.checkImage("https://mysite",
function () {
app.offline = false;
},
function () {
app.offline = true;
alert(app.offline);
ready =true;
});
app.offlineChecked = true;
}
setInterval(function () {
if (ready) {
alert(app.offline);
}
}, 1000);
img.onload and img.onerror behave itself as callback, when scripts load or not, it runs onload or onerror. When you try to check it, onerror function doesn't yet launched
I found solution here.
That solved my problem. I write solution on it:
app.checkImage = function(imageSrc, imageChecked)
{
var img = new Image();
img.onload = function(){
app.offline = false;
imageChecked(app.offline);
}
img.onerror = function(){
app.offline = true;
imageChecked(app.offline);
}
img.src = imageSrc;
}
app.offline variable is set in the callback function as follows:
if(app.offlineChecked == true)
{
/**Other operations here if app is offline or not*/
}
else
{
app.checkImage("https://mysite" + data.image_150, function(offline)
{
app.offline = offline;
if(app.offline == true)
{
console.log('offline');
}
else
{
console.log('online');
}
app.offlineChecked = true;
});
}

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/

Javascript variable reverting to original

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 */

Categories