The problem has nothing to do with the file being external or embedded.
You've changed your code, and that's why it stopped working. You could keep your HTML code identical to the original one <h1 id="title" onclick="sayGoodbye();"> Hello </h1>
.
Since you've changed, that's the reason it's not working anymore.
When adding event listeners via Javascript's addEventListener
or jQuery's on
, you must always pass a function reference, and never a function execution. If you use the ()
, the function will be called immediately, and the returned value of it will be passed to the other function you're calling.
For example, if I do that:
function num() {
return 5;
}
console.log(num); // it will log 'function num()'
console.log(num()); // it will log 5
Since your sayGoodbye
function returns nothing, the value passed to jQuery's on
will be undefined
.
function num() {
var y = 5;
y = y + 10;
}
console.log(num); // it will log 'function num() '
console.log(num()); // it will log 'undefined'
When you put in HTML onclick="sayGoodbye();"
, you're in fact saying:
Element.onclick = function() {
sayGoodbye();
}
It automatically wrap your code into an anonymous function, and pass it as a reference to the event.
Tl;dr
Your code isn't working because you're using:
$('#title').on('click', sayGoodbye());
Which evaluates/calls the function immediately, because the parenthesis are present.
Instead, you should supply a callback function by name:
$('#title').on('click', sayGoodbye);
Or as an anonymous function:
$('#title').on('click', function() {
sayGoodbye();
});
Update
After you changing the question, it seems to be another simple problem.
Where are you defining your <script src="externalscript.js"></script>
?
You should be placing it at the same place where your embedded one was. If you've put it into the head
tag, it will be evaluated even before your h1#test
is loaded, and then, it won't find the Element, and don't add the event listener to it.
But if you really want/need to put it inside the head
tag, then, you must wrap your code into an load
event listener. If using vanilla Javascript, it would be:
document.addEventListener('DOMContentLoaded', function() {
// your code
});
But since you're using jQuery, you can use $(document).ready
:
$(document).ready(function() {
// your code
});
And there is a shorthand for it, that's just wrap into $();
:
$(function() {
// your code
});
Note: I've just realised that your biggest problem here is that you don't understand the difference between doing <h1 id="title" onclick="sayGoodbye();"> Hello </h1>
, and adding your event handler through jQuery.
Your first example is working the way you expected, because when you do:
$("#title").html("Goodbye");
$("#title").click(function() {
$("#title").html("Hello");
$("#title").off("click");
});
You're saying:
- Change the
innerHTML
property of the element with id title
to 'Goodbye'
Add a click
event handler that:
2.1 Change the innerHTML
property of the element with id title
to 'Hello'
2.2 Remove all the jQuery event handlers for the event click
So, what is going to happen:
When you click the first time
1.1 Your h1
will change to 'Goodbye'
1.2 And there will be a new click
event handler for it
When you click the second time
2.1 It will fire the same event again firstly, so your h1
will change to 'Goodbye'
2.2 There will be a new click
event handler for it
2.3 The previously event handler added on 1.2
will be fired
2.4 Then, your h1
will change back to Hello
2.5 And you remove all the jQuery click
event handlers of it
So, when you click the third time, it will be like it was when the page was loaded, because the event handler placed into the HTML code will still remains, but all the jQuery event handlers that were attached to the h1
were removed.
That said, 3rd will be the same as 1st, 4th will be the same as 2nd, and so on.
When you stop attaching the event handler into your HTML code, and start attaching it through jQuery, your code stops working because:
When you click the first time
1.1 Your h1
will change to 'Goodbye'
1.2 And there will be a new click
event handler for it
When you click the second time
2.1 It will fire the same event again firstly, so your h1
will change to 'Goodbye'
2.2 There will be a new click
event handler for it
2.3 The previously event handler added on 1.2
will be fired
2.4 Then, your h1
will change back to Hello
2.5 And you remove all the click
event handlers of it
As you can see, pretty the same as the example above. But there is one big difference: When 2.5
happens, you don't have any click
event handlers attached to the h1
anymore, since you've removed all of them there.
That happens, because when you pass only one parameter to the jQuery's off
method, you're saying "Remove all the jQuery's event handlers for that type of event" (in that case, click
). So, it will remove both the event handler attached to sayGoodBye
and the one that you've created with the anonymous function.
In the first example, it doesn't happen, because jQuery doesn't know about the event you've attached via HTML code, so it never removes it, and your code works the way you expect.
So, if you want to work with jQuery only, your code should be something like:
$(function(){
function sayGoodbye() {
$('#title')
.html('Goodbye')
.off('click', sayGoodbye)
.on('click', sayHello);
}
function sayHello() {
$('#title')
.html('Hello')
.off('click', sayHello)
.on('click', sayGoodbye);
}
$('#title').on('click', sayGoodbye);
});