Undefined properties in localStorage's 'storage' event - javascript

The event that should be fired when localStorage is changed seems to be lacking information in Firefox.
I set up the following event handler:
function storageEventHandler(e){
alert("key " + e.key);
alert("oldValue " + e.oldValue);
alert("newValue " + e.newValue);
alert("url " + e.url);
}
window.addEventListener('storage', storageEventHandler, false);
which should be triggered by this:
localStorage.setItem('foo', 'bar');
However, all the properties in the event (e.g. e.key and everything else) are all undefined. I am using Firefox 3.16. Why are the event properties undefined?
EDIT. Here is all the code I am using. The storage event fires in Firefox 3.16 but not in Firefox 4.0b8
Also, important, I am running it from XAMPP http://localhost/index.html
Running it from file:// make it die localStorage Getting NULL?
<!DOCTYPE html5>
<html lang="en">
<head>
<script class="jsbin" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script>
$(function() {
var edit = document.getElementById('edit');
$(edit).blur(function() {
localStorage.setItem('todoData', this.innerHTML);
});
// when the page loads
if (localStorage.getItem('todoData')) {
edit.innerHTML = localStorage.getItem('todoData');
}
window.addEventListener('storage', storageEventHandler, false);
function storageEventHandler(e){
alert('localStorage event fired')
}
});
</script>
</head>
<body>
<header>
<h1> My Simple To-Do List </h1>
</header>
<section>
<ul id="edit" contenteditable="true">
<li></li>
</ul>
</section>
<em>Add some items, and refresh the page. It'll remember what you typed.</em>
</body>
</html>
EDIT #2: Here's a simpler example that shows the problem between the browsers...
<html>
<head>
<script>
function storageEventHandler(e){
alert('localStorage event fired')
}
window.addEventListener('storage', storageEventHandler, false);
localStorage.setItem('foo', 'bar');
alert('ok')
</script>
</head>
<body>
Test
</body>
</html>

Firefox 3.6 (Gecko 1.9.2) doesn't implement these properties (the specification was changing and most other browsers at the time didn't implement these properties either). This is fixed in Firefox 4 (Gecko 2). See https://bugzilla.mozilla.org/show_bug.cgi?id=501423
[edit] your testcase is a single-page. The spec says:
When the setItem(), removeItem(), and clear() methods are called on a Storage object x that is associated with a local storage area, if the methods did something, then in every HTMLDocument object whose Window object's localStorage attribute's Storage object is associated with the same storage area, other than x, a storage event must be fired, as described below.
So you need a separate page on the same domain to observe the event.

Related

Communicate between two pages / tabs

I'm wanting a JavaScript file to control two HTML files simultaneously.
<!DOCTYPE html>
<html>
<head>
<title>tryAgainPage1</title>
<meta charset="UTF-8">
</head>
<body>
<div id="page1"></div>
<script src="tryAgain.js"></script>
</body>
</html>
That's page one. Next is page two.
<!DOCTYPE html>
<html>
<head>
<title>tryAgainPage2</title>
<meta charset="UTF-8">
</head>
<body>
<div id="page2"></div>
<script src="tryAgain.js"></script>
</body>
</html>
And here is the JavaScript:
newFunction();
function newFunction() {
document.getElementById("page1").innerHTML = "page one says hello";
document.getElementById("page2").innerHTML = "page two says goodbye";
}
Page one is working, page two isn't. I've been trying for a day to get pages talking to each other, without success. I'm not sure I understand how to implement Broadcast channel in this instance (if indeed that is appropriate.) Can anyone help?
postMessage
If you're looking for a way to make two pages or tabs communicate you can take a look at:
MDN Window.postMessage, and read this postMessage article
or MDN Broadcast_Channel_API
Using Broadcast Channel API page1 — page2
How it works:
pageX subscribes to a named Broadcast Channel object
pageY broadcasts to the same Channel name using postMessage
pageX listens to "message" events and prints the Event.data
And vice-versa.
page1.html
<h1>PAGE 1</h1>
<p><button data-broadcast="Page 1 talking!">BROADCAST</button></p>
Page 2 says: <div id="page2"></div>
<script src="comm.js"></script>
page2.html
<h1>PAGE 2</h1>
<p><button data-broadcast="Page 2! 'Allo 'Allo!">BROADCAST</button></p>
Page 1 says: <div id="page1"></div>
<script src="comm.js"></script>
comm.js
var bc = new BroadcastChannel('comm');
document.querySelector("[data-broadcast]").addEventListener("click", ev => {
bc.postMessage( ev.target.dataset.broadcast );
});
const targetEl = document.querySelectorAll("#page1, #page2");
bc.addEventListener("message", ev => {
[...targetEl].forEach( el => el.innerHTML = ev.data );
});
localStorage and the storage Event
Another simple, yet cool way, if both tabs are on the same domain is by using
Window.localStorageMDN and its Storage Event.
How it works:
pageX writes to localstorage[pageX]
pageY's window will trigger a storage event
pageY can now read localstorage[pageX] or better (to make it simpler (and pageN agnostic)) the Event.newValue sent by the storage event
And vice-versa.
For starters: DEMO: page1 — page2
page1.html
<h1>PAGE 1</h1>
<textarea data-sender="page1" placeholder="Write to page 2"></textarea>
Page 2 says: <div id="page2"></div>
<script src="comm.js"></script>
page2.html
<h1>PAGE 2</h1>
<textarea data-sender="page2" placeholder="Write to page 1"></textarea>
Page 1 says: <div id="page1"></div>
<script src="comm.js"></script>
comm.js
// RECEIVER
window.addEventListener("storage", ev => {
document.getElementById( ev.key ).innerHTML = ev.newValue;
});
// SENDER
[...document.querySelectorAll("[data-sender]")].forEach( el =>
el.addEventListener("input", ev => localStorage[el.dataset.sender] = el.value )
);
Web RTC
You could use Web RTC (Web Real-Time Communications). A technology which enables Web applications and sites to capture and optionally stream audio and/or video media, as well as to exchange arbitrary data between browsers
Your main errors:
Your script was not working on one page... actually on both, the only difference was that on page 1 broke after realizing #page2 Element could not be found - Inversely on the other page broke immediately after realizing there is no "#page1" Element (since first in order).
You should always check if al element exists using if ( someElement ) { /*found!*/ } .
And yes, you cannot make communicate two pages that way. They will only share / include the same JS file.
Both pages are throwing an error, the difference is, on the first page the error doesn't happen until after the div is changed.
Here's one possible approach.
newFunction();
function newFunction() {
var page = document.getElementById("page1") ? "1" : "2";
var msg = page == "1" ? "page one says hello" : "page two says goodbye";
document.getElementById("page"+page).innerHTML = msg;
}

firefox - unable to receive event for dynamic javascript

I have some dynamic javascript that creates elements, with a click event element handler... the script is included from another domain.
However with Firefox at runtime it gives a security warning and does not process the click event (Chrome works fine).
A simplified version below
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<h2 id="headertitle">TEST</h2>
<br/>
<script type="text/javascript" src="somewhereelse.com/script.js">
</script>
</body>
</html>
Javascript include:
document.getElementById("headertitle").insertAdjacentHTML('beforeBegin',
"<button value='TEST' onclick='clickHandler(this)' >Button</button>");
function clickHandler(evt){
alert("clicked");
}
Warning Message:
Security wrapper denied access to property undefined on privileged
Javascript object. Support for exposing privileged objects to
untrusted content via exposedProps is being gradually removed -
use WebIDL bindings or Components.utils.cloneInto instead. Note that
only the first denied property access from a given global object will
be reported.
I tried your code here and it worked fine for me on Firefox 50.1.0. =/
However, I strongly recommend you use JQuery to deal with events triggered by dynamically created elements. JQuery handles the DOM differently, it's cross-browser and it's just made for this kind of situation. It may solve your problem. =D
Try and change your html to
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<h2 id="headertitle">TEST</h2>
<br/>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="somewhereelse.com/script.js">
</script>
</body>
</html>
and your JS code to
document.getElementById("headertitle").insertAdjacentHTML('beforeBegin',
'<button value="TEST" class="clickable" id="btn1">Button</button>');
$('.clickable').on('click', function() {
alert($(this).attr('id') + ' was clicked');
});
That should make it work!
Cheers! =)

IE localStorage event misfired

Within Internet Explorer 9 & 10, the localStorage implementation fires events unexpectedly (great thread here: Bug with Chrome's localStorage implementation?)
Does anybody know of a way to stop the storage event from firing on tabs that initiated the change within internet explorer?
For example the following shouldn't show an alert when the add button is clicked, but it does in IE:
fiddle: http://jsfiddle.net/MKFLs/
<!DOCTYPE html>
<html>
<head>
<title>Chrome localStorage Test</title>
<script type="text/javascript" >
var handle_storage = function () {
alert('storage event');
};
window.addEventListener("storage", handle_storage, false);
</script>
</head>
<body>
<button id="add" onclick="localStorage.setItem('a','test')">Add</button>
<button id="clear" onclick="localStorage.clear()">Clear</button>
</body>
</html>
EDIT:
On a side note, I've opened a bug with MS here. https://connect.microsoft.com/IE/feedback/details/798684/ie-localstorage-event-misfired
Maybe it won't get closed.....
Changing your script to the following prevents the handling of any storage events in the focused window.
This isn't precisely what you asked, as I believe that would require a patch to the browser, but it causes IE 9/10 to conform to the spec while having no adverse effects on other browsers (other than the global and listeners).
<script type="text/javascript" >
var focused;
window.addEventListener('focus', function(){focused=1;}, false);
window.addEventListener('blur', function(){focused=0;}, false);
var handle_storage = function (e) {
if(!focused)
alert("Storage",focused);
};
window.addEventListener("storage", handle_storage, false);
</script>
See this fiddle for the updated, conforming behavior.
Edit: The following also works and avoids the listeners at the cost of a runtime check of window focus:
<script type="text/javascript" >
var handle_storage = function (e) {
if(!document.hasFocus())
alert("Storage");
};
window.addEventListener("storage", handle_storage, false);
</script>

Store domain in local storage and call it in href

I allow the user to store a domain in local storage (e.g. http://192.168.1.104). My method of pulling the domain out of local storage is like this:
<script type="text/javascript">
domain = localStorage['domain'];
function DOMAIN(dive) {
window.location=domain+dive;
}
</script>
and I can open it like this:
CLICK HERE
or
CLICK HERE
but I can't seem to get it to allow opening in a new tab (chrome v13). It's driving me nuts, any suggestions?
Try this:
CLICK HERE
Lets see if this works for you:
CLICK HERE
Okay, I figured it out, but it's a little hacky and restless. Make a dummy html document, say /html/home.html for instance. Call the js-function inside the dummy doc:
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Ripping Status</title>
<script type="text/javascript">
domain = localStorage['domain'] || '';
function init() {
window.location=domain+'/';
document.getElementById( 'box' );
};
</script>
</head>
<body onload="init();">
<div id="box"></div>
</body>
</html>
where 'domain' is stored as, say, http://192.168.1.101. Now, call /html/home.html inside the main html document via
CLICK HERE
and it allows right click > open new tab, window, etc as you would expect.

window.opener.focus() fails in IE, and works in FireFox

i have the problem that IE cant bring up opener window when i call
opener.focus() method
window.opener.focus(); // After that, child window stay in front.
html1.htm file:
<script type="text/javascript" language="JavaScript"><!--
function toCompare() {
wCompare = window.open("html2.htm", "wCompare", "width=800,height=600,resizable=yes,directories=no,status=no,toolbar=no,menubar=0,location=no,scrollbars=yes");
wCompare.focus();
};
//--></script>
</head>
<body>
open child window
</body>
html2.htm
<script type="text/javascript" language="JavaScript"><!--
function show_Parent(url) {
window.opener.location.href = url;
window.opener.focus(); // After that, child window stay in front.
}
//--></script>
</head>
<body>
<a onclick="return show_Parent('html3.htm');">go back to parent window</a>
</body>
This works fine for me, but I have seen similar behavior. Try creating a function in the parent page that grabs it's own focus and changes the URL
html1.htm
function focusAndGo(url) {
window.focus();
// EDIT: changed document.location.href= to window.location.href=
// Reference:
// https://developer.mozilla.org/En/Document.location
// document.location was originally a read-only property,
// although Gecko browsers allow you to assign to it as well.
// For cross-browser safety, use window.location instead.
window.location.href=url;
}
and call this from html2.htm
window.opener.focusAndGo(url);
Try to blur the current window first, maybe that helps.
window.blur();
window.opener.focus();

Categories