1

I would like to record all events that are fired through user action on DOM elements. A feature like recording user actions (macro) on my website so the app can later re-generate the current state by executing use actions sequentially. How to do it?

Is there any API or solution to find all events that are processed by event listeners? Or should I gather events by myself? If so, what would be your approach/solution/design?

this OP says no: https://stackoverflow.com/a/63346192/5078847

Ali Khosro
  • 1,580
  • 18
  • 25
  • What do you need it for? How do you expect it to use? If you want it for tests automation, you can use [playwright codegen](https://playwright.dev/docs/cli?_highlight=codegen#generate-code). Otherwise your question already answered [here](https://stackoverflow.com/questions/27321672/listen-for-all-events-in-javascript/48388878) and [there](https://stackoverflow.com/questions/5107232/is-it-possible-to-programmatically-catch-all-events-on-the-page-in-the-browser) – Mr. Hedgehog Mar 07 '21 at 21:51
  • I want it for production. No test or debug. I want to know "user entered this input in el1, then selected buttonX, and then hit buttonY." When this user shares this link with a friend (or later comes back), I can re-generate that state as it was left. – Ali Khosro Mar 07 '21 at 22:23

2 Answers2

2

It would be technically possible to record such a thing by

(1) using addEventListener exclusively in your site's code (if you don't, you'll have to also iterate through all on- properties and scan for inline handlers too, which is quite a pain)

(2) Overwrite the addEventListener prototype with a custom hander that, when fired, stores information uniquely identifying the click in an array (for example, save the name of the event fired, and a full selector string to the element the event is dispatched to, and if you need it, also the amount of time since the page was loaded)

(3) When needed, save the array somewhere

(4) To emulate the user's prior actions, retrieve the array, then iterate through it. For each action, create and dispatch an event to the unique selector at the time required.

But this is really, really convoluted. It would make a lot more sense for there to be a single source of truth for what's being displayed on your page. To save a state, just serialize the object that holds the data. To resume a state, retrieve the object and render according to its contents.

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
1

There isn't anything built in, like the other post said. Chrome devtools has a function getEventListeners that gets all the handlers for a given element (singular). You also can't use this outside of Chrome's devtools.

You could (but shouldn't) hijack addEventListener from the prototype chain.

Based off of this old forum here

/** !! Foot-Gun !! **/
/** Proof of Concept/Probably Doesn't Work **/
HTMLElement.prototype._addEventListener = HTMLElement.prototype.addEventListener;

HTMLElement.prototype.addEventListener = function(eventName, handlerFunction, eventOptions) {
    // reportFunction you would have to write yourself
    this._addEventListener(eventName, reportFunction, eventOptions);
    this._addEventListener(eventName, handlerFunction, eventOptions);
    // Store an array of them on the element
    if ('currentListeners' in this === false) {
        this.currentListeners = [
            { eventName, handlerFunction, eventOptions }
        ];
    } else {
        this.currentListeners.push({ eventName, handlerFunction, eventOptions });
    }
}

Granted, I just handed out a loaded foot-gun for anyone who wants one. It's an anti-pattern at best, it doesn't control/track state, emulate user interactions, etc. etc.

I wouldn't recommend this for "regenerating" or rerendering UI as it's gonna be more trouble than it's worth.

If you're trying to use this for debugging, there are a couple of SAAS whose whole business models are based off of this, like HotJar and Sentry.io. I'd recommend checking them out first if you're looking for a solution.

frankie
  • 201
  • 1
  • 6