0

Because StorageEvent does not work here, I want to implement an event handler by localStorage.

Assume we have a web page as follows. Any change to the input field will trigger an event, we save the new value to localStorage. JSBin

<html ng-app="app">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
  </head>
  <body ng-controller="Ctrl">
    <input type="text" ng-model="text"></input>
    <div id="console"></div>
    <script>
      var app = angular.module('app', []);
      app.controller('Ctrl', ["$scope", function ($scope) {
        $scope.$watch('text', function (newValue, oldValue) {
          var x = "nV: " + newValue;
          localStorage.setItem("messages", localStorage.getItem("messages") + "   " + x)
          debug(localStorage.getItem("messages"))
        }, false)
      }])

      function debug(msg) {
        document.getElementById("console").innerHTML += msg + "<br/>";
      }
    </script>
  </body>
</html>

And we have another web page that listens. It scans localStorage by setInterval. It is actually a pipe: several messages can be stored in localStorage, and we should treat them all and then empty localStorage. JSBin

<html>
  <body>
    <div id="console"></div>
    <script>
      var listen = setInterval(function () {
        var m = localStorage.getItem("messages");
        if ((m !== "") && (m !== undefined)) {
          localStorage.setItem("messages", "")
          treatMessages(m);
        }
      }, 100)

      function treatMessages(messages) {
        debug(messages)
      }

      function debug(msg) {
        document.getElementById("console").innerHTML += msg + "<br/>";
      }
    </script>
  </body>
</html>

But what is important, is that we should make sure that no message is missed by the receiver. Unfortunately, it is not the case for the moment, For example, I typed quickly 123456789 in the input field, then 12345 was missing on the side of the receiver. It is probably because the sender generated 12345 just after the receiver read the localStorage and before the receiver emptied the localStorage.

So does anyone know how to fix this? Should we have a semaphore for localStorage or is there any other workaround?

enter image description here

Edit 1: I tried to add a semaphore by lock and waitfor: the sender and the receiver, but it still can miss messages. For example, 123456 is missing in the example below. It is not surprising, I think it is because when lock is free, we entered simultaneously the callback of the 2 waitfor, then it messed up.

enter image description here

Edit 2: I have done another shot which is supposed to work better, but I don't know why the two pages cannot align their localStorage value: the sender and the receiver

SoftTimur
  • 5,630
  • 38
  • 140
  • 292
  • So just to get this straight, you want to capture all of these values on website 2: 1,12,123,1234,12345,123456,1234567,12345678,123456789. And not: 1,2,3,4,5,6,7,8,9 right?? Or do you just want 123456789? – S. Walker Jun 22 '17 at 23:16
  • Yes, all of `1,12,123,1234,12345,123456,1234567,12345678,123456789` that the sender sends... – SoftTimur Jun 22 '17 at 23:17
  • One more question. Is this assumption correct: You want to attach an event handler to a textbox in another window, using local storage? – S. Walker Jun 22 '17 at 23:38
  • I want to implement an event sender and listener by using localStorage, the text field is just an example. – SoftTimur Jun 22 '17 at 23:39
  • Ah. Would it be harmful to wait until the listener has read the value before sending it a new value? – S. Walker Jun 22 '17 at 23:42
  • This mechanism is fine as well, do you have a neat way to implement this? – SoftTimur Jun 22 '17 at 23:43
  • Not neatly. You could use 2 values in local storage. 1 representing the message, 1 representing if the listener has captured that message. If the listener has not captured the message, but another message is being raised, push that message onto a que. Use a timeout to pop messages off the que to the listener. – S. Walker Jun 22 '17 at 23:49
  • The sender needs to have a listener to the `1 representing if the listener has captured that message`. It is like adding a semaphore. I think that will work, but I would prefer a code that works. – SoftTimur Jun 22 '17 at 23:55

2 Answers2

1

Try the newer IndexedDB. https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Using_IndexedDB. It is more sophisticated/complex. It is now broadly supported: http://caniuse.com/#search=indexeddb.

I believe it can solve your issue above (missed messages), but there is no changeEvent. I also believe it will not be able to see changes across browser (WebKit) instances on Mac (e.g. Excel for Mac) due to caching, but should work across tabs.

Andrew Hall
  • 549
  • 6
  • 17
0

I suggest using localDataStorage to fire the events for you, for each key value addition, deletion or change. It even reports these events in a single page/tab! This utility can transparently set/get any of the following "types": Array, Boolean, Date, Float, Integer, Null, Object or String (no conversion needed).

[DISCLAIMER] I am the author of the utility [/DISCLAIMER]

Once you instantiate the utility, the following snippet will allow you to monitor the events:

function localStorageChangeEvents( e ) {
    console.log(
        "timestamp: "     + e.detail.timestamp + " (" + new Date( e.detail.timestamp ) + ")" + "\n" +
        "key: "           + e.detail.key     + "\n" +
        "old value: "     + e.detail.oldval  + "\n" +
        "new value: "     + e.detail.newval  + "\n"
    );
};
document.addEventListener(
    "localDataStorage"
    , localStorageChangeEvents
    , false
);
Mac
  • 1,432
  • 21
  • 27