I have the following code, which executes before a form is submitted.
I'm changing an image then redrawing a canvas before saving that image.
the problem I have is that it doesn't work as intended (instead it saves the image with the previous image src attribute)...
If I step through it in firebug the correct image is saved, which leads me to think there needs to be a delay before it saves....
How do I do it?
$('#WindowForm').submit(function () {
if (isInternal)
{
imgsrc = $(".externalColor.selected-color").find('img').attr("src");
draw();
var canvas = document.getElementById('myCanvas');
context.drawImage(can, 0, 0)
var dataURL = canvas.toDataURL();
$("#ImageData").val(dataURL);
return true;
}
});
Note that there is an onload in the draw method too:
var img = new Image();
img.src = imgsrc;
img.onload = function () {
pattern = context.createPattern(img, "repeat");
context.fillStyle = pattern;
DrawContext(context);
};
The problem is very likely that you need to wait for the image to load in your draw() function. The best way would be to include a callback parameter in your function, so you could save after it is finished.
function draw(callback){
//...
img.onload = (function(callback){
return function(){
//...create your pattern...
callback.call();
};
})(callback);
}
draw(function(){ /* ...save image... */ });
You could also use something like setTimeout(function(){ /*...save image...*/ }, 1); but this isn't the best solution.
I'd approach it like this:
$( 'form' ).on(
'submit',
function( evt ) {
var form = $( this );
evt.preventDefault(); // prevent the form submission
// ...do stuff...
// delay the submission
window.setTimeout(
function() {
form.off( 'submit' ); // remove this event handler
form.submit(); // manually submit the form
},
500 // or whatever
);
}
);
This basically stops the form from being submitted until everything is sorted, then manually submits it. You might want to combine this with #Evilzebra's answer and stick the timeout function in an onload event for the created image, however the basic principles will be the same (prevent submission, then manually submit once ready).
N.B. you need to unbind the event handler before the manual submit, or the submit event will fire again and just keep running in a loop!
Looking through your code I think I understand what you're trying to do, and why its not working. First off I think your example code has some errors that shouldn't be there. I'm going to assume that imgsrc should be img.src at which point your making an asynchronous call to load a new image, which most likely won't be done until after you've competed the rest of this function. A quick and easy way to remedy this is to create a flag that lets the img.onload know if it should be saving the image or not. In the below example I key off of isInternal
$('#WindowForm').submit(function (e) {
if (isInternal)
{
e.preventDefault();
imgsrc = $(".externalColor.selected-color").find('img').attr("src");
// this will then cause the img.onload to fire
};
});
function pleaseSubmitMe(){
draw();
var canvas = document.getElementById('myCanvas');
context.drawImage(can, 0, 0)
var dataURL = canvas.toDataURL();
$("#ImageData").val(dataURL);
// alright now that thats done, lets submit this bad boy
isInternal= false; // we need to set this to false so we actually try submitting
$('#WindowForm').submit();
}
img.onload = function () {
pattern = context.createPattern(img, "repeat");
context.fillStyle = pattern;
DrawContext(context);
// if I'm Internal lets send this image to be submitted
if(isInternal){
pleaseSubmitMe();
}
};
Related
I write a function for checking image height and width. You can find my code below. It works but I have a problem with return false: it does not work.
$("#published").click(function( event ){
var img = $('<img src="'+selectedImage+'"/>').load(function( event ){
var orgWidth = this.width;
var orgHeight = this.height;
console.log(orgWidth+" = "+orgHeight);
if(orgWidth >= 169 && orgHeight >= 169){
thisValidate.parent('div.rwmb-input').children('.imageError').remove();
return true;
}else{
event.preventDefault();
if(thisValidate.parent('div.rwmb-input').children('.imageError').length == 0){
thisValidate.parent('div.rwmb-input').append("<p class='imageError'></p>");
}
thisValidate.parent('div.rwmb-input').children('.imageError').html('<br/><label for="techranger_booked_feature_images" class="error">Upload Image More then 169 x 169</label>');
return false;
}
});
});
I have added event.preventDefault(); but it did not help as well.
You are returning to the load() function which isn't going to return to the outer click function.
Also load() is asynchronous so the click event will be completed long before load().
Finally you have 2 event arguments and the one inside load isn't going to have any impact on the click
You would need to prevent the click completely and trigger the next event manually when the load() succeeds.
$("#published").click(function( event ){
event.preventDefault();// prevent default
// no access to "this" inside load() so store reference to form
var $form = $(this).closest('form');
var img = $('<img src="'+selectedImage+'"/>').load(function(imgEvt ){
// code removed for clarity
if(orgWidth >= 169 && orgHeight >= 169){
/* trigger form submit */
$form.submit();
}else{
// other code
}
});
});
Firstly, your return false is running in the scope of the function which serves the load event and your event is an event of jQuery load function.
Secondly, if you want to do it on the button, you cannot do it synchronously like you try to do because the request to get your image is asynchronous, so it happens after your function on button event is finished (so you can't stop the event default behavior because it is already happened). You are forced to prevent / return false in the click method regardless of the image size and then call another function when the check is (un-?)successful to go on. This is the only way.
$("#published").click(function(event){
// here your check, e.g. if (imageFits) goOnFunction();
event.preventDefault();
});
And finally you absolutely do not need jQuery here:
var myImage = new Image();
myImage.src = 'http://okolo.me/wp-content/uploads/2015/07/5998.jpg';
myImage.onload = function() {
// here you can use myImage.width and myImage.height
};
To make sure a document is ready before doing stuff, i do the following :
(function() {
var interval = window.setInterval(function() {
if("complete" === document.readyState) {
window.clearInterval(interval);
// Some stuff
}
}, 10);
})();
If somewhere in my code i create an image from JavaScript like this :
var image = new Image();
image.onload = function() {
// Some other stuff
};
image.src = 'some_url';
Will the check I perform on document.readyState also wait for "image" to be loaded, or will it just wait for the images present in the HTML code, and only those, to be loaded ?
Thanks in advance.
You don't need your setInterval.
From the MDN :
The load event fires at the end of the document loading process. At
this point, all of the objects in the document are in the DOM, and all
the images and sub-frames have finished loading.
You can simply do this for the statically included images :
window.onload = function() {
// Some stuff
};
As this doesn't take into account the images you create later, you may do this :
window.onload = function() {
var image = new Image();
image.onload = function(){
// Some stuff
};
image.src = 'some_url';
};
In jquery document.ready() function is call when entire html page is ready or we can say bind (in technical terms).
You should try with increasing Interval time. or include image load callback for performing the stuff.
I want to create an alert box after an image is loaded, but if the image is saved in the browser cache, the .onload event will not be fired.
How do I trigger an alert when an image has been loaded regardless of whether the image has been cached or not?
var img = new Image();
img.src = "img.jpg";
img.onload = function () {
alert("image is loaded");
}
As you're generating the image dynamically, set the onload property before the src.
var img = new Image();
img.onload = function () {
alert("image is loaded");
}
img.src = "img.jpg";
Fiddle - tested on latest Firefox and Chrome releases.
You can also use the answer in this post, which I adapted for a single dynamically generated image:
var img = new Image();
// 'load' event
$(img).on('load', function() {
alert("image is loaded");
});
img.src = "img.jpg";
Fiddle
If the src is already set then the event is firing in the cached case before you even get the event handler bound. So, you should trigger the event based off .complete also.
code sample:
$("img").one("load", function() {
//do stuff
}).each(function() {
if(this.complete || /*for IE 10-*/ $(this).height() > 0)
$(this).load();
});
There are two possible solutions for these kind of situations:
Use the solution suggested on this post
Add a unique suffix to the image src to force browser downloading it again, like this:
var img = new Image();
img.src = "img.jpg?_="+(new Date().getTime());
img.onload = function () {
alert("image is loaded");
}
In this code every time adding current timestamp to the end of the image URL you make it unique and browser will download the image again
I have met the same issue today. After trying various method, I realize that just put the code of sizing inside $(window).load(function() {}) instead of document.ready would solve part of issue (if you are not ajaxing the page).
I found that you can just do this in Chrome:
$('.onload-fadein').each(function (k, v) {
v.onload = function () {
$(this).animate({opacity: 1}, 2000);
};
v.src = v.src;
});
Setting the .src to itself will trigger the onload event.
Using the following script to add an event listener, basically it says "Hide the #curtain div (whole page) until .bgImage is downloaded, then wait 1500ms and fade everything in"
My question is this - sometimes due to server lag or glitchy triggering of .bind("load") the page is not fading in. How can I add some kind of timeOut to the effect so that it triggers after X miliseconds if the .bind("load) event is not triggered?
$(document).ready(function(){
// #curtain DIV begins hidden then fades in after .bgImage (curtain) is loaded - prevents "ribbon" loading effect in Chrome
$('#curtain').hide();
$(".bgImage").bind("load", function () {$('#curtain').delay(1500).fadeIn(); });
});
$(".bgImage").bind("load", function () {
setTimeout(function() {
$('#curtain').delay(1500).fadeIn();
}, 500);
});
if you want to add a delay to the fadeIn animation this will help. cheers
What you could do is this:
var url = $('.bgImage').attr('src');
var img = new Image();
img.onload = function() {
$('#curtain').delay(1500).fadeIn();
};
img.src = url;
In my experience, as long as you set up the "onload" property of an "Image" object before you set the "src", the handler will always run.
edit — if you wanted to be sure that the thing would eventually fade in, then you could do something like this:
var allDone = false;
var url = $('.bgImage').attr('src');
var img = new Image();
img.onload = function() {
if (!allDone) {
$('#curtain').delay(1500).fadeIn();
allDone = true;
}
};
setTimeout(img.onload, 5000); // show the hidden stuff after 5 seconds, image or no image
img.src = url;
You can use something like this:
var timeout;
$(".bgImage").bind("load", function(){
clearTimeout(timeout);
// do something here
});
timeout = setTimeout(function(){
$(".bgImage").unbind("load");
// do something else instead
}, 10000);
and maybe also handle errors:
$(".bgImage").bind("error", function(){
// do something else here as well
});
UPDATE: I added code to cancel your timeout when the load does happen. Those two functions has to be able to cancel out each other.
Try adding this to your css:
#curtain {
display:none;
}
and using this in your document read():
$(.bgImage).load(function() {
$('#curtain').fadeIn(3000);
});
I'm currently working on a page that loads several images sequentially using setTimeout and onLoad. Basically when an image finishes loading, onLoad is triggered, which starts another image loading via a setTimeout call. Unfortunately, if an image load is interrupted for some reason, such as a subsequent ajax call, onload is never called and any images left to be loaded are not loaded. Is there any way in javascript to detect this situation? I've attempted to hook into onError and onAbort (on the image tag) and neither of these seem to be called.
queuePhotos: function(options)
{
this.init();
this.photo_urls = options.photo_urls;
this.photo_size = options.size
this.max_width = options['max_width'];
this.max_height = options['max_height'];
this.containers = options['containers'];
yd = YAHOO.util.Dom;
photo_tags = yd.getElementsByClassName('image_stub', 'div');
for( i in photo_tags )
{
//create new image
photo = new Image();
this.queue.push( { tag: photo_tags[i], photo: photo } );
}
setTimeout(photoLoader.prepareNextPhoto, 1);
},
prepareNextPhoto: function()
{
photo_tag_and_image = photoLoader.queue.shift();
if(photo_tag_and_image)
{
YAHOO.util.Event.addListener(photo_tag_and_image.photo, "load", photoLoader.appendPhoto, photo_tag_and_image, photoLoader);
photo_tag_and_image.photo.src = photoLoader.photo_urls[photo_tag_and_image.tag.id];
}
},
An AJAX call shouldn't cancel the loading of images. There could be something else going on here...
I don't think that you can readily detect the load failure of an image. You could fire off a timer with a certain timeout threshold to deem an image as failed if your timeout timer expires before you get the load event from the image.
You can call onload and onerror
myImage.onload = function(){ alert("loaded"); };
myImage.onerror = function(){ alert("whoops"); };
Eric