I have two functions in jQuery. One of them looks for image extensions from form and another is getting image dimensions and triggers an alert() when an image is not big enough.
Both functions are correctly executed in demos but together only one is executed. Only part where extensions is getting is executed. Sorry for the length of the code but it was the only way to show the problem.
(function ($) {
$.fn.checkFileType = function (options) {
var defaults = {
allowedExtensions: [],
success: function () {},
error: function () {}
};
options = $.extend(defaults, options);
return this.each(function () {
$(this).on('change', function () {
var value = $(this).val(),
file = value.toLowerCase(),
extension = file.substring(file.lastIndexOf('.') + 1);
if ($.inArray(extension, options.allowedExtensions) == -1) {
options.error();
$(this).focus();
} else {
options.success();
}
});
});
};
})(jQuery);
$("#filput").on('change', function () {
var fr = new FileReader;
fr.onload = function () { // file is loaded
var img = new Image;
img.onload = function () {
// image is loaded; sizes are available
var w = img.width
if (w < 500) {
alert("too small");
} else {
alert("big enough");
}
};
img.src = fr.result;
};
fr.readAsDataURL(this.files[0]);
});
$(function () {
$('#filput').checkFileType({
allowedExtensions: ['jpg', 'jpeg', 'png'],
error: function () {
alert('error');
}
});
});
Only part where extentions is getting is executed
That code is wrapped by $(function() { ... }); so, you should probably put both pieces of code there:
$(function() {
$("#filput").on('change', function () {
var fr = new FileReader;
// ...
});
$('#filput').checkFileType({
// ...
});
});
Based on what you have described, the input element wasn't present yet at the time your code is run; by putting both code segments in the DOMReady event handler, you're making sure it exists.
Related
I think my javascript in my php file is in conflict with my javascript file.
I have a script that checks of the image is smaller then 2MB and a script that shows the image you selected in a small version. But the second part does not work when the first script is active. how do I fix this?
script in HTML
<script>
window.onload = function() {
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
if(this.files[0].size > 2000000){
alert("File is too big!");
this.value = "";
};
};
var uploadField = document.getElementById("itemImages");
uploadField.onchange = function() {
if(this.files[0].size > 200){
alert("File is too big!");
this.value = "";
};
};
}
</script>
.js file
$("#frontImages").change(function () {
if ($('#frontImages').get(0).files.length > 0) {
$('#frontImages').css('background-color', '#5cb85c');
} else {
$('#frontImages').css('background-color', '#d9534f');
}
});
$("#itemImages").change(function () {
if ($('#itemImages').get(0).files.length > 0) {
$('#itemImages').css('background-color', '#5cb85c');
} else {
$('#itemImages').css('background-color', '#d9534f');
}
});
document.getElementById("frontImages").onchange = function () {
var x = document.getElementById('previewFrontImage');
x.style.display = 'block';
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById("previewFrontImage").src = e.target.result;
};
reader.readAsDataURL(this.files[0]);
};
function previewImages() {
var $preview = $('#previewItemImages').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
var reader = new FileReader();
$(reader).on("load", function () {
$preview.append($("<img/>", {src: this.result, height: 100}));
});
reader.readAsDataURL(file);
}
}
$('#itemImages').on("change", previewImages);
I'm guessing that the conflict is between the html script and this
document.getElementById("frontImages").onchange = function ()
I also have a question how I can fix that there will be no small image when the image is too big
Your guess is correct, onchange is simply member variable of various elements, and thus
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
and
document.getElementById("frontImages").onchange = function ()
are setting this single variable (of frontImages), which will store one callback function at a time.
You could use addEventListener() instead, which maintains a list of event listeners, so there can be more than one. Modifying the lines to
var uploadField = document.getElementById("frontImages");
uploadField.addEventListener("change", function() {
and
document.getElementById("frontImages").addEventListener("change", function ()
will register both event listeners on frontImages, regardless of the order they are executed.
Side remark: when you have "nice" ids, document.getElementById() can be omitted, as elements with ids become variables (of window which is the global scope), and thus you could write frontImages.addEventListener(...). You still need the getter in various cases, like when a local variable shadows the id, or when it is not usable as variable identifier (like id="my-favourite-id" or id="Hello World")
I have two function print and callPrint bellow. I click call function print the first time is right.
But when click call function print the second or third then function callPrint will be call 2 times or 3 times.
I have debug on attack file.
function print(url) {
console.log('print');
var _this = this, iframeId = 'iframeprint', $iframe = $('iframe#iframeprint');
if ($iframe.attr('src') != url) {
$.when(
$iframe.attr('src', 'about:blank'),
$iframe.load(function () {
console.log($iframe.prop('contentWindow').document.readyState);
})
).done(function () {
$iframe.attr('src', url);
$iframe.load(function () {
console.log('new');
_this.callPrint(iframeId);
});
});
} else {
console.log('old');
_this.callPrint(iframeId);
}
}
// initiates print once content has been loaded into iframe
function callPrint(iframeId) {
console.log('callPrint');
$('div.wait').hide();
var PDF = document.getElementById(iframeId);
PDF.focus();
PDF.contentWindow.print();
return false;
}
A JavaScript function is repeated many times
The problem is because you're attaching two new load() event handlers to the iframe every time print() is called. To fix this, add a single load() event handler and call your function from in there. This will be triggered whenever you update the src attribute on the element. Try this:
var $iframe = $('#iframeprint').load(function() {
// You'll need to make sure the function is in scope of the handler
// There's not enough information in the OP for me to show you how
callPrint('iframeprint');
});
function print(url) {
var _this = this;
if ($iframe.attr('src') != url) {
$iframe.attr('src', url);
} else {
_this.callPrint(iframeId);
}
}
Thanks "Rory McCrossan". I add setTimeout function when callPrint so dialog print will open. But I can't vote for you at the moment.
var $iframe = $('iframe#iframeprint').load(function () {
// You'll need to make sure the function is in scope of the handler
// There's not enough information in the OP for me to show you how
setTimeout(function () {
callPrint('iframeprint');
}, 100);
});
function print(url) {
if ($iframe.attr('src') != url) {
$iframe.attr('src', url);
} else {
console.log('old');
callPrint('iframeprint');
}
}
// initiates print once content has been loaded into iframe
function callPrint(iframeId) {
$('div.wait').hide();
var PDF = document.getElementById(iframeId);
PDF.focus();
PDF.contentWindow.print();
}
I am trying to create a function that will recursively try to reload an image until it either is successful, or a maximum amount of attempts is reached. I have created this function, but it doesn't work (is it due to the fact that the reference to the image has changed?):
function reload (image, URL, maxAttempts)
{
image.onerror = image.onabort = null;
if (maxAttempts > 0)
{
var newImg = new Image ();
newImg.src = URL;
newImg.onerror = image.onabort = reload (image, URL, maxAttempts - 1);
newImg.onload = function () {
newImg.onerror = newImg.onabort = null;
image = newImg;
}
}
else
{
alert ("Error loading image " + URL); /* DEBUG */
}
}
Which is used in the following manner:
var globalTestImage = new Image ();
reload (globalTestImage, "testIMG.jpg", 4);
Rather than it attempting to load "testIMG.jpg" four times, and waiting in between attempts, it instead tries to load it twice, and regardless of whether it was successful the second time around it will display the error message.
What am I doing there? More precisely, why is it acting the way it is, rather than retrying to load the image 4 times?
(function ($) {
var retries = 5; //<--retries
$( document).ready(function(){
$('img').one('error', function() {
var $image = $(this);
$image.attr('alt', 'Still didn\'t load');
if (typeof $image !== 'undefined') {
if (typeof $image.attr('src') !== 'undefined') {
$image.attr('src', retryToLoadImage($image));
}
}
});
});
function retryToLoadImage($img) {
var $newImg = $('<img>');
var $src = ($img.attr('src')) || '';
$newImg.attr('src', $src);
$newImg.one('error', function() {
window.setTimeout(function(){
if (retries > 0) {
retries--;
retryToLoadImage($newImg);
}
}, 1000); //<-retry interval
});
$newImg.one('load', function() {
return $newImg.attr('src');
});
}
})(jQuery);
Some code I wrote for the same case a while ago. Hope it helps you!
In the end I solve this issue in a simple (if inelegant) way:
try
{
canvas.getContext("2d").drawImage (testImage, 0, 0);
backgroundLoaded = true;
}
catch (err)
{
testImage = new Image ();
testImage.src = "placeholder.jpg";
}
The idea is that if an image failed to load, it will fail when rendering it on the canvas, producing an error. When such an error happens, we can create a new image and try again.
I have a image loader function, that calls a function when all images are loaded, regardless how many I load. But currently it fails when a image src file name is not valid, because onload is not called.
How can I throw an error message, if an image is not loaded?
loadImage: function(image, id, fn) {
var bgImg = new Image(),
self = this;
// counting images currently loaded
this._loadingImages++;
// set image source and onload callback
bgImg.src = image;
bgImg.onload = function() {
fn(image, id);
self._loadingImages--;
if( self._loadingImages === 0 ) self.imagesLoaded();
}
},
loadImage: function (image, id, fn) {
var bgImg = new Image(),
self = this;
// counting images currently loaded
this._loadingImages++;
// set image source and onload callback
bgImg.src = image;
bgImg.onerror = function () {
// your error code
}
bgImg.onload = function () {
fn(image, id);
self._loadingImages--;
if (self._loadingImages === 0) {
self.imagesLoaded();
}
}
};
This should work.
This Thread can help you: Check if an image is loaded (no errors) in JavaScript
I guess with jQuery you can achieve this such the answer on the link that I've copied below:
$("<img/>")
.load(function() { console.log("image loaded correctly"); })
.error(function() { console.log("error loading image"); })
.attr("src", $(originalImage).attr("src"))
;
Thanks to t.niese, this is my solution:
loadImage: function(image, id, fn) {
var bgImg = new Image(),
self = this;
// counting images currently loaded
this._loadingImages++;
// set error and onload callback and then image source
bgImg.onerror = function() {
throw new Error( "ERROR" );
};
bgImg.onload = function() {
fn(image, id);
self._loadingImages--;
if( self._loadingImages === 0 ) self.imagesLoaded();
}
bgImg.src = image;
},
I want to know when an image has finished loading. Is there a way to do it with a callback?
If not, is there a way to do it at all?
.complete + callback
This is a standards compliant method without extra dependencies, and waits no longer than necessary:
var img = document.querySelector('img')
function loaded() {
alert('loaded')
}
if (img.complete) {
loaded()
} else {
img.addEventListener('load', loaded)
img.addEventListener('error', function() {
alert('error')
})
}
Source: http://www.html5rocks.com/en/tutorials/es6/promises/
Image.onload() will often work.
To use it, you'll need to be sure to bind the event handler before you set the src attribute.
Related Links:
Mozilla on Image.onload()
Example Usage:
window.onload = function () {
var logo = document.getElementById('sologo');
logo.onload = function () {
alert ("The image has loaded!");
};
setTimeout(function(){
logo.src = 'https://edmullen.net/test/rc.jpg';
}, 5000);
};
<html>
<head>
<title>Image onload()</title>
</head>
<body>
<img src="#" alt="This image is going to load" id="sologo"/>
<script type="text/javascript">
</script>
</body>
</html>
You can use the .complete property of the Javascript image class.
I have an application where I store a number of Image objects in an array, that will be dynamically added to the screen, and as they're loading I write updates to another div on the page. Here's a code snippet:
var gAllImages = [];
function makeThumbDivs(thumbnailsBegin, thumbnailsEnd)
{
gAllImages = [];
for (var i = thumbnailsBegin; i < thumbnailsEnd; i++)
{
var theImage = new Image();
theImage.src = "thumbs/" + getFilename(globals.gAllPageGUIDs[i]);
gAllImages.push(theImage);
setTimeout('checkForAllImagesLoaded()', 5);
window.status="Creating thumbnail "+(i+1)+" of " + thumbnailsEnd;
// make a new div containing that image
makeASingleThumbDiv(globals.gAllPageGUIDs[i]);
}
}
function checkForAllImagesLoaded()
{
for (var i = 0; i < gAllImages.length; i++) {
if (!gAllImages[i].complete) {
var percentage = i * 100.0 / (gAllImages.length);
percentage = percentage.toFixed(0).toString() + ' %';
userMessagesController.setMessage("loading... " + percentage);
setTimeout('checkForAllImagesLoaded()', 20);
return;
}
}
userMessagesController.setMessage(globals.defaultTitle);
}
Life is too short for jquery.
function waitForImageToLoad(imageElement){
return new Promise(resolve=>{imageElement.onload = resolve})
}
var myImage = document.getElementById('myImage');
var newImageSrc = "https://pmchollywoodlife.files.wordpress.com/2011/12/justin-bieber-bio-photo1.jpg?w=620"
myImage.src = newImageSrc;
waitForImageToLoad(myImage).then(()=>{
// Image have loaded.
console.log('Loaded lol')
});
<img id="myImage" src="">
You could use the load()-event in jQuery but it won't always fire if the image is loaded from the browser cache. This plugin https://github.com/peol/jquery.imgloaded/raw/master/ahpi.imgload.js can be used to remedy that problem.
If the goal is to style the img after browser has rendered image, you should:
const img = new Image();
img.src = 'path/to/img.jpg';
img.decode().then(() => {
/* set styles */
/* add img to DOM */
});
because the browser first loads the compressed version of image, then decodes it, finally paints it. since there is no event for paint you should run your logic after browser has decoded the img tag.
Here is jQuery equivalent:
var $img = $('img');
if ($img.length > 0 && !$img.get(0).complete) {
$img.on('load', triggerAction);
}
function triggerAction() {
alert('img has been loaded');
}
Not suitable for 2008 when the question was asked, but these days this works well for me:
async function newImageSrc(src) {
// Get a reference to the image in whatever way suits.
let image = document.getElementById('image-id');
// Update the source.
img.src = src;
// Wait for it to load.
await new Promise((resolve) => { image.onload = resolve; });
// Done!
console.log('image loaded! do something...');
}
these functions will solve the problem, you need to implement the DrawThumbnails function and have a global variable to store the images. I love to get this to work with a class object that has the ThumbnailImageArray as a member variable, but am struggling!
called as in addThumbnailImages(10);
var ThumbnailImageArray = [];
function addThumbnailImages(MaxNumberOfImages)
{
var imgs = [];
for (var i=1; i<MaxNumberOfImages; i++)
{
imgs.push(i+".jpeg");
}
preloadimages(imgs).done(function (images){
var c=0;
for(var i=0; i<images.length; i++)
{
if(images[i].width >0)
{
if(c != i)
images[c] = images[i];
c++;
}
}
images.length = c;
DrawThumbnails();
});
}
function preloadimages(arr)
{
var loadedimages=0
var postaction=function(){}
var arr=(typeof arr!="object")? [arr] : arr
function imageloadpost()
{
loadedimages++;
if (loadedimages==arr.length)
{
postaction(ThumbnailImageArray); //call postaction and pass in newimages array as parameter
}
};
for (var i=0; i<arr.length; i++)
{
ThumbnailImageArray[i]=new Image();
ThumbnailImageArray[i].src=arr[i];
ThumbnailImageArray[i].onload=function(){ imageloadpost();};
ThumbnailImageArray[i].onerror=function(){ imageloadpost();};
}
//return blank object with done() method
//remember user defined callback functions to be called when images load
return { done:function(f){ postaction=f || postaction } };
}
This worked for me:
// Usage
let img = await image_on_load(parent_element_to_put_img, image_url);
img.hidden = true;
// Functions
async function image_on_load(parent, url) {
let img = element(parent, 'img');
img.src = url;
await new Promise((resolve, reject) => {
element_on(img, 'load', () => {
resolve();
});
element_on(img, 'error', () => {
reject();
});
});
return img;
}
function element(parent, tag_name, text = '') {
let result = document.createElement(tag_name);
element_child_append(parent, result);
element_html_inner(result, text);
return result;
}
function element_child_append(parent, result) {
parent.appendChild(result);
}
function element_html_inner(result, text) {
result.innerHTML = text;
}
function element_on(e, event, on_event) {
e.addEventListener(event, async () => {
await on_event();
});
}
If you are using React.js, you could do this:
render() {
// ...
<img
onLoad={() => this.onImgLoad({ item })}
onError={() => this.onImgLoad({ item })}
src={item.src} key={item.key}
ref={item.key} />
// ...
}
Where:
- onLoad (...) now will called with something like this:
{ src: "https://......png", key:"1" }
you can use this as "key" to know which images is loaded correctly and which not.
- onError(...) it is the same but for errors.
- the object "item" is something like this { key:"..", src:".."}
you can use to store the images' URL and key in order to use in a list of images.