I have a .htc file whose behaviour is attached to a div in my page (div#test). Within the file, there is a tag at the top, setting up the behaviour:
<PUBLIC:ATTACH EVENT="ondocumentready" FOR="element" ONEVENT="function1()" />
And throughout the file, there are calls to 'element', & this.element - which I presume are then referring to this div#test.
If I wanted to take the JS from this file, would it be possible to put into the main .html page? I've tried to make calls to the function on document load, but can't get my syntax correct.
I'm trying:
document.getElementById.('test').attachEvent(onlonad, function1());
Would appreciate any pointers, if I'm doing something basic wrong, or if anyone can tell me why doing it at all would be a bad idea! =)
You have a dot in the wrong place, you're passing an undefined variable to the function and you're calling function1() instead of passing it:
document.getElementById.('test').attachEvent(onlonad, function1());
// ^ this ^ ^ ^ and these ^^
Correct syntax would be
document.getElementById('test').attachEvent("onload", function1);
Also note that only a few elements support the onload event - images, scripts and the body (which maps to window.onload).
If you want to make calls on document load, then it's awkward in IE because it doesn't support the document ready event that other browsers support. There are ways around this, or you can use the window.onload event:
window.onload = function () {
// Code to execute when the window is loaded here
}
Related
Why does a linked JavaScript file sometimes not work when it is included at the top of the page and not at the bottom?
<script type="text/javascript" src"..."></script>
For example, if you want to manipulate DOM items, and those are not yet existing, it won't work. If the JavaScript file is included in the head, the body is not existing yet, but if you include it at the end of the body, those items are valid.
If you don't want to rely on this behaviour, you may define a callback, which is run, when the document is ready, i.e. when the whole of the DOM is loaded already.
This is what e.g. jQuery achieves with $(document).ready(function() {}), or more shortly $(function () {});. In vanilla JavaScript (using modern browsers, so IE9+) this can be achieved using
document.addEventListener("DOMContentLoaded", function() {
// code...
});
The best way to know why is it not working is by checking for JS error. Try to find out what errors you are getting when the script has been included at the top. As mentioned in the other response it can be because of DOM items. You can circumvent this issue by adding a "defer" tag to the script.
It can also be because of some JS object you are expecting to be present when this script runs. For example if your script tag is serving a JSONP request then you must have the function that processes the data. Otherwise you will get a "undefined function" error when the script runs.
JS code is executed instruction by instruction from top to bottom.
The code that calls a function needs to be under that functions definition.
This code works:
var func = function()
{
alert('it works');
};
func();
While this doesn't:
func();
var func = function()
{
alert('it works');
};
It throws an undefined error. The reason for this is that JS compiler is not aware of the func definition at the time it tries to call it.
Same goes for the JS files included in your HTML page. You can include them at the bottom as long as there are not dependencies in above sections, or, if they do not try to manipulate HTML code before page load.
So here' s the piece of code. I'm very new to JavaScript so don't be afraid to explain the obvious
$(".my-css-class").on("click", function() {
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
});
There's an element in the .jsp page that looks like this:
<i class="clickMe"></i>
I know the .jsp creates a link-icon, and that the above JavaScript is an event handler. I know that it passes these 3 values as arguments another JavaScript method:
function doStuff(prop1, prop2, obj) {
if (prop1 == 'foo') {
//do stuff with prop2
}
else{
// do stuff with obj
}
}
It all works fine. What I want to know is what exactly is going on to make it work? I can't find anything in the code that connects what the event-handler returns to the 'doStuff' java-script function.
The names are totally different, so it's not reflection, it can't be parameter matching because there's other functions with the same number and type of parameters in the file, it can't be convention based because it still works if I find/replace the name of the function to gibberish.
I guess basically I'm asking what this line is doing:
($(this).attr("data-property-1"), $(this).attr("data-property-2"), this);
tl;dr: I'm at a loss, I know how the properties get as far as the onClick event-handler's anonymous function - but how does JavaScript know to pass them as arguments the to the doStuff() function?
the onClick event is a standard event triggered on click of any clickable html element and is automatically raised by the DOM.
You are hooking in to this by listening on any matched ".my-css-class" elements for an onClick Event.
The jquery syntax ".on" has been simplified over time and allows you to hook into any number of events like "submit" - OnSubmit event , or "load" - onLoad Event
Wherever your on("click", myFunction) event hook is picked up, your myFunction will execute.
Looking at your second point...
because it still works if I find/replace the name of the function to gibberish.
The DoStuff function will be found and replaced across all files in your site? or page? or open tabs? , so therefore it must exist somewhere as "doStuff(" or "giberish(".
so when you do a global find/replace, do each one slowly, until you locate it.
Finally, when you do a view source in the browser, this should either explicitly show you the doStuff function, or at the very least give you a clue as to satelite files loaded at runtime, where you can go and investigate.
Use firebug in firefox to debug loaded resources; the ".net tab" to view external loaded resources and the html/javascript they might contain. (for example: your master page might be loading in an embeded resource that contains the doStuff method, becuase of a user or server control reference in that master page)
Also have a look at this:
http://www.developerfusion.com/article/139949/debugging-javascript-with-firebug/
You can step through the javascipt piece by peice until it hits the doStuff method.
Just remember to set at least 1 breakpoint ;-)
So, as a sort of exercise for myself, I'm writing a little async script loader utility (think require.js, head.js, yepnope.js), and have run across a little bit of a conundrum. First, the basic syntax is like this:
using("Models/SomeModel", function() {
//callback when all dependencies loaded
});
Now, I want to know, when this call is made, what file I'm in. I could do it with an ajax call, so that I can mark a flag after the content loads, but before I eval it to mark that all using calls are going to be for a specific file, then unset the flag immediately after the eval (I know eval is evil, but in this case it's javascript in the first place, not json, so it's not AS evil). I'm pretty sure this would get what I need, however I would prefer to do this with a script tag for a few reasons:
It's semantically more correct
Easier to find scripts for debugging (unique file names are much easier to look through than anonymous script blocks and debugger statements)
Cross-domain requests. I know I could try to use XDomainRequest, but most servers aren't going to be set up for that, and I want the ability to reference external scripts on CDN's.
I tried something that almost got me what I needed. I keep a list of every time using is called. When one of the scripts loads, I take any of those using references and incorporate them into the correct object for the file that just loaded, and clear the global list. This actually seems to work alright in Firefox and Chrome, but fails in IE because the load events seem to go off at weird times (a jQuery reference swallowed a reference to another type and ended up showing it as a dependency). I thought I could latch on to the "interactive" readystate, but it doesn't appear to ever happen.
So now I come asking if anybody here has any thoughts on this. If y'all want, I can post the code, but it's still very messy and probably hard to read.
Edit: Additional usages
//aliasing and multiple dependencies
using.alias("ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js", "jQuery");
using(["jQuery", "Models/SomeModel"], function() {
//should run after both jQuery and SomeModel have been loaded and run
});
//css and conditionals (using some non-existant variables here)
using.css({ src: "IEFix", conditionally: browser === "MSIE" && version < 9 });
//should include the IEFix.css file if the browser is IE8 or below
and to expound more on my response below, consider this to be file A (and consider the jquery alias from before to be there still):
using(["jQuery", "B"], function() {
console.log("This should be last (after both jQuery and B have loaded)");
console.log(typeof($));
});
Then this would be B:
using("C", function() {
console.log("This should be second");
});
And finally, C:
console.log("This should be first");
The output should be:
This should be first
This should be second
This should be last (after both jQuery and B have loaded)
[Object Object]
Commendable that you are taking on such an educational project.
However, you won't be able to pull it off quite the way you want to do it.
The good news is:
No need to know what file you are in
No need to mess with eval.
You actually have everything you need right there: A function reference. A callback, if you will.
A rough P-code for your using function would be:
function using(modules, callback) {
var loadedModules = []
// This will be an ajax call to load things, several different ways to do it..
loadedModules[0] = loadModule(modules[0]);
loadedModules[1] = loadModule(modules[1]);
// Great, now we have all the modules
// null = value for `this`
callback.apply(null, loadedModules);
}
I'm trying to work with Raphael for some SVG stuff and tried, well, with my limited knowledge, to build something beautiful ;)
I have 3 files:
1x html file and 2xjs files
html file: with an onload function ( + header,body and stuff)
window.onload=function()
{
init();
}
js File1: has the init function and a function to load js files (e.g. Raphael) and a callback to proceed after the file is loaded
function init()
{
getScripts(initTool)
}
function getScripts(callback)
{
$.when($.getScript(scripts[raphael]).then(callback)
}
function initTool()
{
$('body').append("<div id='tool'></div>");
tool=Raphael("tool",5000,5000);
$('body').append("<a href='javascript:void(0)' onclick='newElement'>New element</a>")
}
js File2: Here I have the function newElement which should add (for this example) a single path to the svg element created by Rapahel
function newElement()
{
tool.path("M10,20L30,40");
}
Unfortunately the path does not show up and I have no idea why. I tried referencing the "tool" variable before the onload in case it it related to global/local variables (wild guessing) but this also does not work. changing id's to "tool" to "tool2" for the svg element also does not work.
What else could it be? Where is my (possibly obvious) blind spot?
SHould callback not be declared as a parameter here?
function getScripts(callback)
{
$.when($.getScript(scripts[raphael]).then(callback)
}
To be honest with you I've written quite a bit of javascript and I don't quite grok variables scopes fully yet. However, when calling functions you should use parenthesis to indicate that it should be executed (there are a couple of times when you reference them without parenthesis, but that is beyond the scope of this answer).
So...
$('body').append("<a href='javascript:void(0)' onclick='newElement()'>New element</a>")
But this isn't enough to make it work, you should also declare your function like this:
var newElement = function() {
tool.path("M10,20L30,40");
}
Here is a working solution: http://jsfiddle.net/vAjG2/
(perhaps somebody can expand on why these changes are needed, I don't grasp them myself).
The problem has nothing to do with variable scope. You just need parentheses following the function name in your inline event handler. Rewrite the last line as:
$('body').append("New element")
and you'll be up and running.
However, inline event handlers are frowned upon for a whole variety of reasons. As quirksmode says: "Although the inline event registration model is ancient and reliable, it has one serious drawback. It requires you to write JavaScript behavior code in your XHTML structure layer, where it doesn't belong."
A much cleaner way to do this would separate out the markup and the script, e.g.:
<div id='tool'></div>
<a id="mylink" href='#'>New element</a>
<script>
var tool = Raphael("tool",500,500);
$('#mylink').on("click", function() {
tool.path("M10,20L30,40");
});
</script>
See this jsfiddle for this code in action.
Lastly, as a helpful hint, I would advise running your code on document ready, instead of window load, especially you're using jquery,. Document ready happens when the DOM is first constructed. Window load waits for all assets to be fully loaded, which can take awhile, and typically isn't necessary. It's long considered a best practice.
The following scenario is a problem I am having. I came to the conclusion that jQuery must not be ready when Javascript is executing by observing this scenario.
Scenario:
I have a Java application which injects Javascript script tags into the currently loaded DOM page. The following Java code runs inline Javascript which inserts jquery.js and myCode.js. myCode.js holds my Javascript codes.
browser.executeJavaScript("var head= document.getElementsByTagName('head')[0];" +
"var script= document.createElement('script');script.type= 'text/javascript';script.src= 'jquery.js';head.appendChild(script);" +
"var script4= document.createElement('script');script4.type= 'text/javascript';script4.src= 'http://myCode.js';head.appendChild(script4);");
In this Java application, I also have a buttonListener that fires a function in myCode.js in ActionPerformed();
executedJS = browser.executeJavaScript("replaceAllLinks()");
The problem that is encountered is nullPointerException at the above line when button is clicked. Accomodating for null case results in endless loop without any changes.
while(executedJS == null) browser.executeJavaScript("replaceAllLinks()");
The cause of the problem was pinpointed down to when jQuery functions, methods are present inside replaceAllLinks(); javascript function. when jQuery, methods were absent, no problems could be observed. There was not one instance of nullPointerException raised.
The only possible underlying issue would be that somehow jQuery library is not fully loaded while replaceAllLinks(); is being executed. If jQuery methods and functions were not in use, it doesn't matter and everything runs okay.
My question is then, how can I make sure that jQuery is fully loaded and available for use?
Every script relying on jQuery should be contained inside a DOM ready function. Such a function normally takes this form:
$(document).ready(function() {
/* code here */
});
and a shortcut to achieve the same thing would be:
$(function() {
/* code here */
});
Here's the documentation for further information on the ready method:
http://api.jquery.com/ready/
Declare some global variable at the end jquery.js, e.g.
window.jQueryIsLoaded=true;
and check this variable before using jQuery.
<edit>Forget this, see Salman A's comment below, should be the right answer.</edit>