Existing Functions aren't Functions? - javascript

So I'm working on a project. My functions are working fine, until all of a sudden I click a button that should run download(), but it doesn't. So I open the console, and see this:
TypeError: download is not a function
And I'm confused. I run download() from the console, and it works fine. So I think it might be an issue with onclick (my button has onclick="download()"), so I use JavaScript to add in the click event instead.
$("#download").onclick=download()
Note: $() is a custom jQuery-esque function without using the framework itself. It's worked on a lot of other uses at the same time as this problem.
But that doesn't work either. So I also try using
$("#download").addEventListener("click", download)
That yet again doesn't work. Both times it said that $() was null. So I go out on a limb, and try using
document.getElementById("download").onclick=download()
and the same with addEventListener(). But that gives me a very surprising error message:
TypeError: document.getElementById(...) is null
I've repeated all expressions in the console and found that they aren't null. I don't click the button until the page has been loaded very several seconds.
Here is the pertinent code:
function $(el){switch(el[0]){case"#":return document.getElementById(el.substring(1));break;case".":return document.getElementsByClassName(el.substring(1));break;default:return document.getElementsByTagName(el);break;}}
function download() {
alert("download() executed")
}
// Attempted Scripts:
//$("#download").onclick = download()
//$("#download").addEventListener("click", download)
//document.getElementById("download").onclick = download()
//document.getElementById("download").addEventListener("click", download)
<a class = "nav-link nohighlight" id = "download" onclick = "download()">Download</a>
It feels like my web browser is just trying to ensure I don't run the function. I've tested this on the latest Edge and Firefox. You can see my full page here.

Look at where your script tag is in your HTML: it's above the body. Scripts by default run immediately: when the HTML parser runs across them, it immediately executes the script before moving on to parse the rest of the HTML. So, at the time your script runs, none of your elements have been created yet - so, selecting any element will fail.
Either wrap your entire script in a DOMContentLoaded listener function:
document.addEventListener('DOMContentLoaded', () => {
// put your whole script here
});
Or give your script tag the defer attribute, which directs the parser to run it only once the document has been fully parsed:
<script src = "index.js" defer></script>

Related

Only part of JQuery executable. When pasted in HTML directly everything works (window.location)

I have a JS file, which works flawlessly, and executes all the code in it.
But I now added the following JQuery:
$("#need2Know").click(function(){
window.location ="URLString";
return false;
});
$("#nice2Know").click(function(){
window.location ="URLString";
return false;
});
When I call this part of the code in the HTML file, the onclick Handling executes as expected.
However, as soon as I paste it in the JS file (above all other code, the remainder of the code still working), the onclick handling does not work anymore.
I use the following JQuery library:
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
My JQ file is called after this library.
What is so strange to me is, that the code works in HTML but not in the JS file, although the rest of the code still processes as before...
Any advice on how to fix this, so the click-handling can be performed in the JS?
Currently what you are using is called a "direct" binding which will only attach to element that exist on the page at the time your code makes the event binding call. As the DOM is not loaded yet, no event handlers are attached.
You can solve the problem by one of these methods:
Wrap the code in document-ready handler.
Specify a function to execute when the DOM is fully loaded.
$(document).ready(function() {
});
Move the reference to the file to bottom of the <body> element.
Try this code:
$("body").on("click","#nice2Know", function(){
window.location ="URLString";
return false;
});

Div is not created before javascript run

I have a question about javascript/html.
First, I have this:
var post = document.body.getElementsByClassName("post");
var x=post[i].getElementsByClassName("MyDiv")[0].innerHTML;
I get from the debugger that x is not defined, it doesn't exists.
This javascript function runs onload of the body. I am sure that I gave the right classnames in my javascript, so it should find my div.
So, I read somewhere that sometimes javascript does not find an element because it is not yet there, it is not yet created in the browser ( whatever that means).
Is it possible that my function can't find the div with that classname because of this reason?
Is there a solution?
So, I read somewhere that sometimes javascript does not find an element because it is not yet there, it is not yet created in the browser ( whatever that means).
Browsers create the DOM progressively as they get the markup. When a script element is encountered, all processing of the markup stops (except where defer and async have an effect) while the script is run. If the script attempts to access an element that hasn't been created yet (probably because its markup hasn't been processed yet) then it won't be found.
This javascript function runs onload of the body.
If that means you are using something like:
<body onload="someFn()"...>
or perhaps
<script>
window.onload = function() {
someFn();
...
}
</script>
then when the function is called, all DOM nodes are available. Some, like images, may not be fully loaded, but their elements have been created.
If it means you have the script in the body and aren't using the load event, you should move the script to the bottom of the page (e.g. just before the closing body tag) and see if that fixes the issue.
Okay, instead of calling functions with
body onload, use jQuery's ready() function, or, if you don't want to use jQuery, you can use pure javascript, but this is up to you:
// jQuery
$(document).ready(function() {
var post = document.getElementsByClassName("post"),
x = post[i].getElementsByClassName("MyDiv")[0].innerHTML;
});
// JavaScript
window.onload = function initialization() {
var post = document.getElementsByClassName("post"),
x = post[i].getElementsByClassName("MyDiv")[0].innerHTML;
}
A few side notes, I don't know what the use of innerHTML
is, and also if you're doing a for loop with i then definitely
post that code, that's kind of important.
After some discussion, my answer seems to have worked for you, but you can also place your script at the end of your body tag as #RobG has suggested.

How to execute Javascript from external HTML

If I have a button that executes the code
$('#main').load('welcome.html');
and in welcome.html I have a button that executes the code
$('#main').load('otherpage.html');
the Javascript isn't executed, regardless of whether that function is on the parent file's HTML code or the child's.
How can I get a Javascript function to work from externally loaded HTML files?
EDIT
Here's a bit more of a sample...
Homepage:
<body>
<div id="main"></div>
</body>
<script>
document.onLoad(){
$('#main').load('welcome.html');
}
function show(file){
$('#main').load(file+'.html');
}
</script>
welcome.html page:
Test
...however when the Test button is clicked, test.html is not loaded into the Main div.
EDIT 2
Here is what the current state is and what the issue is - exactly.
I've uploaded the bones of the code to PasteBin.
When the 'grid' button is clicked, the content changes and the footer changes.
However, the footer, which has URLs based on Javascript, comes up with the error:
Uncaught SyntaxError: Unexpected token ILLEGAL
...when trying to access the 1i.html page.
There's a difference between test the variable and 'test' the string:
Test
Probably should be:
Test
It is important to understand that when loading script into page via AJAX that the main page has already gone through document.ready . Thus, any code you load will fire immediately.
If the code you load precedes the html it references, it will not find that html when it fires.
Placing the code after the html in remote page will resolve this issue
Check jQuery.live() and jQuery.on().
Maybe your eventhandler is wrong. When you import new markup via load() or ajax(), you have to initialize the handlers from new document. The easiest way is using jQuery.on or jQuery.live() instead of jQuery.click().
$('MYBUTTON').live('click', function(){
$('#main').load('your_url.html')
})
or use the callbackfunction to (re-)initialize the buttons event.
A better solution is this: Just add the target_url to buttons rel attribute...
<button rel="YOUR_URL.html">Open Page</button>
$('button[rel]').live('click', function(){
$('#main').load($(this).attr('rel'));
})

Javascript: Uncaught TypeError: Cannot call method 'addEventListener' of null

I'm trying to do something fairly simple, but for the reason of me probably not being good enough to search documentation, I can't get this to work.
I have a functioning inline JS that looks like this:
<A title="Wolfram IP Calc" href="javascript:txt=prompt('Enter%20IP%20address,%20e.g.%2010.20.30.40/29','1.2.3.4/5');%20if(txt)%20window.open('http://www.wolframalpha.com/input/?i='+txt);void(O);">Compute!</A>
For various reasons, I'm trying to seperate the JS, and this is where I hit a snag.
I've created the following test page that gives me the error Uncaught TypeError: Cannot call method 'addEventListener' of null:
<HTML> <HEAD profile="http://www.w3.org/2005/10/profile"> <script type="text/javascript">
var compute = document.getElementById('compute');
compute.addEventListener('click', computeThatThing, false);
function computeThatThing() {
txt=prompt('Enter%20IP%20address,%20e.g.%2010.20.30.40/29','1.2.3.4/5');
if(txt) {
window.open('http://www.wolframalpha.com/input/?i='+txt);
}
}
</script></HEAD>
<BODY>
<A title="Wolfram IP Calc" id="compute" href="javascript:void(O);">Test</A>
</BODY>
</HTML>
The only thing I've been able to find that points to a problem like that is that addEventListener can't work with <A> but should handle <IMG> (which suits me fine as I'm going to pour this on some images), so I tried adding the following to no avail:
<img id="compute" src="http://products.wolframalpha.com/images/products/products-wa.png" />
Thanks in advance for pointing out what I'm doing wrong. It is probably glaringly obvious, but I have close to zero experience with JS and I have gone mostly by cargo culting when I've needed it until now.
Your code is in the <head> => runs before the elements are rendered, so document.getElementById('compute'); returns null, as MDN promise...
element = document.getElementById(id);
element is a reference to an Element object, or null if an element with the specified ID is not in the document.
MDN
Solutions:
Put the scripts in the bottom of the page.
Call the attach code in the load event.
Use jQuery library and it's DOM ready event.
What is the jQuery ready event and why is it needed?
(why no just JavaScript's load event):
While JavaScript provides the load event for executing code when a page is rendered, this event does not get triggered until all assets such as images have been completely received. In most cases, the script can be run as soon as the DOM hierarchy has been fully constructed. The handler passed to .ready() is guaranteed to be executed after the DOM is ready, so this is usually the best place to attach all other event handlers...
...
ready docs
Move script tag at the end of BODY instead of HEAD because in current code when the script is computed html element doesn't exist in document.
Since you don't want to you jquery. Use window.onload or document.onload to execute the entire piece of code that you have in current script tag.
window.onload vs document.onload

JavaScript TinyMCE/jQuery race condition on firefox

I have a website with a form that uses TinyMCE; independently, I use jQuery. When I load the form from staging server on Firefox 3 (MacOS X, Linux), TinyMCE doesn't finish loading. There is an error in Firefox console, saying that t.getBody() returned null. t.getBody(), as far as I understand from TinyMCE docs, is a function that returns document's body element to be inspected for some features. Problem doesn't occur when I use Safari, nor when I use Firefox with the same site running from localhost.
Original, failing JavaScript-related code looked like this:
<script type="text/javascript" src="http://static.alfa.foo.pl/json2.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.ui.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript">
tinyMCE.init({ mode:"specific_textareas", editor_selector:"mce", theme:"simple", language:"pl" });
</script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.jeditable.js"></script>
<script type="text/javascript" src="http://static.alfa.foo.pl/jquery.tinymce.js"></script>
<script type="text/javascript" charset="utf-8" src="http://static.alfa.foo.pl/foo.js"></script>
<script type="text/javascript">
$(document).ready(function(){
/* jQuery initialization */ });
</script>
I tried changing script loading order, moving tinyMCE.init() call to the <script/> tag containing $(document).ready() call—before, after, and inside this call. No result. When tinyMCE.init() was called from within $(document).ready() handler, the browser did hang on request—looks like it was too late to call the init function.
Then, after googling a bit about using TinyMCE together with jQuery, I changed tinyMCE.init() call to:
tinyMCE.init({ mode:"none", theme:"simple", language:"pl" });
and added following jQuery call to the $(document).ready() handler:
$(".mce").each( function(i) { tinyMCE.execCommand("mceAddControl",true,this.id); });
Still the same error. But, and here's where things start to look like real voodoo, when I added alert(i); before the tinyMCE.execCommand() call, alerts were given, and TinyMCE textareas were initialized correctly. I figured this can be a matter of delay introduced by waiting for user dismissing the alert, so I introduced a second of delay by changing the call, still within the $(document).ready() handler, to following:
setTimeout('$(".mce").each( function(i) { tinyMCE.execCommand("mceAddControl",true,this.id); });',1000);
With the timeout, TinyMCE textareas initialize correctly, but it's duct taping around the real problem. The problem looks like an evident race condition (especially when I consider that on the same browser, but when server is on localhost, problem doesn't occur). But isn't JavaScript execution single-threaded? Could anybody please enlighten me as to what's going on here, where is the actual problem, and what can I do to have it actually fixed?
The browser executes scripts in the order they're loaded, not written. Your immediate scripts -- tinyMCE.init(...) and $(document.ready(...)); -- can execute before the files finish loading.
So, the problem is probably network latency -- especially with 6 separate scripts (each requiring a different HTTP conversation between the browser and server). So, the browser is probably trying to execute tinyMCE.init() before tiny_mce.js has finished being parsed and tinyMCE is fully defined.
If don't have Firebug, get it. ;)
It has a Net tab that will show you how long it's taking all of your scripts to load.
While you may consider the setTimeout to be duct taping, it's actually a decent solution. Only problem I see is that it assumes 1 second will always fix. A fast connection and they could see the pause. A slow connection and it doesn't wait long enough -- you still get the error.
Alternatively, you might be able to use window.onload -- assuming jQuery isn't already using it. (Can anyone else verify?)
window.onload = function () {
tinyMCE.init(...);
$(document).ready(...);
};
Also, was that a direct copy?
<script type="text/javascript">
$(document).ready(function(){
/* jQuery initialization */ }
</script>
It's missing the ) ending ready:
<script type="text/javascript">
$(document).ready(function(){
/* jQuery initialization */ })
</script>
Missing punctuation can cause plenty of damage. The parser is just going to keep reading until it finds it -- messing up anything in between.
Since this is the first page which came in google when I asked myself the same question, this is what i found about this problem.
source
There's a callback function in tinyMCE which is fired when the component is loaded and ready. you can use it like this :
tinyMCE.init({
...
setup : function(ed) {
ed.onInit.add(function(ed) {
console.log('Editor is loaded: ' + ed.id);
});
}
});
If you are using jquery.tinymce.js then you don't need tiny_mce.js because TinyMCE will try to load it with an ajax request. If you are finding that window.tinymce (or simply tinymce) is undefined then this means that the ajax is not yet complete (which might explain why using setTimeout worked for you). This is the typical order of events:
Load jquery.js with a script tag (or google load).
Load TinyMCE's jQuery plugin, jquery.tinymce.js, with a script tag.
Document ready event fires; this is where you call .tinymce(settings) on your textareas. E.g.
$('textarea').tinymce({ script_url: '/tiny_mce/tiny_mce.js' })
Load tiny_mce.js this step is done for you by TinyMCE's jQuery plugin, but it could happen after the document ready event fires.
Sometimes you might really need to access window.tinymce, here's the safest way to do it:
$(document).tinymce({
'script_url': '/tiny_mce/tiny_mce.js'
'setup': function() {
alert(tinymce);
}
});
TinyMCE will go so far as to create a tinymce.Editor object and execute the setup callback. None of the editor's events are triggered and the editor object created for the document is not added to tinymce.editors.
I also found that TinyMCE's ajax call was interfering with my .ajaxStop functions so I also used a setTimeout:
$(document).tinymce({
'script_url': '/tiny_mce/tiny_mce.js'
'setup': function() {
setTimeout(function () {
$(document).ajaxStart(function(e) {/* stuff /});
$(document).ajaxStop(function(e) {/ stuff */});
}, 0);
}
});

Categories