Why doesn't this onload function run? - javascript

Why does the onLoad not get triggered?
function FULL_IMAGE(fimage){
document.getElementById("FULL_SRC").onLoad = function(){
offsetTop = document.getElementById("FULL_SRC").height / 2;
offsetLeft = document.getElementById("FULL_SRC").width / 2;
document.getElementById("FULL_SRC").style.marginTop="-"+offsetTop+"px";
document.getElementById("FULL_SRC").style.marginLeft="-"+offsetLeft+"px";
}
document.getElementById("FULL_SRC").src=fimage;
document.getElementById("FULL_VIEW").style.display="block";
}

sometimes when image is retrieved from browser cache, onload event would not be fired, thus you may do a little hack:
function FULL_IMAGE(fimage) {
var loaded = false;
function loadHandler() {
if (loaded) {
return;
}
loaded = true;
/* your code */
}
var img = document.getElementById('FULL_SRC');
img.addEventListener('load', loadHandler);
img.src = fimage;
img.style.display = 'block';
if (img.complete) {
loadHandler();
}
}

In my original code I used onLoad not onload... the second line of code should read
document.getElementById("FULL_SRC").onload = function(){
with a lowercase "l" in onload.

The definition of the event is found inside of a function block. While I have not referenced the ECMAScript specification, I can only guess that the function keyword associates the function body code with the FULL_IMAGE symbol and does not actually enter/execute the code. Therefore, it becomes necessary for the function FULL_IMAGE to be called from the global block in order to register the event. Alternatively, the event registration code can be placed in the global block. This is all of course assuming that a FULL_SRC id has been given to an element on the given HTML document.
Given the comment, the following has been posted:
(Option 1)
document.getElementById("FULL_SRC").onLoad = function(){
offsetTop = document.getElementById("FULL_SRC").height / 2;
offsetLeft = document.getElementById("FULL_SRC").width / 2;
document.getElementById("FULL_SRC").style.marginTop="-"+offsetTop+"px";
document.getElementById("FULL_SRC").style.marginLeft="-"+offsetLeft+"px";
}
function FULL_IMAGE(fimage){
document.getElementById("FULL_SRC").src=fimage;
document.getElementById("FULL_VIEW").style.display="block";
}
(Option 2)
function FULL_IMAGE(fimage){
document.getElementById("FULL_SRC").onLoad = function(){
offsetTop = document.getElementById("FULL_SRC").height / 2;
offsetLeft = document.getElementById("FULL_SRC").width / 2;
document.getElementById("FULL_SRC").style.marginTop="-"+offsetTop+"px";
document.getElementById("FULL_SRC").style.marginLeft="-"+offsetLeft+"px";
}
document.getElementById("FULL_SRC").src=fimage;
document.getElementById("FULL_VIEW").style.display="block";
}
FULL_IMAGE (myParameter);

Related

How to add removeEventListener in window.matchMedia?

Here is my problem:
I want to have an "addEventListener" click method only for browser size smaller than "400px". But when we resize the browser, I want to remove this method.
The format of my code is below. If I grow up the browser over 400px I continue to have the method. I want your help.
function customFunction(x) {
var cardClick = document.getElementsByClassName("card");
var inner = document.getElementsByClassName("card-inner");
if (x.matches) {
cardClick[0].addEventListener("click", cardFunction);
function cardFunction() {
// some code
// inner[0].style......
}
} else {
cardClick[0].removeEventListener("click", cardFunction);
}
}
var x = window.matchMedia("(max-width: 400px)");
customFunction(x);
x.addListener(customFunction);
"Calling removeEventListener() with arguments that do not identify any currently registered EventListener on the EventTarget has no effect."
You define new version of card Function each time you call customFunctions so you can't detach it from element because is not the same function that you attach.
function cardFunction() {
// some code
// inner[0].style......
}
function customFunction(x) {
var cardClick = document.getElementsByClassName("card");
var inner = document.getElementsByClassName("card-inner");
if (x.matches) {
cardClick[0].addEventListener("click", cardFunction);
} else {
cardClick[0].removeEventListener("click", cardFunction);
}
}
var x = window.matchMedia("(max-width: 400px)");
customFunction(x);
x.addListener(customFunction);
javascript
x.removeListener(customFunction)
check example here: https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList/removeListener

Using JQuery on a window reference?

Can you use JQuery on a window reference? I have tried the following with no luck.
function GetDiPSWindow() {
var DiPSURL = "/DiPS/index";
var DiPSWindow = window.open("", "DiPS", "toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=no,width=520,height=875");
if (DiPSWindow.location.href === "about:blank") {
DiPSWindow.location = DiPSURL;
}
return DiPSWindow;
}
function AddRecipient(field, nameId) {
// Get window
var win = GetDiPSWindow();
// Attempt 1
$(win.document).ready(function () {
var input = win.document.getElementById(field + "_Input");
input.value = nameId;
});
// Attempt 2
$(win).ready(function () {
var input = win.document.getElementById(field + "_Input");
input.value = nameId;
});
// Attempt 3
$(win).load(function () {
var input = win.document.getElementById(field + "_Input");
input.value = nameId;
});
}
Am I making a simple mistake?
EDIT For some reason, win.document.readyState is "complete". Not sure if that makes a difference.
I have also tried:
View contains:
<script>var CallbackFunction = function() {}; // Placeholder</script>
The method:
function AddRecipient(field, nameId) {
var DiPSURL = "/DiPS/index";
if (deliveryChannel === undefined) {
deliveryChannel = 0;
}
var DiPSWindow = GetDiPSWindow();
if (DiPSWindow.location.href === "about:blank") {
DiPSWindow.location = DiPSURL;
DiPSWindow.onload = function () { DiPSWindow.CallbackFunction = AddRecipient(field, nameId) }
} else {
var input = DiPSWindow.document.getElementById(field + "_Input");
input.value = input.value + nameId;
var event = new Event('change');
input.dispatchEvent(event);
}
}
The answer is.... kinda. it depends on what you are doing.
You can use jquery on the parent page to interact with a page within an iframe, however, anything that requires working with the iframe's document object may not work properly because jQuery keeps a reference of the document it was included on and uses it in various places, including when using document ready handlers. So, you can't bind to the document ready handler of the iframe, however you can bind other event handlers, and you can listen for the iframe's load event to know when it is absolutely safe to interact with it's document.
It would be easier though to just include jquery within the iframe itself and use it instead. It should be cached anyway, so there's no real detriment to performance by doing so.

Only call function once?

So I have this javascript on a project I'm working on:
<script type="text/javascript">
document.getElementById('contact').onmouseover = function ()
{
var w = 130;
function step()
{
if (w < 250)
{
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
};
</script>
I want this to run only once. After it detects a mouseover, I want it to run the function and then never run again until the page refreshes. How would I accomplish this?
I'd either use jQuery's one method or if you want to use 'plain' JavaScript you could just remove the event after the function has been triggered. Here's an example:
// Create a named function for the mouseover event
function myFunc() {
// Remove the `myFunc` function event listener once `myFunc` is run
document.getElementById('contact').removeEventListener('mouseover', myFunc, false);
var w = 130;
function step() {
if (w < 250) {
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
};
// Add an event listener to run the `myFunc` function on mouseover
document.getElementById('contact').addEventListener('mouseover', myFunc, false);
Note that if you have to support IE8 (or even earlier), you need to use ...attachEvent("onmouseover", myFunc) and detachEvent("onmouseover", myFunc); instead; you can tell by checking if the element has addEventListener:
var elm = document.getElementById('contact')
if (elm.addEventListener) {
// Use addEventListener
}
else {
// Use attachEvent
}
(Perhaps hidden away in a utility function.)
All you need to do is remove the event listener from within the listener (so that it will stop listening to the event). However, in order to remove the listener, you need a reference to it, so you can't do it with a predefined listener directly attached to mouseover. Instead, use addEventListener to attach the listener, keep the returned reference and then use removeEventListener to remove the listener from within the callback.
var contact = document.getElementById('contact');
contact.addEventListener('mouseover', tehlistener);
function tehlistener() {
// yada yada do whatever
// ...
// I think it's ok to use `this` here, but since this is so specific
// its better to be specific about which listener you want removed
contact.removeEventListener('mouseover', tehlistener);
};
Here's a link to the lovely MDN article on addEventListener.
If you are interested in using JQuery, there is a nice function called "one" that may be exactly what you need.
http://api.jquery.com/one/
Edit: Adding more code to show more of the solution:
$( "#contact" ).one( "mouseover", function() {
var w = 130;
function step()
{
if (w < 250)
{
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
});
You could just overwrite the event handler
<script type="text/javascript">
document.getElementById('contact').onmouseover = function() {
var w = 130;
function step() {
if (w < 250) {
middle.style.width = (w++) + "px";
setTimeout(step, 5);
}
}
setTimeout(step, 1500);
this.onmouseover = null;//overwrite event handler with a blank callback
};
</script>
You can use a once function.
function once(fn){
var called = false;
return function(){
if (called) {
return;
}
called = true;
return fn.apply(this, arguments);
}
}
Example:
something.onmouseover = once(function(){
// this will happen only once
});

window.onresize fires twice

I'm new to js. Please, don't kick painfully.
I have this code
window.onresize=function() {alert(1);};
When I resize any browser`s window, this function fires twice. Why? And how to rewrite this code that code will fire once.
Thanx in advance.
You need a timeout to bundle the resize events.
var res;
window.onresize=function() {
if (res){clearTimeout(res)};
res = setTimeout(function(){console.log("resize triggered");},100);
};
live Example
This event will fire multiple times in different browsers (some once you've finished the the resize, others during).
One way to get around this is to wait a certain amount of time (say half a second) after the event fires, to see if there are further updates. If not, you can proceed with the alert.
e.g.
var resizeTimer;
window.onresize = function(){
if (resizeTimer){
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(function(){
alert(1);
}, 500);
};
See it work on this fiddle.
To prevent function from "firing" the same result more than once when user resize
var doc = document; //To access the dom only once
var cWidth = doc.body.clientWidth;
var newWidth = cWidth; //If you want a log to show at startup, change to: newWidth = 0
window.onresize = function (){
newWidth = doc.body.clientWidth;
if(cWidth != newWidth){
cWidth = newWidth;
console.log("clientWidth:", cWidth); //instead of alert(cWidth);
};
};
I propose other solution because I don't like the timeouts,
`var resized;
window.onresize = function () {
if(resized){
resized = false;
}
else{
resized = true;
alert('resize');
}
};`

Adding listener for position on screen

I'd like to set something up on my site where when you scroll within 15% of the bottom of the page an element flyouts from the side... I'm not sure how to get started here... should I add a listener for a scroll function or something?
I'm trying to recreate the effect at the bottom of this page: http://www.nytimes.com/2011/01/25/world/europe/25moscow.html?_r=1
update
I have this code....
console.log(document.body.scrollTop); //shows 0
console.log(document.body.scrollHeight * 0.85); //shows 1038.7
if (document.body.scrollTop > document.body.scrollHeight * 0.85) {
console.log();
$('#flyout').animate({
right: '0'
},
5000,
function() {
});
}
the console.log() values aren't changing when I scroll to the bottom of the page. The page is twice as long as my viewport.
[Working Demo]
$(document).ready(function () {
var ROOT = (function () {
var html = document.documentElement;
var htmlScrollTop = html.scrollTop++;
var root = html.scrollTop == htmlScrollTop + 1 ? html : document.body;
html.scrollTop = htmlScrollTop;
return root;
})();
// may be recalculated on resize
var limit = (document.body.scrollHeight - $(window).height()) * 0.85;
var visible = false;
var last = +new Date;
$(window).scroll(function () {
if (+new Date - last > 30) { // more than 30 ms elapsed
if (visible && ROOT.scrollTop < limit) {
setTimeout(function () { hide(); visible = false; }, 1);
} else if (!visible && ROOT.scrollTop > limit) {
setTimeout(function () { show(); visible = true; }, 1);
}
last = +new Date;
}
});
});
I know this is an old topic, but the above code that received the check mark was also triggering the $(window).scroll() event listener too many times.
I guess twitter had this same issue at one point. John Resig blogged about it here: http://ejohn.org/blog/learning-from-twitter/
$(document).ready(function(){
var ROOT = (function () {
var html = document.documentElement;
var htmlScrollTop = html.scrollTop++;
var root = html.scrollTop == htmlScrollTop + 1 ? html : document.body;
html.scrollTop = htmlScrollTop;
return root;
})();
// may be recalculated on resize
var limit = (document.body.scrollHeight - $(window).height()) * 0.85;
var visible = false;
var last = +new Date;
var didScroll = false;
$(window).scroll(function(){
didScroll = true;
})
setInterval(function(){
if(didScroll){
didScroll = false;
if (visible && ROOT.scrollTop < limit) {
hideCredit();
visible = false;
} else if (!visible && ROOT.scrollTop > limit) {
showCredit();
visible = true;
}
}
}, 30);
function hideCredit(){
console.log('The hideCredit function has been called.');
}
function showCredit(){
console.log('The showCredit function has been called.');
}
});
So the difference between the two blocks of code is when and how the timer is called. In this code the timer is called off the bat. So every 30 millaseconds, it checks to see if the page has been scrolled. if it's been scrolled, then it checks to see if we've passed the point on the page where we want to show the hidden content. Then, if that checks true, the actual function then gets called to show the content. (In my case I've just got a console.log print out in there right now.
This seems to be better to me than the other solution because the final function only gets called once per iteration. With the other solution, the final function was being called between 4 and 5 times. That's got to be saving resources. But maybe I'm missing something.
bad idea to capture the scroll event, best to use a timer and every few milliseconds check the scroll position and if in the range you need then execute the necessary code for what you need
Update: in the past few years the best practice is to subscribe to the event and use a throttle avoiding excessive processing https://lodash.com/docs#throttle
Something like this should work:
$(window).scroll(function() {
if (document.body.scrollTop > document.body.scrollHeight * 0.85) {
// flyout
}
});
document.body.scrollTop may not work equally well on all browsers (it actually depends on browser and doctype); so we need to abstract that in a function.
Also, we need to flyout only one time. So we can unbind the event handler after having flyed out.
And we don't want the flyout effect to slow down scrolling, so we will run our flytout function out of the event loop (by using setTimeout()).
Here is the final code:
// we bind the scroll event, with the 'flyout' namespace
// so we can unbind easily
$(window).bind('scroll.flyout', (function() {
// this function is defined only once
// it is private to our event handler
function getScrollTop() {
// if one of these values evaluates to false, this picks the other
return (document.documentElement.scrollTop||document.body.scrollTop);
}
// this is the actual event handler
// it has the getScrollTop() in its scope
return function() {
if (getScrollTop() > (document.body.scrollHeight-$(window).height()) * 0.85) {
// flyout
// out of the event loop
setTimeout(function() {
alert('flyout!');
}, 1);
// unbind the event handler
// so that it's not call anymore
$(this).unbind('scroll.flyout');
}
};
})());
So in the end, only getScrollTop() > document.body.scrollHeight * 0.85 is executed at each scroll event, which is acceptable.
The flyout effect is ran only one time, and after the event has returned, so it won't affect scrolling.

Categories

Resources