I am relatively new to JavaScript and am trying to understand how to use it correctly.
If I wrap JavaScript code in an anonymous function to avoid making variables public the functions within the JavaScript are not available from within the html that includes the JavaScript.
On initially loading the page the JavaScript loads and is executed but on subsequent reloads of the page the JavaScript code does not go through the execution process again. Specifically there is an ajax call using httprequest to get that from a PHP file and passes the returned data to a callback function that in onsuccess processes the data, if I could call the function that does the httprequest from within the html in a
<script type="text/javascript" ></script>
block on each page load I'd be all set - as it is I have to inject the entire JavaScript code into that block to get it to work on page load, hoping someone can educate me.
If you aren't using a javascript framework, I strongly suggest it. I use MooTools, but there are many others that are very solid (Prototype, YUI, jQuery, etc). These include methods for attaching functionality to the DomReady event. The problem with:
window.onload = function(){...};
is that you can only ever have one function attached to that event (subsequent assignments will overwrite this one).
Frameworks provide more appropriate methods for doing this. For example, in MooTools:
window.addEvent('domready', function(){...});
Finally, there are other ways to avoid polluting the global namespace. Just namespacing your own code (mySite.foo = function...) will help you avoid any potential conflicts.
One more thing. I'm not 100% sure from your comment that the problem you have is specific to the page load event. Are you saying that the code needs to be executed when the ajax returns as well? Please edit your question if this is the case.
I'd suggest just doing window.onload:
<script type="text/javascript">
(function() {
var private = "private var";
window.onload = function() {
console.log(private);
}
})();
</script>
On initially loading the page the js loads and is executed but on subsequent reloads of the page the js code does not go through the execution process again
I'm not sure I understand your problem exactly, since the JS should execute every time, no matter if it's an include, or inline script. But I'm wondering if your problem somehow relates to browser caching. There may be two separate points of caching issues:
Your javascript include is being cached, and you are attempting to serve dynamically generated or recently edited javascript from this include.
Your ajax request is being cached.
You should be able to avoid caching by setting response headers on the server.
Also, this page describes another way to get around caching issues from ajax requests.
It might be best not to wrap everything in an anonymous function and just hope that it is executed. You could name the function, and put its name in the body tag's onload handler. This should ensure that it's run each time the page is loaded.
Depends what you want to do, but to avoid polluting the global namespace, you could attach your code to the element you care about.
e.g.
<div id="special">Hello World!</div>
<script>
(function(){
var foo = document.getElementById('special');
foo.mySpecialMethod = function(otherID, newData){
var bar = document.getElementById(otherID);
bar.innerHTML = newData;
};
//do some ajax... set callback to call "special" method above...
doAJAX(url, 'get', foo.mySpecialMethod);
})();
</script>
I'm not sure if this would solve your issue or not, but its one way to handle it.
Related
I'm creating a web application that has multiple pages of content that I'm loading dynamically with AJAX and the HTML5 History API. When a user attempts to change the page, the new content is loaded with a $.get and injected into the body, like so:
$.get("somepage.html", function (data)
{
$("body").html(data);
});
Most of these pages require additional scripts to be loaded. This wouldn't be an issue except for the fact that $(document).ready fires before these scripts are loaded. Somepage.html looks something like this.
<script src='http://getjquerysomewhere/'></script>
<script src='my_script_that_depends_on_jQuery'></script>
This issue is complicated by the fact that these pages must have the ability to be loaded on their own. I'm therefore unsure how I can eliminate the $(document).ready functions without affecting this behavior as well.
How should I approach this problem?
What you are trying to do is certainly possible, but it's not going to be very maintainable in the long-run.
One of the biggest issues you'll run into is properly injecting the code from the ajax loaded html into the current page. You can't just ignore it and let it all run because then you'll be including libraries multiple times (resulting in plugins getting overwritten/removed), and the code for the page you are loading may happen too soon due to the dom already being ready.
This pretty much leaves you with two options: dependency injection or front-loading.
Dependency injection will probably be the easiest of the two for you to implement because it requires the least amount of changes to your current code-base. All you would have to do is ensure that all pages requested with ajax only include the content of the <body> (which can be done with server-side code), and ensure that all page-specific code is included before the closing </body> of each page. Then you would just have to use the dependency-injection methods to run your code with the proper dependencies.
You could also have it only include <div id="#content">...</div> for your partials, which ever makes more sense for your use-case.
Front-loading would be a little more difficult because you'll have this one giant file that has all of your code for all of the pages, unless you use a build process (if you've never used a build-process before, you really should try it, even if you don't think you need it.) With front-loading, you'll either have to use event delegation, or have init methods for each page that you selectively execute as you load each page. This could become a maintainability nightmare without good build processes.
You can call functions from the original scripts on the page which you have loaded. For Instance you could do this in your main:
<script>
function ExternalScriptLoaded(){}
</script>
Then on your external page:
<script>
try{ ExternalScriptLoaded(); }catch(err){alert('This page was not loaded with ajax because i can't find the function');}
</script>
The alert will trigger if the script can't find the function on your main page.
i.e. call the function after you know the script has finished runnng.
Hope this helped.
Am having a problem with Yabble that I have not been able to solve.
From within my main html I load all of my js using yabble
<script>
require.setModuleRoot('./javascript/');
require.run('main')
</script>
I have a bunch of js (gamejs related). In one file I have function changeSimulationSettings(). Later within the same page I want to take user input and access the gamejs objects and change their state. The problem I am having is that I am unable to call changeSimulationSettings. It is not defined within the current context. Yabble does so much magic I am unable to find where it is defined or how to access.
<div>
<button type="button" onclick="updateSettings()">Update-Settings</button>
</div>
<script type="text/javascript">
function updateSettings(){
// access function defined in a js loaded by yabble
i.e. changeSimulationSettings()
}
</script>
All of the js is definitely being loaded as I have got functions calling each other from different files which does work. However, I am unable to call anything from js embedded within the entry web page.
Any help would be appreciated as I have been stuck on this one for hours and hours.
Thanks,
Code defined in modules is isolated and not available globally.
I would do it the other way around: from within a module attach an event handler. Do not use "onclick=" but instead in a module, where you have changeSimuSettings available, do something like this (e.g. using jquery or plain DOM):
$('button').click(changeSimulationSettings)
This is cleaner and you are not leaking globals. If you insist on doing it your way, you could export changeSimulationSettings to global and use the code you already have. Like so (I would not recommend that):
window.changeSimulationSettings = function() {...
My issue is that multiple websites are going to include my JS file and when calling something like this:
<script src="..."></script>
hello.say("yay");
there going to be a race issue so sometimes it could make it sometimes not. i know that i can solve that easily by putting every function in a window.onload but that wouldn't be clean as i've seen other websites magically solve that like google analytics:
.. Calling google analytics JS..
<script type="text/javascript">
try{
var pageTracker = _gat._getTracker("UA-xxxxxx-x"); <-- this an object !
pageTracker._trackPageview();
} catch(err) {}
</script>
How to do that?
Google Analytics uses a trick that's a perfect example of something that can only be done in duck typed languages. The main object is an array if the GA-script hasn't loaded, but if it has it changes behaviour. Let's see if I can explain it.
I pulled this piece from the source here at stackoverflow:
var _gaq = _gaq || [];
_gaq.push(['_setAccount','UA-5620270-1']);
_gaq.push(['_trackPageview']);
It looks like an array with some values being pushed to it. In fact, if _gaq is falsy when this code is run (as it is if no other analytics-JavaScript has run yet), it as an array. Then, when the main analytics script (included with a script-tag anywhere on the page) loads it examines this array and performs some task based on the contents of the array.
So, if this happens in opposite order (the main script is loaded first, and then the snippet above) the main script set _gaq to an object with a push-method that does whatever google wants it to do. Later, when the code above runs, _gaq.push doesn't just add values to an array; it actually executes arbitrary code (and doesn't push to an array at all).
Hence, regardless of which script runs first, the end result will be the same when both have finished.
If you include your file in the header part of the html page, it will be loaded before any other javascript in the page is run.
UPD: Also, I think even files included in the text of thml are downloaded before the processing of the rest of javascripts. Are you sure that is your problem in the first place?
You will need to delay the execution of any javascript code that depends on the external javascript until after the page has been fully loaded and you can do that by attaching the execution to the window.onload event.
window.onload = function() {
hello.say('yay');
}
But this has the disadvantage of only working for one function and will override any functions that have been initially attached to that event. You would want to read Simon Wilson's post and the comments for solutions on how to handle this situation.
http://simonwillison.net/2004/May/26/addLoadEvent/
I'm a bit unsure as to what you think the race issue is here.
Browsers always* execute script tags in the order they see them. If this were not true, a good portion of the internet would break - as well as pretty much every common JavaScript library in existence.
So, as long as users load your script earlier in the document than when they call its APIs, you should have no problem. The only potential exception to this I can think of is if your script's initialization relies on asynchronous logic, in which case you should think about providing a standard callback mechanism of your own for users to write their code in.
If users might load your script AFTER the point they use its APIs, then the trick Jakob alludes to in his answer would work. But I'm not even sure you're aiming for that level of complexity.
*edit: I should note, to be perfectly honest, there are specific exceptions to this, but not so long as you're simply dealing with standard non-deferred usage of <script> tags within an HTML document.
I have the following setup, and I need to know how to persist state.
1.) An external web page uses ajax to load and display a .jsp file, which contains javascript.
2.) Once this rendering is complete, javascript in the .jsp file must be called to perform an action based on the results that occurred during rendering. Specifically, the document does action on $(document).ready, and those actions dictate what must be done on later function calls.
The question I have is this: How do I persist the data and state created when the page is loaded? I tried something like this:
External:
ajax to test.jsp
Internal test.jsp
var saveMe = {};
function getsCalled()
{
saveMe = {'a':function(){return false;}};
}
function needsData()
{
//???
}
Later...
External:
needsData();
Nothing I seem to attempt is working. What would be the best way to persist state in this situation?
If you want to know about scoping read this. It might help you to work out what is going on.
Have you tried declaring saveMe outside of the $(document).ready? Then you should be able to change the value from inside the $(document).ready as well as from the external script. I'm not sure how the scoping works for javascript variables from an ajax call though, so I'm not sure if this would actually work.
Making the variable a member of the function object worked swimmingly.
I have a swf file that is not controlled by me. The swf expects a javascript call to set some variables after initialization.
The swf is embedded using the swfobject and I'm trying to call the as function right after the embed. This appears to be too soon because I get an error. Everything else should be fine since calling the as function manually via firebug does not produce the error.
So the question is how do I call the function when the embed is complete?
Are you doing this while the page is still loading? Or from am onload handler?
If it's inline javascript I would suggest doing it in the onload handler from javascript which you can do like this -
window.onload = function() {
// your code here
}
it will run your code once the page is fully loaded.
This doesn't guarentee that the flash is initialised though. You could do that by having the flash make a callback to javascript once it is ready, but you said that the swf is not in your control. All I can really think of us using the onload method to make sure the page is finished loading, and then insert a short delay before trying to use it. Look at the setTimeout javascript function for that. Not a great solution though.
I found some code for checking whether the function exists yet. In summary:
if (typeof yourFunctionName == 'function') {
yourFunctionName();
}
Does that work for you? If it does then you can just wrap in a while loop. A bit less nasty than a setTimeOut!
When integrating Flash and HTML / JavaScript, there are several common approaches, which have been designed to eliminate this problem.
Pass in the variables as flashvars. They will be available to the flash movie immediately.
When the flash has loaded, it should call out to your page, normally there is a contract that defines the methods you can / must implement for the flash movie to call. For example, it would state that it will call MovieLoaded() when the flash file has loaded, and you could then put any scripts dependent on the movie being loaded within this method...
function MovieLoaded() {
doSomething();
}