Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to store/stash JavaScript event and reuse it later?

From https://developers.google.com/web/fundamentals/app-install-banners/#trigger-m68

let deferredPrompt;

window.addEventListener('beforeinstallprompt', (e) => {
  e.preventDefault();
  // Stash the event so it can be triggered later.
  deferredPrompt = e;
});

This code is fine, but I want to trigger the stashed event later, in a different place. To perform that, I need to store an event not just in a variable, but somewhere else.

The question: how can an event be stored with its methods?

I tried Local Storage with serialization/deserialization of an object:

> localStorage.setItem('stashed-event', JSON.stringify(e))
>
> JSON.parse(localStorage.getItem('stashed-event'))

But this approach doesn't work as expected, because it's storing only key-values and losing all event methods.

like image 272
Limon Monte Avatar asked May 22 '18 06:05

Limon Monte


3 Answers

You cannot store an event in this manner. You want to store an object. Only serializable properties are storable for such an object. Functions are not serializable in JavaScript. Functions are not serializable in many languages.

Fundamentally this is basically because when you deserialize an object, its signature can change. If you have ever programmed in java, this is similar to a deserialization error when reading in a serialized object and attempting to reconstruct an object. Because the body of a method function of an object can change in between the time the object is written to some storage and then later read, methods are not serializable. This is because when you serialize an object, it does not serialize its interface definition where methods are defined. It just stores data.

Same reason when you serialize to a json string, it drops the functions.

Instead of storing an event, store the useful information from the event in an object (or let things be implicitly dropped by stringify and use the event directly).

Which method of storage you use just depends on things not mentioned in your question. Such as how long it should be stored, whether it should be available outside of your site's origin, how much data will typically be stored, whether there is more than one object to store, etc. Based on the limited information provided in your question, you are probably fine just using either localStorage or an in memory array.

If you find the need to store hundreds of objects then indexedDB would begin to be more appropriate. But just choosing a different storage medium will have no effect whatsoever on whether you can store functions. You cannot store functions.

like image 154
Josh Avatar answered Oct 06 '22 01:10

Josh


There have been loads of talk around this as soon as I/O 2018 mentioned about handling of A2HS event being developer driven from now onwards. This is also captured in the official doc and inspired from it, there is a beautiful article explaining thoroughly how to achieve exactly this scenario. While I'd suggest to go through the complete article for proper understanding of the updated dynamics around the A2HS flow, feel free to jump onto the "The New Add To Homescreen Flow" section for your requirement.

In a nutshell, follow the following steps:

  1. Create a variable outside the scope of the beforeinstallprompt event handler.
  2. Save a reference to the beforeinstallprompt event object in the above handler.
  3. Use this later to trigger the add to homescreen prompt on demand.

The article have the complete code snippets which you can refer/reuse.

Edit: I read your question once again and realized one important aspect you might be specifically looking for, viz., using it "somewhere else". If this means you are referring to using it on a different page, then my suggestion would be to go for storing the event object in:

  1. IndexedDB which is a collection of "object stores" which you can just drop objects into. Disadvantage - Can have browser compatibility restrictions. Also, can result in large amount of nested callbacks.
  2. Or you can choose to use the "in process cache" (heap memory of your application) which doesn't require serializing either. Disadvantage - This cannot be shared across multiple servers though.

Other than this, I cannot foresee a con free solution at the moment. But will try to figure it out and possibly update the thread.

like image 21
Saurabh Rajpal Avatar answered Oct 06 '22 00:10

Saurabh Rajpal


After reading your question a few times, and the answers another few,

The question: how can any javascript Object be stored with its methods?

The answer: there is no how.

However,

Josh properly explained you can extract and store all the serializable properties, say data, from your event.

I will just add you can create an event with somehow that same data later anywhere, this new event will have all the methods any Event has, but by now probably none of use.

Obviously, even serialized in your data, properties like timeStamp, isTrusted, etc... will be overriden at creating the new event.

What you just miss / need is an EventTarget, the value of the event.target property, the reference which is lost forever when document.body unloads forever, or when serializing the event Object.

But if it is still alive, or if you know what event.target should be, like a DOM Element or any Object you can reference, from wherever you recreate the event (where?), just dispatch your event to that object, if it listens to that event.type, your brand new event should be at least heard.

Simple example from MDN EventTarget, or see EventTarget.dispatchEvent

As a comment over the extensive answer by cegfault: eval, and text source code... could be <script> text source code </script>... should your script produces a (String) script. If not you ´d probably better go further backwards to where did your script creates the unserializable things that appear in your event, and think about recreating those things, not the event.

like image 37
lucchi Avatar answered Oct 06 '22 01:10

lucchi