New user here.
I am making a hockey game using JavaScript, and I need all of the images to finish loading before the main function is called to avoid flickering.
There are four images used: skaterAmin.png, skaterBmin.png, goalieAmin.png, goalieBmin.png
I am getting stuck on 2 out of 4 .onload functions.
both loadSkaterImgA and loadSkaterImgB will change to true but both loadGoalieImgA and loadGoalieImgB remain false
also used console.log() to confirm they were actually stuck
I also double checked all image src's and they are correct
//load images before main draw function to avoid flickering
var loadSkaterImgA = false;
var loadGoalieImgA = false;
var loadSkaterImgB = false;
var loadGoalieImgB = false;
function preloadSkaterImgA() {
var skaterImgA = new Image();
skaterImgA.onload = function() {
completeSkaterImgA();
return;
}
skaterImgA.src = 'skaterAmin.png';
return skaterImgA;
}
function preloadGoalieImgA() {
var goalieImgA = new Image();
goalieImgA.onload = function() {
completeGoalieImgA();
return;
}
goalieImgA = 'goalieAmin.png';
return goalieImgA;
}
function preloadSkaterImgB(){
var skaterImgB = new Image();
skaterImgB.onload = function() {
completeSkaterImgB();
return;
}
skaterImgB.src = 'skaterBmin.png';
return skaterImgB;
}
function preloadGoalieImgB(){
var goalieImgB = new Image();
goalieImgB.onload = function() {
completeGoalieImgB();
return;
}
goalieImgB = 'goalieBmin.png';
return goalieImgB;
}
function completeSkaterImgA(){
loadSkaterImgA = true;
return loadSkaterImgA;
}
function completeGoalieImgA(){
loadGoalieImgA = true;
return loadGoalieImgA;
}
function completeSkaterImgB(){
loadSkaterImgB = true;
return loadSkaterImgB;
}
function completeGoalieImgB(){
loadGoalieImgB = true;
return loadGoalieImgB;
}
preloadSkaterImgA();
preloadGoalieImgA();
preloadSkaterImgB();
preloadGoalieImgB();
Thank you for reading
You just need to call your preload methods after the DOM (which waits until all images are loaded) has loaded:
window.onload = function () {
preloadSkaterImgA();
preloadGoalieImgA();
preloadSkaterImgB();
preloadGoalieImgB();
}
Related
I have a custom extended property attached to the window object in JavaScript as follows:
Community.js
(function (window, document, $) {
'use strict';
var containerScrollPositionOnHideList = [];
var scrollToTopOnShowContainerList = [];
var userProfileInfo = {};
window.Community = $.extend({
//init
init: function () {
var Site = window.Site;
Site.run();
this.enableHideShowEventTrigger();
},
setUserInfo: function (userObj) {
if (UtilModule.allowDebug) { debugger; }
window.localStorage.setItem('userInfo', JSON.stringify(userObj));
var d = new $.Deferred();
$.when(this.initUserProfile(userObj.UserId)).done(function () {
d.resolve("ok");
});
},
getUserInfo: function () {
var userJson = window.localStorage.getItem('userInfo');
var userObj = JSON.parse(userJson);
return userObj;
},
})(window, document, jQuery);
The problem is that this extension property window.Community is null in certian scenarios when i refresh the page which i am going to describe below along with flow of code.
and here is a module in JavaScript to force reload scripts even if they are cached every time the page is refreshed as my code heavily depends on javascript calls so I just enabled it to make sure while I am still writing the code page reloads every time, the code is below as follows:
Util.js
var UtilModule = (function () {
var allowDebug = false;
var currentVersion = 0;
var properlyLoadScript = function (scriptPath, callBackAfterLoadScript) {
//get the number of `<script>` elements that have the correct `src` attribute
//debugger;
var d = $.Deferred();
$('script').each(function () {
console.log($(this).attr('src'));
});
if (typeof window.Community == 'undefined') {
//debugger;
console.log('community was undefined till this point');
//the flag was not found, so the code has not run
$.when(forceReloadScript(scriptPath)).done(function () {
callBackAfterLoadScript();
d.resolve("ok");
});
}
else {
console.log('Community loaded already and running now : ' + scriptPath);
callBackAfterLoadScript();
}
return d.promise();
};
var forceReloadScript = function (scriptPath) {
if (UtilModule.allowDebug) { debugger; }
var d = $.Deferred();
initCurrentVersion();
var JSLink = scriptPath + "?version=" + currentVersion;
var JSElement = document.createElement('script');
JSElement.src = JSLink;
JSElement.onload = customCallBack;
document.getElementsByTagName('head')[0].appendChild(JSElement);
function customCallBack() {
d.resolve("ok");
}
return d.promise();
};
var enableDebugger = function () {
allowDebug = true;
};
var disableDebugger = function () {
allowDebug = false;
};
var debugBreakPoint = function () {
if (allowDebug) {
}
};
var initCurrentVersion = function () {
if (currentVersion == 0) {
var dt = new Date();
var ttime = dt.getTime();
currentVersion = ttime;
}
};
var getCurrentVersion = function () {
return currentVersion;
};
return {
forceReloadScript,
properlyLoadScript,
enableDebugger,
disableDebugger,
debugBreakPoint,
allowDebug,
getCurrentVersion
};
})();
Note: I have made deferred objects to resolve only when the JSElement.onload has been called successfully. This step was taken just for testing purpose to make sure that I am not missing something before reaching a point to call the method where I am getting an error.
After that the code where I load scripts using UtilModule in my layout file look like as below:
_Layout.cshtml
<script src = "~/Scripts/Application/Modules/Util.js" ></script>
<script>
$.when(
UtilModule.properlyLoadScript('/Scripts/Application/Community.js', () => {
// Community.init() was supposed to be called here but i was still getting the error so i implemented this using promise that is returned from properlyLoadScript and call Community.init() further in .done callback to make sure that script is properly loading till this point.
//window.Community.init();
})
).done(function() {
window.Community.init();
});
</script>
#RenderSection("scripts", required: false)
Now coming to my main file where My index file is executing having (_layout.chsmtl) as parent layout
is
Index.cshtml
#{
ViewBag.Title = "My Blog";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<article id="BlogPage" style="margin: 5px;">
</article>
#section scripts{
<script type="text/javascript">
$(document).ready(function () {
$.when(UtilModule.properlyLoadScript('/Scripts/Application/Modules/Blog.js', () => {
})).done(function () {
BlogModule.init();
});
});
//});
</script>
}
from what I know is that #section scripts is executed only once all the scripts in the layout page are loaded first so seems like a safe place to initialize the code which is dependent on some script in _Layout.HTML file and further enclosed with $(document).ready() for testing just to make sure that this script loads after everything else is loaded already.
Note: I am running all this code in in-cognito mode in chrome so nothing is cached while this code is running
now my Blog.js file looks like as below
var BlogModule = (function () {
var moduleReference = this;
var PageId = "#BlogPage ";
var currentUser;
var BlogPostList = [];
var blogPostInfo = {};
//init
var init = function () {
if (UtilModule.allowDebug) { debugger; }
//This is where the problem happens
console.log(window.Community);
console.log(window.Community.getUserInfo());
currentUser = window.Community.getUserInfo();
initBlogInformation();
//window.Community.registerModule(BlogModule);
if (Object.keys(window.Community.getUserProfileObject()) <= 0) {
$.when(window.Community.initUserProfile(currentUser.UserId)).then(function () {
$.when(initBlogInformation()).done(function () {
//debugger;
console.log(BlogPostList);
window.WidgetManager.populateWidget(PageId, moduleReference);
loadBlogPostWidget();
loadBlogViewWidget();
loadBlogCommentsWidget();
});
});
}
else {
$.when(initBlogInformation()).done(function () {
window.WidgetManager.populateWidget(PageId, moduleReference);
loadBlogPostWidget();
loadBlogViewWidget();
loadBlogCommentsWidget();
});
}
};
var loadBlogIndexMenuWidget = function () {
if (UtilModule.allowDebug) { debugger; }
};
var loadBlogPostWidget = function () {
var widgetOptions = {};
widgetOptions.type = "BlogPostWidget";
widgetOptions.container = PageId + "#BlogPostWidgetContainer";
var settings = {};
settings.UserId = 1;
widgetOptions.settings = settings;
window.WidgetManager.loadWidget(widgetOptions);
}
var loadBlogViewWidget = function () {
var widgetOptions = {};
widgetOptions.type = "BlogViewWidget";
widgetOptions.container = PageId + "#BlogViewWidgetContainer";
var settings = {};
settings.UserId = 1;
widgetOptions.settings = settings;
window.WidgetManager.loadWidget(widgetOptions);
};
var loadBlogCommentsWidget = function () {
var widgetOptions = {};
widgetOptions.type = "BlogCommentsWidget";
widgetOptions.container = PageId + "#BlogCommentsWidgetContainer";
var settings = {};
settings.UserId = 1;
widgetOptions.settings = settings;
window.WidgetManager.loadWidget(widgetOptions);
};
var initBlogList = function () {
$.when(getBlogPosts()).then(function (results) {
if (UtilModule.allowDebug) { debugger; }
BlogPostList = results.Record;
console.log(BlogPostList);
});
};
var getBlogPosts = function () {
if (UtilModule.allowDebug) { debugger; }
var d = new $.Deferred();
var uri = '/Blog/GetBlogPosts?userId=' + currentUser.UserId;
$.post(uri).done(function (returnData) {
if (UtilModule.allowDebug) { debugger; }
if (returnData.Status == "OK") {
BlogPostList = returnData.Record;
BlogPostList.map(x => {
if (UtilModule.allowDebug) { debugger; }
x.UserName = window.Community.getUserProfileObject().UserName;
if (x.Comments != null) {
x.CommentsObject = JSON.parse(x.Comments);
x.CommentsCount = x.CommentsObject.length;
}
});
console.log(returnData.Record);
d.resolve("ok");
} else {
window.Community.showNotification("Error", returnData.Record, "error");
d.resolve("error");
}
});
return d.promise();
};
var initBlogInformation = function () {
//debugger;
var d = $.Deferred();
getBlogPosts().then(getBlogModelTemplate()).then(function () {
d.resolve("ok");
});
return d.promise();
};
//Get Blog Model
var getBlogModelTemplate = function () {
var d = new $.Deferred();
var uri = '/Blog/GetBlogModel';
$.post(uri).done(function (returnData) {
blogPostInfo = returnData.Record;
d.resolve("ok");
});
return d.promise();
};
return {
init: init,
};
})();
The error I have highlighted below
so the problem is in init function of BlogModule which is BlogModule.init() the page is idle for too long and I reload it I get the following error:
cannot call
window.Community.getUserInfo() of undefined implying that community is undefied
after couple of refreshes its fine and the issue doesn't happen unless I change reasonable portion of code for js files to be recompiled again by browser or the browser is idle for too long and I am not able to understand what is triggering this issue.
below is log from console
p.s. error occurs more repeatedly if i refresh page with f5 but happens rarely if i refresh page with ctrl + f5
Please any help would be of great value
Answering my own question, took a while to figure it out but it was a small mistake on my end just fixing the following function in Util.js fixed it for me
var properlyLoadScript = function(scriptPath, callBackAfterLoadScript) {
//get the number of `<script>` elements that have the correct `src` attribute
//debugger;
var d = $.Deferred();
$('script').each(function() {
console.log($(this).attr('src'));
});
if (typeof window.Community == 'undefined') {
//debugger;
console.log('community was undefined till this point');
//the flag was not found, so the code has not run
$.when(forceReloadScript('/Scripts/Application/Community.js')).done(function() {
//debugger;
$.when(forceReloadScript(scriptPath)).done(function() {
callBackAfterLoadScript();
});
d.resolve("ok");
});
} else {
console.log('Community loaded already and running now : ' + scriptPath);
$.when(forceReloadScript(scriptPath)).done(function() {
callBackAfterLoadScript();
});
}
return d.promise();
};
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;
});
}
I realize this is a common question asked by novice javascript programmers which I am. Console.log(img) and console.log("before onload") execute correctly but I never see an Image Loaded message.
AssetManager.loadImages = function(urls) {
var images = [];
var urlCount = urls.length;
for (var i=0; i<urlCount; i++) {
var img = new Image();
images.push(img);
}
var urlsLoaded = 0;
for (var i=0; i<urlCount; i++) {
(function(img) {
console.log(img);
console.log("before onload");
img.onload = function(e) {
console.log("Image Loaded!");
urlsLoaded++;
if (urlsLoaded >= urlCount) {
AssetManager.callback(images);
}
}
})(images[i]);
images[i].src = urls[i];
}
}
For anyone who made the same mistake as me - make sure onload is all lowercase and not camel case: onLoad.
This good:
img.onload = function () { };
This bad:
img.onLoad = function () { };
Try var img = document.createElement("img");
or
AssetManager.loadImages = function(urls) {
var images = new Array();
var urlCount = urls.length;
var urlsLoaded = 0;
var leImg;
for (var i=0; i<urlCount; i++) {
leImg = document.createElement("img");
leImg.onload = function(e){
urlsLoaded++;
if (urlsLoaded >= urlCount) {
// AssetManager.callback(images); --> this is balls, still
}
}
leImg.src = urls[i];
_images.push(leImg);
}
}
(not tested, and drunk)
onload doesn't fire if the image is being loaded from cache. You can use the complete property to check for this case.
if(img.complete){
// do the work
} else {
img.onload = () => {
// do the work
}
}
You can use a function to keep the code DRY.
"img.onload" function when call in nested function not work exact
you need call "img.onload" function explicit in "$().ready (function(){ }" or "window.onload = function() { }"
e.g
$().ready (function(){
var img = new Image();
img.src = 'image.png';
img.onload = function()
{
console.log("loaded");
}
}
I'm not sure what the exact problem is with your code, but here's some code I wrote awhile back to handle the same problem (fiddle: http://jsfiddle.net/LJRSL/) There's some extra stuff in there that's probably not necessary :)
$.preloadImg = function (url, callback, to_len) { //to_length = image fetch timeout in ms
var img = new Image(),
$img = $(img),
st = new Date().getTime(),
to;
if (callback && $.isFunction(callback)) {
to = window.setTimeout(function () {
callback.call(this, url, true);
}, to_len || 5000);
}
$img
.on('load', function () {
to = window.clearTimeout(to);
if ($.isFunction(callback))
callback.call(this, url, false);
})
.attr('src', url)
;
/*this is probably unnecessary*/
if (img.complete) {
$img.off('load');
if ($.isFunction(callback)) {
to = window.clearTimeout(to);
callback.call(this, url);
}
}
};
$.preloadImg('https://www.google.com/images/srpr/logo4w.png', function(img) { $('#test').attr('src', img); alert('done'); });
and for good measure loading multiple:
$.preloadImgs = function (urls, callback, to_len) {
var i = 0, c = 0;
for (; i < urls.length; i++) {
c++;
$.preloadImg(urls[i], function (url, timedout) {
if (--c === 0 && i >= urls.length - 1)
callback.call(this, urls);
}, to_len);
}
};
You might try binding your event via addEventListener instead of onload =
I faced a similar problem. I noticed that my image .onload was not being called if the page is reloaded normally, if I reloaded the page using f12 + right click reload button and chose Empty Cache and Hard Reload, the .onload was called.
So, I have this:
function isOnline(sURL) {
var bOnline,
oImage = document.body.appendChild( document.createElement("img") );
oImage.onload = function() {
bOnline = true;
};
oImage.onerror = function() {
bOnline = false;
};
oImage.src = sURL;
return bOnline;
}
... and I've had this problem before yet gotten around but I'm a little lost here. How can I get the value of bOnline to pass to isOnline at the right time? As expected, it returns undefined (initially). Any help would be appreciated.
It is always recommended to use callback functions in such situations as given below
var online = false;
isOnline("htp://....", function(){
online = true;
}, function(){
online = false;
});
function isOnline(sURL, onLoad, onError) {
var oImage = document.body.appendChild( document.createElement("img") );
oImage.onload = onLoad;
oImage.onerror = onError;
oImage.src = sURL;
}
I strongly advise you use a callback to continue your logic :
function isOnline(sURL, callbacks){
var bOnline,
oImage = document.body.appendChild( document.createElement("img") );
oImage.onerror = callbacks.error;
oImage.onload = callbacks.success;
oImage.src = sURL;
}
And instead of a call like this :
if(isOnline('some-src')) {
// good stuff
} else {
// bad stuff
}
you should use the function like :
isOnline('some-src',{
success : function(){
// yey! image is online
},
error : function(){
// eerror loading image. boo :((
}
});
If you still want to test at some point in time without using callbacks, you can return the actual image object and pin a ready or error flag on it :
function isOnline(sURL) {
var bOnline,
oImage = document.body.appendChild( document.createElement("img") );
oImage.ready = oImage.error = false;
oImage.onload = function(){
oImage.ready = true;
}
oImage.error= function(){
oImage.error = true;
}
oImage.src = sURL;
return oImage;
}
var img = isOnline('some-src');
// .. after some computing
if(img.ready) {
// yey image has loaded
} else if(img.error) {
// damn error :(
} else {
// still not loaded :-?
}
I have a class like this
var grid = function () {
this.cell = null;
this.loadImage = function () {
var image = new Image();
var object = this;
image.src = "blah";
$(image).load(function () {
object.cell = this;
});
}
this.showImage = function () {
alert(object.cell); // This should print [object Object] ... but it print null;
}
}
The showImage function is called after the image called loaded from loadImage function.
Does anyone know why object.cell is null... I have reference to this object in loadImage.
object is undefined in showImage.
This is what I think you should be doing:
var grid = function () {
this.cell = null;
this.loadImage = function () {
var image = new Image();
image.addEventListener("load", (function (obj) {
return function () {
obj.cell = this;
};
})(this));
image.src = "http://upload.wikimedia.org/wikipedia/commons/8/84/Example.svg";
}
this.showImage = function () {
alert(this.cell);
}
}