I have a question for you regarding this code snippet:
window.location.hash=1;
$(window).on('hashchange', function() {
alert('hello');
});
The script above should do this:
set the location hash to 1
on any further change -> alert('hello')
This is the problem: why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?
How can I fix it so that it works as described?
Firstly, you ask:
why is hashchange called at the first time of the first execution? Shouldn't this script change only the hash without any alert?
To answer this, we can delve into the specification. When navigating to a new fragment (ie setting document.location.hash), the specification goes through a number of steps, one of which is:
Traverse the history to the new entry, with the asynchronous events flag set. This will scroll to the fragment identifier given in what is now the document's address.
The specification for traversing the history goes on to say:
If the asynchronous events flag is not set, then run the following steps synchronously. Otherwise, the asynchronous events flag is set; queue a task to run the following substeps.
If state changed is true, fire a trusted event with the name popstate at the Window object of the Document, using the PopStateEvent interface, with the state attribute initialized to the value of state. This event must bubble but not be cancelable and has no default action.
If hash changed is true, then fire a trusted event with the name hashchange at the browsing context's Window object, using the HashChangeEvent interface, with the oldURL attribute initialized to old URL and the newURL attribute initialized to new URL. This event must bubble but not be cancelable and has no default action.
So all of that taken together means that when you run your code, the event listener for hashchange will be added before the code in the substeps of step 14 is run and will subsequently be fired when the hash is set.
How can I fix it so that it works as described?
To fix it, you can also queue the adding of your event listener using setTimeout(.., 0):
setTimeout(function() {
$(window).on('hashchange', function() {
alert('hello');
});
}, 0);
Since you add this to the queue after setting the hash, it will be added to the queue after the task queued in step 14 above, and so the event listener only gets added after the event has been fired.
use a counter inside your code:
var counter = 0;
$(window).on('hashchange', function() {
if (counter)
alert('hello');
counter++;
});
Another way to fix it without calling setTimeout would to register the 'hashchange' event and then set the value of hash.
$(window).on("hashchange",function()
{
alert('Invoked due to hash change' + window.location.hash);
});
alert('Hash Updated');
window.location.hash = "1";
Fiddle : http://jsfiddle.net/86829ryz/10/
Related
<script>
var ohnoesEl = document.getElementById("ohnoes");
var onOhNoesClick = function(e) {
e.preventDefault();
var audioEl = document.createElement("audio");
audioEl.src = "https://www.kasandbox.org/programming-sounds/rpg/giant-no.mp3";
audioEl.autoplay = "true";
document.body.appendChild(audioEl);
};
ohnoesEl.addEventListener("click", onOhNoesClick);
</script>
In this code, I didn't understand one thing. I checked internet and StackOverflow but couldn't find anything.
I have a problem to understand event property.
Why do we put e as an argument before we use properties such as preventDefault?
How will I realize whether I should use it or not?
I have a problem to understand event property.
Well, it's not a property. All event handling functions are automatically passed a reference to the event object that represents the event currently being handled. This object can tell you quite a bit about the circumstances at the time of the event (i.e. which mouse button was clicked, what key was pressed, where on the screen the mouse was when the click happened, what object triggered the event, etc.).
Why do we put e as an argument before we use properties such as
preventDefault?
The syntax of e.preventDefault() is simply common Object-Oriented Programming syntax of: Object.method(). We are accessing the Event object that was passed into the function with the e identifier and then invoking the preventDefault method stored within that object.
It's how you get at some object-specific behavior. .preventDefault() is not a global function, you can't just call it on its own. It's only something that an event object can do, so you have to reference the object before calling the method.
As with all function arguments, you may call the argument any valid name you like, but since the object will be an event object, e, evt, and event are quite common.
How will I realize whether I should use it or not?
In your code: e.preventDefault(), indicates that the event that was triggered should not perform its built-in action, effectively cancelling the event.
You would use this technique in situations where the user has initiated some event, but your code determines that the process should not continue. The best example is with a form's submit event. If the user hasn't filled out all the required fields and then hits the submit button, we don't want the form to be submitted, so we check to see if the required fields were filled in and, if not, we cancel the submit event.
Here's an example:
// Get a reference to the link:
var link = document.getElementById("nasaLink");
// Set up a click event callback function that will automatically
// be passed a reference to the click event when it occurs. In this
// example, the event will be received as "evt".
link.addEventListener("click", function(evt){
console.clear(); // Cancel previous log entries
// Get the type of event that was received and the object that triggered it
console.log("You triggered a " + evt.type + " on :", evt.target)
// Cancelling an event is generally based on some condition
// Here, we'll make it simple and say that if you click on the
// link when the second is an even second, the navigation will be cancelled
if(new Date().getSeconds() % 2 === 0){
// Normally, clicking a valid hyperlink will navigate you away from the current page
// But, we'll cancel that native behavior by cancelling the event:
evt.preventDefault();
console.log(evt.type + " cancelled! No navigation will occur.");
}
console.log("The mouse was postioned at: " + evt.screenX + " x " + evt.screenY);
console.log("The SHIFT key was pressed at the time? " + evt.shiftKey);
console.log("\tTry clicking again, but with SHIFT held down this time.");
});
Click for NASA
The event property is an object that is passed to every event handler.
This event object then has many properties and methods you can call to manipulate the event process and action in the handler.
For instance, in the event object you have this method called preventDefault() . What does preventDefault() do? Each event is triggered by a particular html dom element in the page. Sometimes this html elements have behaviour attached to them. For instance, and <a> element has the potential of changing the browser url for a particular window. If the element that triggered the event is then an <a>, with preventDefault() you just cut the default behaviour for that <a> anchor and that will avoid an url load/change.
I recommend you find a reference for this event object and pay a read to it. So you'll become more familiar to what it is available within it.
I am wondering if there is a way to execute a JavaScript function once only on the first ever page load and then not execute on any subsequent reloads.
Is there a way I can go about doing this?
The code below will execute once the onload event fires. The statement checks if the onetime function has NOT been executed before by making use of a flag (hasCodeRunBefore), which is then stored in localStorage.
window.onload = function () {
if (localStorage.getItem("hasCodeRunBefore") === null) {
/** Your code here. **/
localStorage.setItem("hasCodeRunBefore", true);
}
}
Note: If the user clears their browsers' localStorage by any means, then the function will run again because the flag (hasCodeRunBefore) will have been removed.
Good news...
Using localStorage can be tedious because of operators and long winded function names. I created a basic module to simplify this, so the above code would be replaced with:
window.onload = function () {
if (!ls.exists('has_code_run_before')) {
/** Your code here... **/
ls.set.single('has_code_run_before', true);
/** or... you can use a callback. **/
ls.set.single('has_code_run_before', true, function () {
/** Your code here... **/
});
}
};
Update #1
Per #PatrickRoberts comment, you can use the in operator to see if a variable key exists in localStorage, so
if (localStorage.getItem('hasCodeRunBefore') === null)
becomes
if (!('hasCodeRunBefore' in localStorage))
and is less verbose and a lot cleaner.
Secondly, you can set values as you would an object (localStorage.hasCodeRunBefore = true) though it will be stored as a string, not as boolean (or whatever data type your value is).
function toBeExecutedOnFirstLoad(){
// ...
}
if(localStorage.getItem('first') === null){
toBeExecutedOnFirstLoad();
localStorage.setItem('first','nope!');
}
All JavaScript must execute every time a page loads. If the script is on the page, it will execute.
The logic that is executed within the JavaScript included on the page may execute in a different manner depending on the page state, input provided, and any other signals it receives, be it from the server or the client.
If you're using a server side language, you might choose to render a script conditionally, such as the first time a user logs in.
If you need to include the javascript irrespective of context, then you need to listen to other signals.
The simple modern solution is to make use of localStorage. localStorage can be used to store custom string values on custom key values for any given domain.
The code to make use of this would look like:
if (localStorage['...my key here...'] === '...my expected value here...') {
// The page has been visited before
} else {
// The page has not been visited before
// OR
// The user or script has cleared the localStorage value
}
localStorage['...my key here...'] = '...my expected value here...';
That's all well and good if you just need things to work on the client alone. Sometimes you might need the server to know whether or not the page has been visited before.
The (less)simple solution is to use document.cookie:
if (/(?:^|;\s*)...my key here...=...my expected value here...(?:;|$)/.test(document.cookie)) {
// the page has been visited before
} else {
// The page has not been visited before
// OR
// The user or script has cleared the cookie
}
document.cookie = '...my key here...=...my expected value here...';
If you need to defer the execution until the page has finished loading, then simply include the script in an onload callback, either by assigning the event to the window:
window.onload = function () {
// do stuff when the page has loaded
//this will override any other scripts that may have been assigned to .onload
};
or by binding the event handler to the window:
window.addEventListener('load', function () {
// do stuff when the page has loaded
}, false);
It depends on what first page load means to you. It's subjective.
If you want the function to fire once the DOM has been parsed, but only the HTML and no other external resources, bind it to the DOMContentLoaded event.
document.addEventListener('DOMContentLoaded', fn);
Otherwise, if you want to wait for external resources to be loaded and then fire the event, you should bind it to the window object's load event like so:
window.addEventListener('load', fn);
Here are some links from the Mozilla Developer Network that explain the what I just said in more detail:
https://developer.mozilla.org/en-US/docs/Web/Events/load
https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
Good luck!
I was facing something similar, the difference in my case was, I wanted to run a code whenever a new instance was being created I needed a certain code to execute, and then later for the rest of the reloads that code should not execute.
For that similar to localStorage solutions above use session storage instead:
fun_RunOnlyOnFirstPageLoad(){}
if(!$window.sessionStorage.getItem(hasRunBefore)){
fun_RunOnlyOnFirstPageLoad();
$window.sessionStorage.setItem(hasRunBefore, true);
}
using the window.sessionStorage instead stores the value only for that session.
this way once the tab is closed (session is over, that value is wiped out) and on every new instantiation, the code is executed.
Is it possible to bind functions to events on child windows?
document.getElementById('foo').onclick = function() {
var newWindow= window.open('other.html', "_blank");
newWindow.document.addEventListener("onreadystatechange", function(){
console.log('foo'); // This is never run. Can I construct the new window so that it is run "onreadystatechange"?
});
return false;
};
Note that I would like to bind an event to onreadystatechange. I wish to avoid a race condition, can I create a window, bind the events and then load the URL to avoid the race condition?
.addEventListener("onreadystatechange", ...)
Event properties start with "on". The event names on the other hand do not. I.e. it should be
.addEventListener("readystatechange", ...)
I have not tried avoiding the race condition because I know of no way to do so.
Ok, I'm not entirely sure how events and auxiliary browsing context initialization work with window.open(), the spec is quite complex there.
I'd just try setting DOM event breakpoints (chrome debugger has those) and see which events are fired in which order and then check if that works in other browsers.
That said, I think the simplest option here might to read the document.readyState property. If it's "complete" then the site is already fully loaded and no further state change event will be fired and you can execute your script directly instead of waiting for the event.
If you do this should be good to go.
var newwindow = window.open('other.html', "_blank");
var $ = newwindow.$; // add if needed
$(newwindow).bind('someEvent', function() { FunctionThatDoesSomethingInTheNewWindow });
return false;
I'm trying to execute JavaScript functions that are called when a event (for example onClick event) is performed on a web page with JavaScript code. I'm getting the function from the event like this :
var attributval = document.getElementsByTagName("a").getAttribute('onClick');
and I'm trying to execute this object (which a JavaScript function in fact) as a function (suppose we have <a onClick = alert('whatever');> on this example, I tried:
var attributval = document.getElementsByTagName("a").getAttribute('onClick');
attributval() = function(){attributval};
attributval();
but it didn't work.
A DOM attribute is not the same as a JavaScript property (even though they can have the same name onclick). You should use
var attributval = document.getElementsByTagName("a")[0].onclick;
to retrieve a function (or null) from the JS object (as opposed to getAttribute(), which will most likely return a toString() for the property).
Now, attributval() = is illegal syntax, as attributval() is not an l-value (you cannot assign to it).
attributval(); will work but without the second line (which is illegal JavaScript) it will invoke the original A element onclick handler (if one is defined) or throw an exception (if the onclick handler is null).
Skip trying to create a function around the function. Just call it:
var attributval = document.getElementsByTagName("a")[0].onclick;
attributval();
try
var attributval = document.getElementsByTagName("a")[0].getAttribute('onClick');
By using get attribute you are returning a string so your only way is to use eval(onclickString) or var fn = new Function(onClickString); fn();
attributval is simply a string, correct? If you trust this code, execute it with eval(attributval) -- however any reference to this won't work.
What you probably want is to manually trigger an event. jQuery makes that easy.
If you want to do more than a click, then Chris McDonald's answer at Is it possible to trigger a link's (or any element's) click event through JavaScript? seems to fit the bill, although you might need to heed the third comment.
I thought I'd add a short answer on how to work with events using jQuery, since it seems relevant.
// Select the link using it's ID field (assuming it has one)
var myLink = $('a#myLink')
// Add a click event to the link
myLink.on('click', function(e) {
console.log("I've been clicked!");
});
// Trigger the click event manually. This would result in the above
// function being run. Interestingly, this will not cause the browser
// to follow the link like a real click would
myLink.trigger('click');
// Remove the click event (this removes ALL click events)
myLink.off('click');
// Add a click event to the link that only runs once, then removes itself
myLink.one('click', function() {
alert("I'll only bother you once!");
});
// Add a click event that you can identify from other click events.
// This means that you can trigger it or remove it without bothering other
// click events
myLink.on('click.myClick', function() {
alert("This click event has been identified as 'myClick'");
});
// Now you can trigger it without triggering other click events
myLink.trigger('click.myClick');
// And remove it, also with no harm coming to other click events
myLink.off('click.myClick');
Hope this helps
I use a couple of functions heavily in my code. Now, as I'm looking for the source of high memory usage, I want to ensure that they're not the culprits.
Using jQuery, I bind and trigger custom events on the body element. When an event is triggered, I store it in a list of triggered events. One of the helper functions I use is called "waitfor". Here's some pseudocode:
waitfor = function(event, callback){
if(event_has_ever_been_called){
callback(); //RUN IMMEDIATELY
}
else{
//BIND CALLBACK TO RUN AS SOON AS THE EVENT IS TRIGGERED
$("body").bind(event, function(){
callback();
});
}
}
For example,
//ADD GOOGLE MAP TO PAGE
... listen for the google map 'idle' event,
... then call $("body").trigger("gmap.ready")
//ADD MARKERS AS SOON AS POSSIBLE (BUT NOT BEFORE)
waitfor("gmap.ready", function(){
//add markers
});
This seems very straightforward to me but I'm a little concerned that it (or any of my other functions that use anonymous callback functions) could be causing high memory usage.
Is this sufficient information to determine that this function is safe / not safe?
You should call one instead of bind to remove the handler after the event fires.
Otherwise, your function, and everything referenced by its closure, will stay referenced forever by jQuery's handler list.