How to stringify event object?
You won't be able to serialize an event object with JSON.stringify, because an event object contains references to DOM nodes, and the DOM has circular references all over the place (e.g. child/parent relationships). JSON can't handle these by default, so you're a bit out of luck there.
I'd suggest to look at How to serialize DOM node to JSON even if there are circular references? which has a few suggestions on how to serialize a DOM node. Also, the following questions seem to have useful information:
- How to save an object with circular references?
- Stringify (convert to JSON) a JavaScript object with circular reference
JSON libraries able to handle circular references seem to be
- JSON-js (see cycle.js)
- dojox.json.ref
Alternatively, you could delete all references to DOM nodes if you don't need them, and then serialize the object. You shouldn't do this after all. See @PointedEars comment :)
Stringifying event object works, but is practically empty
JSON.stringify
ignores non-enumerable properties, and most of the properties of a MouseEvent
are (apparently) non-enumerable:
document.querySelector('button').addEventListener('click', ev => { let props = ['isTrusted', 'target', 'clientX', 'clientY', 'layerX', 'layerY']; props.forEach(prop => { console.log(prop + '?', ev.propertyIsEnumerable(prop)); });});
<button>Try it!</button>
JSON.stringify losing properties - Logging and saving all javascript events
There could be a couple reasons for this. Most likely is those properties are not enumerable which causes them to not be included in JSON. (Properties are defined as enumerable
via Object.defineProperties.) See:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#Description
I would recommend explicitly declaring which properties you want to POST, since you probably don't need all of them anyway:
axios.post('/api/logger', JSON.stringify(events.map(event=>{
return {
altKey: event.altKey,
bubbles: event.bubbles,
// etc...
}
}));
event listener attached to canvas only receives {isTrusted:true} object in codeSandbox
That sandbox has a lot of code, I'm just going to focus on what you have here...
The mouse event object is complex and most likely JSON.stringify
is taking a shortcut; and correct if you try to output the entire object it will be slow or it could crash like you describe, but there are other properties there, you can see it on the sample below.
var canvas = document.querySelector("canvas")
var ctx = canvas.getContext("2d")
ctx.fillStyle = "red"
for (let i = 10; i < 100; i += 10 )
ctx.rect(i, i, 50, 50);
ctx.stroke();
canvas.onmousedown = function (event) {
console.log(JSON.stringify(event));
console.log(event.x, event.y);
ctx.beginPath()
ctx.arc(event.x, event.y, 5, 0, 8)
ctx.fill();
};
body { margin: 0 }
<canvas id="canvas"></canvas>
How to access js event object in a super type that is called from a subtype?
This
UiResultsItemInfoParser.prototype = new EvntParser();
is an opt-repeated anti-pattern, and the root of your issue. EvntParser
expects an argument and assumes it was given it (this._evntInfo.time = e.timeStamp.toString()
), so it fails when you do the above.
Instead:
UiResultsItemInfoParser.prototype = Object.create(EvntParser.prototype);
That creates an object that has EvntParser.prototype
as its prototype, but without calling EvntParser
. (Then your next line, which is exactly right, fixes constructor
on the resulting object.)
Later, you're doing the right thing by doing EvntParser.call(this, e);
in your subclass constructor. So it's really just the one line.
Since you're using arrow functions, you must be working in an ES2015 environment. That means you can use the new class
syntax, which does all this fiddly hooking things up for you:
class EvntParser {
constructor(e) {
this._evntInfo = {};
this._evntInfo.time = e.timeStamp.toString();
this._evntInfo.type = 'event';
}
set evntInfo(e) {
this._evntInfo.time = e.timeStamp.toString();
this._evntInfo.type = 'event';
}
get evntInfo() {
return JSON.stringify(this._evntInfo);
}
}
class UiResultsItemInfoParser extends EvntParser {
}
Note how you don't even need to define a constructor in UiResultsItemInfoParser
; when you don't, the JavaScript engine defines one for you that calls super
with all the arguments it receives.
Side note: This:
this._evntInfo = {};
this._evntInfo.time = e.timeStamp.toString();
this._evntInfo.type = 'event';
can also be written
this._evntInfo = {
time: e.timeStamp.toString(),
type: 'event'
};
if you like (even before ES2015). Exactly the same object is created.
Related Topics
Conditionalpanel JavaScript Conditions in Shiny: Is There R %In% Operator in JavaScript
R Shiny Build Links Between Tabs
Rails Include JavaScripts Assets Folder Recursively
Js Replace Not Working on String
How to Save a Leaflet Map with Drawn Shapes/Points on It in Shiny
Change Second Select List Based on First Select List Value in Rails
Js.Erb Not Executing JavaScript But Is Processed Rails
Embed a JavaScript Engine in an iOS Application
Twitter Bootstrap Rails Button Dropdown No Responding to Ajax
Programmatically Select Text in a Contenteditable HTML Element
Jquery Scrolltop() Doesn't Seem to Work in Safari or Chrome (Windows)
How to Include Newlines in Labels in D3 Charts
How to Invoke Ruby from Node.Js
How to Update Window.Location.Hash Without Jumping the Document
Template Literal Inside of the Regex
How to Return Multiple Lines Jsx in Another Return Statement in React