I am quite new to JavaScript programming and I'm trying to create some scripts that would save me time in maintaining one of my websites.
Now I have two functions in the same script that I'm calling from the head of my document and I'm trying to get them both to load at the same time with an onload event handler. I am doing that with window.onload command in my script (I want to make my script as unobtrusive as possible so I'm just calling the script in the header).
The problem is that only the first function loads and the second one doesn't. Can both functions be called with:
window.onload=function(){
function1();
function2();
}
or is there a different code I need to use to accomplish this?
I would really appreciate it if you could make your explanations as simple as possible as I am very new to JavaScript and programming in general.
P.S. If more than one function can't be loaded with onload, could you please explain to me why this is the case so I know in the future.
Ok, I see by the answers that my question probably left too much for assumption so here is the entire code of the functions I am trying to call (this is the script I am calling in the head of my html document):
I was trying to avoid putting the code here because my variables are written in Serbian language (as I am from Serbia), but I hope that you will still be able to look through it without much confusion.
In the code below I am calling at the bottom of the script two functions (lista() and ostale()) and the moveover() function is just a helper function called by the lista() function.
In essence the first one (lista()) lists through all elements of div "boje" (in English translated to "colors") and depending on the color the user hovers their mouse over, the background image changes. It also adds a few attributes to those image elements that the user is supposed to hover over.
The second one (ostale() (Translated to English "others") is supposed to only add attributes to the rest of the color images that are not supposed to do anything if the user hovers over them.
But when I open the page in localhost it doesn't show in Firefox's inspect element that any attributes have been added to the images within the div "ostale".
function lista()
{
var boje = document.getElementById('boje');
var broj = boje.childNodes.length;
for(i=1; i<broj; i++)
{
var stavka = boje.childNodes.item(i);
stavka.setAttribute("id", i);
stavka.setAttribute("onmouseover", "moveover(src)");
stavka.setAttribute("alt", "Boja");
stavka.setAttribute("class", "boja");
stavka.hspace="2";
stavka.height="23";
}
}
function moveover(adresaBoje)
{
var izvor = adresaBoje;
var slika = izvor.slice(0, izvor.length-4);
var pocetak = "url(";
var ekstenzija = ".jpg)";
var novaSlika = pocetak.concat(slika, ekstenzija);
document.getElementById('slika').style.backgroundImage=novaSlika;
}
function ostalo(){
var ostaleboje = document.getElementById('ostale');
var ostalebroj = ostaleboje.childNodes.length;
for(n=1; n<ostalebroj; n++)
{
var ostalestavka = ostaleboje.childNodes.item(n);
ostalestavka.setAttribute("alt", "Boja");
ostalestavka.hspace="2";
ostalestavka.height="23";
}
}
window.onload=function(){
try
{
lista();
ostalo();
}
catch(err)
{
alert(err);
}
}
After I try to load the page it alerts me with an error: "TypeError: stavka.setAttribute is not a function".
This is the html document I am trying to manipulate:
<div id="slika" style="background-image: url(images/nova_brilliant/1.jpg)">
</div>
<div id="tekst">
<h1>Nova Brilliant</h1>
<div id="sadrzaj">
<p>Pređite mišem preko željene boje da biste videli kako izgleda ova kuhinja u toj boji:</p>
<div id="boje">
<img src="images/nova_brilliant/1.gif"><img src="images/nova_brilliant/2.gif"><img src="images/nova_brilliant/3.gif">
</div>
<p>Ostale dostupne boje:</p>
<div id="ostale">
<img src="images/nova_brilliant/4.gif"><img src="images/nova_brilliant/5.gif"><img src="images/nova_brilliant/6.gif">
</div>
</div>
</div>
I ran into the same problem. I came across a couple of help but this one was easy to understand and it worked for me:
window.addEventListener("load", func1); window.addEventListener("load", func2);
just like #Quentin You can read more about it here
Yes you can. However, if the first goes wrong, the second won't fire.
Use this to catch errors:
try { //try executing the functions
function1();
function2();
}
catch(error) { // If there's an error
alert(error); // alert the error.
}
It is a good practice to put try and catch when experimenting with javascript.
Edited: Sorry i confused childNodes[] with childNodes.item().
By the way, I tried something like this, and it works just fine:
<head>
<script>
window.onload = function() {
div = document.getElementById("someDiv");
length = div.childNodes.length;
first();
second();
}
function first() {
for(var i=0;i<length;i++) {
var set = div.childNodes.item(i);
set.setAttribute("name", "span " + (i+1));
}
}
function second() {
for(var i=0;i<length;i++) {
name = div.childNodes[i].getAttribute("name");
console.log(name);
}
}
</script>
</head>
<body>
<div id='someDiv'><span id='span1'></span><span id='span2'></span></div>
</body>
UPDATE: I found the error:
Actually there's nothing wrong with your code. It works just fine, however, the last item of boje is empty space, which means, a text node. That's why the error keeps showing up. Change for(i=1; i<broj; i++) with for(i=1; i<broj-1; i++) and everything should be good.
Can both functions be called with
Yes. If you add event handlers by assigning to DOM properties, then you can only assign a single function to each but that function can call other functions.
However, if you do that and the first function throws an error then the second function won't fire at all. It will also discard the context and arguments, as they won't be passed to the called functions.
You could work around those problems like so:
window.onload=function(){
try {
function1.apply(this, arguments);
} catch (e) { }
try {
function2.apply(this, arguments);
} catch (e) { }
}
or is there a different code I need to use to accomplish this?
You should use addEventListener instead. That avoids the need to fiddle with apply, and protects you from errors being thrown. See the MDN events documentation for more details.
window.addEventListener('load', function1);
window.addEventListener('load', function2);
Related
I am having some trouble wrapping my head around this. I have a web application that is almost entirely built with javascript. It starts out with a basic template, then starts adding content to it as the user interacts. I am trying to use Greensock as the animation library which has the ability to use a progress slider to show how far you are in the animation, see the second box here: https://greensock.com/timelinemax
The issue is that it uses a callback onUpdate that is supposed to run that function on each frame. Then I can use it to make the slider track with the animation.
var mainTL = new TimelineLite({onUpdate:updateSlider});
function updateSlider() {
sliderTimeline.noUiSlider.set( mainTL.progress());
}
This would work - except that the slider object doesn't exist yet. I don't know why, this is some of the last code to be included in the file, but I get a couple errors in the console log just loading the page `ReferenceError: sliderTimeline is not defined' but then everything works.
To try getting away from those errors, I tried to do it like this:
var mainTL = new TimelineLite({onUpdate:updateSlider});
$( document ).ready(function() {
function updateSlider() {
sliderTimeline.noUiSlider.set( mainTL.progress());
}
});
except now it fails because the updateSlider' function hasn't been defined, and it fails to start at all. I could put them both in a$( document ).ready(function()`, but then they become local functions / variables and the 5 other javascript files I am working with don't have access to them.
Do I have to live with the errors, or is there something I am not thinking of?
You can check whether sliderTimeline exists before trying to call it. For example change function updateSlider() to:
function updateSlider() {
if (typeof sliderTimeline !== 'undefined') {
sliderTimeline.noUiSlider.set( mainTL.progress());
}
}
Or if you know that sliderTimeline is declared, but not assigned yet:
function updateSlider() {
if (sliderTimeline) {
sliderTimeline.noUiSlider.set( mainTL.progress());
}
}
Note that this works because onUpdate is called frequently, so it will eventually be called when sliderTimeline is eventually defined.
Edit:
Additionally, you can assign global variables inside $( document ).ready() as long as you declare them outside of the function.
For example:
var mainTL;
var updateSlider;
$( document ).ready(function() {
updateSlider = function () {
sliderTimeline.noUiSlider.set( mainTL.progress());
};
mainTL = new TimelineLite({onUpdate: updateSlider});
});
If you look at their codepen page http://codepen.io/GreenSock/pen/FnsqC/ they have:
var tl = new TimelineMax({delay:0.5, repeat:3,
repeatDelay:2, onUpdate:updateStats,
onRepeat:updateReps, onComplete:restart});
function updateReps() {
reps++;
repeatCount.innerHTML = reps;
}
function updateStats() {
time.innerHTML = tl.time().toFixed(2);
totalTime.innerHTML = tl.totalTime().toFixed(2);
progress.innerHTML = tl.progress().toFixed(2);
totalProgress.innerHTML = tl.totalProgress().toFixed(2);
}
Meaning that you need to define the callback function of onUpdate.
Good afternoon everyone;
I am working with processingjs and I realize one characteristic feature of processingjs;
I have a sketch file called mysketch1.pde and inside of my sketch I just declared int x=5; for test purposes. Thus, mysketch1.pde includes a method called getX() which is a getter for x value.
Lets say, I want to reach this value and print it on my web page. If I write my java script like that I have a problem;
<script type="text/javascript">
var mysketch = Processing.getInstanceById("mysketch1");
if(mysketch==null){
window.alert("it is null");
}
else
window.alert(mysketch.getX());
</script>
In this code mysketch variable returns null all the time. (I am including my sketch before javascript on the head section)
However, If I put a button to my web page and call the same code as function it works perfectly;
<script type="text/javascript">
function click(){
var mysketch = Processing.getInstanceById("mysketch1");
if(mysketch==null){
window.alert("it is null");
}
else
window.alert(mysketch.getX());
}
</script>
<button type="button" onclick="click()">place</button>
I assume this stuation happends because somehow javascript works before my .pde file is loaded.I would like to display value of X after .pde is loaded automatically. Do you know how can I cope with this problem?
Regards,
You should put your code on the window.onload event:
window.onload = function () {
var mysketch = Processing.getInstanceById("mysketch1");
if (mysketch === null) {
window.alert("it is null");
} else {
window.alert(mysketch.getX());
}
}
One way to get around this would be to poll the getX() function until the sketch becomes ready, like setting a timeout to wait until the variable is not null. This approach could also be used to check when the sketch in general is ready, like having a function isReady(){ return true;} and waiting until it is not null to run the rest of your script.
Once the buttons are created, is there anyway I can add a link or use window.location method like this: `window.location = 'nextpage.html?foo=number'. I currently have this
var typeValue = location.search;
var typeStringValue= typeValue.replace("?type=","");
var containers = typeValue.replace("?type=multi","");
var containersValue = parseInt(containers);
var sampleLetter = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
function createButton(buttonName){
var buttonDivBlock = document.getElementById("sampleSets");
var buttonElement = document.createElement("input");
buttonElement.setAttribute("type","button");
buttonElement.setAttribute("name",buttonName);
buttonElement.setAttribute("value","Sample Set"+" "+buttonName);
buttonElement.setAttribute("id",buttonName);
buttonDivBlock.appendChild(buttonElement);
// document.getElementById(sampleLetter[i]).setAttribute('onclick',window.location='SampleInfo.html'+typeStringValue+bottonName);<!--add the button link -->
}
function setButtons(numberOfContainers){
for(i=0;i<numberOfContainers;i++){
createButton(sampleLetter[i]);
}
}
window.onload = function(){
setButtons(containersValue);
}
But document.getElementById("'"+sampleLetter[i]+"'").setAttribute('onclick',window.location='SampleInfo.html'+typeStringValue+bottonName);<!--add the button link -->
returns a null value.
Well, maybe I can help you along with an example:
function getFive() { return 5;}
callOtherFunction("stringArgument", getFive());
The second argument to callOtherFunction is going to be 5, not the getFive function. In many cases, like adding event listeners and AJAX code, you actually want to pass the function itself as an argument, so it can be called later. But if you don't want to bother declaring that function seperately, it looks like this:
callOtherFunction("stringArgument", function() { return 5; });
To make code look cleaner, you can press Enter after the { and make a multi-line function.
Now, all that in mind, take another look at the line you've commented out. Do you see what's missing? (PS. Apologies for the "egging-on" format - I find people get much better at figuring things out if I help them find the solution, rather than just showing it to them)
The sampleLetter variable is not defined where you are trying to use it (judging by commented code). Use the value you had just set to the id attribute a few lines earlier.
document.getElementById(buttonName).setAttribute( /* ... */ );
Or if you are trying to set it in the loop instead of in the createButton function, do not add the single quotes
document.getElementById(sampleLetter[i]).setAttribute( /* ... */ );
My requirements are the following:
I've got a rich webpage that at a certain moment loads a bunch of HTML in a div, via AJAX.
The HTML I retrieve does have javascript (<script>...</script>)
The retrieved javascript contains $('document').ready( ... ) parts
I can not modify the retrieved javascript; it comes from an external lib
I've got a javascript function that is called when the AJAX is loaded. I'm trying to "trick it" into executing by doing:
function AjaxLoaded() {
$('document').trigger('ready');
}
That doesn't cut it, I'm afraid.
I've seen several responses on Stack Overflow that "evade" this question by changing the code that is returned on the AJAX (make it a function and call it after loading, or just remove the $(document).ready()). I need to stress out that I can't change the retrieved code on this case.
Afer some research i created a way to get it to work.
here is my test that shows it working: http://www.antiyes.com/test/test2.php
here is the relevant code:
<script>
// easy copy of an array
Array.prototype.copy = function() {
return [].concat(this);
};
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
if(this.readyList != null)
this.myreadylist = this.readyList.copy();
return this.myreadylist;
};
$(document).ready(function() {
alert("blah");
});
</script>
<script>
// this should be added last so it gets all the ready event
$(document).ready(function() {
readylist = $.getReadyList();
});
</script>
then in the body I have:
<input type="button" onclick="$(readylist).each(function(){this();});" value="trigger ready" />
basically what i did was add a function to jQuery that copies the readyList before it's cleared out, then it will be available to be used by you.
it looks like the code below doesnt work:
function AjaxLoaded() {
$(document).trigger('ready');
}
drop the quotes around document.
Since the jQuery readyList is not exposed as of version 1.4 (discussed here) the nice solutions above are broken.
A way around this is by creating your own readyList, through overriding the original jQuery-ready method. This needs to be done before other scripts that use the original ready method are loaded. Otherwise just the same code as John/Kikito:
// Overrides jQuery-ready and makes it triggerable with $.triggerReady
// This script needs to be included before other scripts using the jQuery-ready.
// Tested with jQuery 1.7
(function(){
var readyList = [];
// Store a reference to the original ready method.
var originalReadyMethod = jQuery.fn.ready;
// Override jQuery.fn.ready
jQuery.fn.ready = function(){
if(arguments.length && arguments.length > 0 && typeof arguments[0] === 'function') {
readyList.push(arguments[0]);
}
// Execute the original method.
originalReadyMethod.apply( this, arguments );
};
// Used to trigger all ready events
$.triggerReady = function() {
$(readyList).each(function(){this();});
};
})();
I'm not sure whether it is advisable to override the ready method. Feel free to advise me on that. I have not yet found any side effects myself though.
Just in case anyone needs it, I refined John's solution a bit so it could be used directly as an included javascript file.
// jquery_trigger_ready.js
// this function is added to jQuery, it allows access to the readylist
// it works for jQuery 1.3.2, it might break on future versions
$.getReadyList = function() {
if(this.readyList != null) { this.myreadylist = [].concat(this.readyList); }
return this.myreadylist;
};
$(document).ready(function() {
readylist = $.getReadyList();
});
$.triggerReady = function() {
$(readylist).each(function(){this();});
}
Including this file after including jquery allows for triggering ready by invoking $.triggerReady(). Example:
<html>
<head>
<title>trigger ready event</title>
<script src="test2_files/jquery-1.js" type="text/javascript"></script>
<script src="jquery_trigger_ready.js" type="text/javascript"></script>
</head>
<body>
<input onclick="$.triggerReady();" value="trigger ready" type="button">
<script type="text/javascript">
$(document).ready(function(){
alert("blah");
});
</script>
</body>
</html>
By the way, I wanted to make it $(document).triggerReady(). If anyone is willing to share some advice on that, ill be appreciated.
We had the same problem and solved it another way.
Instead of
$(document).ready(function () {
$('.specialClass').click(....
We used :
$(document).bind('ready', function(event) {
$('.specialClass', event.target).click(..
jQuery will trigger a "ready" event on the document as usual. When we load the content of a new div via ajax, we can write:
loadedDiv.trigger('ready')
And have all the initialization performed only on the div, obtaining what expected.
Simone Gianni's Answer I think is the most elegant and clean.
and you can even simplify it to become even more easy to use:
jQuery.fn.loadExtended = function(url,completeCallback){
return this.load(url,function(responseText, textStatus, XMLHttpRequest) {
if (completeCallback !== undefined && completeCallback !== null) {
completeCallback(responseText, textStatus, XMLHttpRequest);
}
$(this).trigger("ready");
});
};
So, now instead of using:
$(".container").load(url,function(responseText, textStatus, XMLHttpRequest) {
$(this).trigger("ready");
});
you can just use:
$(".container").loadExtended("tag_cloud.html");
or:
$(".container").loadExtended("tag_cloud.html",function(){
alert('callback function')
});
This has the advantage of only applying the trigger on the div that's being updated.
If your new loaded HTML contain <script> elements and you try insert it into main HTML with pure JS (element.innerHTML = newHTML), then $(document).ready handlers at newHTML and wrapped functions like (function() { /* some functions */ })(); - will not execute because JQuery unbind 'ready' event after first triggering and you can not trigger it repeatly. PS. But you can use $.holdReady(true) and trigger when need.
So, try insert code with jquery method, $(element).html(newHTML). This solved similar problem for me, seems jquery handle js before inserting. Using this method you also will not see the <script> elements among DOM nodes (at browser's Elements Inspector for ex.)
I am having trouble with some JavaScript running before the page is completely rendered in IE 6 (maybe other versions too but just testing IE6 for now. Firefox seems to be OK). I can get around this by calling the js on window.onload like this:
window.onload = function(){doIt();}
However, my concern is the fact that I will overwrite anything else that may already be in window.onload. The code will be used as part of a library so I can not guarantee that window.onload will not be set somewhere else by someone else. I would rather append my function to the onload event like this:
window.onload += function(){doIt1();}
window.onload += function(){doIt2();}
But when I do so, only doit2() is called. Is there a way to register an event handler for when the page is fully rendered? My second thought would be to just put my code in a loop checking to make sure all my objects exist before running. But I am scared that this could potentially lockup the browser.
Just for some background info, my code is hiding/showing iFrames. I know that I can use the iFrame's onload attribute but I need all of the iFrames to be fully loaded before calling the code.
Any thoughts from the community? Thanks in advance for you input.
Use this generic addLoadEvent function...
function addLoadEvent(func) {
if(typeof window.onload != 'function')
window.onload = func;
else {
var oldLoad = window.onload;
window.onload = function() {
if(oldLoad) oldLoad();
func();
}
}
}
This essentially queues up functions to be executed. It never overwrites a previously assigned handler. Sample usage below...
addLoadEvent(function() { alert("One!"); });
addLoadEvent(two);
function two() {
alert("Two!");
}
I want to mention that libraries like jQuery take care of known issues like this for you.